[英]Calling a constructor of a member object within the body of the constructor?
为什么我不允许使用以下语法在类的构造函数体中调用成员对象/不同类的构造函数?
class Circle {
double radius;
public:
Circle(double r) : radius(r) { }
double area() {return radius*radius*3.14159265;}
};
class Cylinder {
Circle base;
double height;
public:
Cylinder(double r, double h) {
base(r);
height = h;
}
double volume() {return base.area() * height;}
};
顺便说一下,我知道我可以使用Cylinder(double r,double h) : base(r), height(r) {}
类的成员初始化列表通过Cylinder(double,double)
调用Circle::Circle(double)
Cylinder(double r,double h) : base(r), height(r) {}
但仍然是什么编译器生成此错误的前一种方法有错吗?
处理此问题的正确方法是初始化列表。 像这样编写Cylinder
的构造函数:
Cylinder(double r, double h) : base(r), height(h) {}
:
和左大括号之间的部分是初始化列表,它在构造函数体的主体运行之前构造类的所有数据成员。 这样,C ++确保您的对象即使在构造函数的主体内也是完全构造的。
由于C ++确保在构造函数体之前完全构造所有成员,因此从构造函数体调用构造函数的任何尝试都会重新初始化该对象。 虽然技术上可以使用placement-new,但这几乎肯定不是你想要做的。
语法base(r);
在构造函数体内尝试在已经完全构造的成员上调用operator()(double)
。 由于您没有提供这样的运算符,您的编译器会抱怨。
问题是,当C ++开始执行构造函数代码时,必须已经构造了所有成员变量(如果你在构造之前调用Circle
的方法怎么办?)。
如果立即构造是一个问题,那么可能的解决方案是向您的成员添加默认构造函数和包含类的构造函数体中的using 赋值 。
你可以想象像int
或double
这样的本地类型确实有一个默认的构造函数,这就是你以后可以初始化它们的原因(但是请注意,对于该语言的许多丑陋的怪癖之一, int
或double
的默认构造函数实际上并不是这样的在这种情况下做任何事情并且你不允许对这样的成员做任何事情,除非给它赋值 - 例如,不允许读取它。
您不能在正文中使用base(r)
,因为它不是有效的语句...在带有左括号的名称之后仅用于函数调用,声明中的初始化或构造函数成员初始化列表中的成员初始化。
如果您为Circle
提供默认构造函数,那么您可以这样做
Cylinder(double r, double h) {
base = Circle(r);
height = h;
}
但请注意,构建非工作对象以便以后修复它们的方法并不是C ++的最佳方法。 该语言喜欢这样的想法:如果一个对象被构造,那么它是可用的,只有在必要时才会考虑与它的偏差(C ++ 11从移动构造函数的原始路径中稍微偏离......但这是另一个故事)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.