对象构造:默认参数与委托
object construction : default parameter vs delegation
考虑以下代码,我试图在其中引入默认构造函数以及 class A
的参数化构造函数。这种方式是在最近的c++改进中引入的。
class A {
private:
unsigned int count;
public:
A(int new_c) : count(new_c) {}
A() : A(10) {}
};
与在参数化构造函数上设置默认参数并完全忽略默认构造函数的旧方法相比。
class A {
private:
unsigned int count;
public:
A(int new_c = 5) : count(new_c) {}
};
除了遵循现代惯例之外,使用第一种方法比使用第二种方法有什么优势吗?
功能上没有区别。要知道甚至还有另一个选项可用于非静态成员初始化(C++11 起):
class A {
private:
unsigned int count = 10;
public:
A() = default;
A(int new_c) : count(new_c) {}
};
在较大的情况下,优势将更加明显 class 其中可以有一些构造函数。以新的方式,您将能够编写一个构造函数,然后将其设置为其他构造函数。这不太容易出错。
class A {
private:
unsigned int count;
int other;
float otherfloat;
public:
A( unsigned int count, int other, float otherfloat ) : count( count), other( other ), otherfloat( otherfloat ) {}
A(int new_c) : A(new_c, 0, 0.0 ) {}
A() : A(10) {}
};
在你的例子中没有优势(在这样的例子中我什至会选择第二个选项更清楚)
在默认值不够时添加委派构造函数以简化工作。
例如
struct Point3d
{
Point3d(int x, int y, int z);
Point3d(Point2d p) : Point3d(p.x, p.y, 0) {}
}
虽然在技术上没有区别,但创建转发构造函数背后的想法是不同的。
想象以下 class:
class sample {
complexType member;
bool createdWithInt;
public:
sample() : member(5), createdWithInt(false) {
/* code ... */
}
sample(int param) : sample() {
createdWithInt = true;
/* other code */
}
};
所以这个class很难用默认参数实现:
它的行为不依赖于参数的值,而是依赖于存在。
人们可能会尝试使用辅助函数 void creator()
来实现它,该函数在不带参数的情况下从构造函数执行 code ...
位。然而,这将意味着复制初始化列表(或者如果从 creator()
内初始化则放弃 RAII 原则)。
注意:createdWithInt
可以从初始化列表中初始化,如果添加了另一个构造函数,则需要一个布尔值,并且两个当前构造函数都转发给那个。为了示例,已将其省略。
考虑以下代码,我试图在其中引入默认构造函数以及 class A
的参数化构造函数。这种方式是在最近的c++改进中引入的。
class A {
private:
unsigned int count;
public:
A(int new_c) : count(new_c) {}
A() : A(10) {}
};
与在参数化构造函数上设置默认参数并完全忽略默认构造函数的旧方法相比。
class A {
private:
unsigned int count;
public:
A(int new_c = 5) : count(new_c) {}
};
除了遵循现代惯例之外,使用第一种方法比使用第二种方法有什么优势吗?
功能上没有区别。要知道甚至还有另一个选项可用于非静态成员初始化(C++11 起):
class A {
private:
unsigned int count = 10;
public:
A() = default;
A(int new_c) : count(new_c) {}
};
在较大的情况下,优势将更加明显 class 其中可以有一些构造函数。以新的方式,您将能够编写一个构造函数,然后将其设置为其他构造函数。这不太容易出错。
class A {
private:
unsigned int count;
int other;
float otherfloat;
public:
A( unsigned int count, int other, float otherfloat ) : count( count), other( other ), otherfloat( otherfloat ) {}
A(int new_c) : A(new_c, 0, 0.0 ) {}
A() : A(10) {}
};
在你的例子中没有优势(在这样的例子中我什至会选择第二个选项更清楚)
在默认值不够时添加委派构造函数以简化工作。
例如
struct Point3d
{
Point3d(int x, int y, int z);
Point3d(Point2d p) : Point3d(p.x, p.y, 0) {}
}
虽然在技术上没有区别,但创建转发构造函数背后的想法是不同的。 想象以下 class:
class sample {
complexType member;
bool createdWithInt;
public:
sample() : member(5), createdWithInt(false) {
/* code ... */
}
sample(int param) : sample() {
createdWithInt = true;
/* other code */
}
};
所以这个class很难用默认参数实现: 它的行为不依赖于参数的值,而是依赖于存在。
人们可能会尝试使用辅助函数 void creator()
来实现它,该函数在不带参数的情况下从构造函数执行 code ...
位。然而,这将意味着复制初始化列表(或者如果从 creator()
内初始化则放弃 RAII 原则)。
注意:createdWithInt
可以从初始化列表中初始化,如果添加了另一个构造函数,则需要一个布尔值,并且两个当前构造函数都转发给那个。为了示例,已将其省略。