简体   繁体   English

在构造函数体内调用成员对象的构造函数?

[英]Calling a constructor of a member object within the body of the constructor?

Why am I not allowed to use the following syntax to call a constructor of a member object/different class in the body of the constructor of a class? 为什么我不允许使用以下语法在类的构造函数体中调用成员对象/不同类的构造函数?

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;}
};

By the way I know I can call Circle::Circle(double) via Cylinder(double,double) using member initialization list like Cylinder(double r,double h) : base(r), height(r) {} but still what's wrong with the former method that the compiler is generating this error? 顺便说一下,我知道我可以使用Cylinder(double r,double h) : base(r), height(r) {}类的成员初始化列表通过Cylinder(double,double)调用Circle::Circle(double) Cylinder(double r,double h) : base(r), height(r) {}但仍然是什么编译器生成此错误的前一种方法有错吗?

错误信息

The correct way to handle this is an initializer list. 处理此问题的正确方法是初始化列表。 Write the constructor of Cylinder like this: 像这样编写Cylinder的构造函数:

Cylinder(double r, double h) : base(r), height(h) {}

The part between the : and the opening brace is the initializer list that constructs all the data members of the class before the body of the constructor code is run . :和左大括号之间的部分是初始化列表,它在构造函数体的主体运行之前构造类的所有数据成员。 That way, C++ ensures that your object is fully constructed even within the body of the constructor. 这样,C ++确保您的对象即使在构造函数的主体内也是完全构造的。

Since C++ ensures that all members are fully constructed before the body of the constructor is run, any attempt to call a constructor from the body of a constructor would reinitialize the object. 由于C ++确保在构造函数体之前完全构造所有成员,因此从构造函数体调用构造函数的任何尝试都会重新初始化该对象。 While technically possible using placement-new, this is almost certainly not what you want to do. 虽然技术上可以使用placement-new,但这几乎肯定不是你想要做的。

The syntax base(r); 语法base(r); within the body of the constructor tries to call the operator()(double) on the already fully constructed member. 在构造函数体内尝试在已经完全构造的成员上调用operator()(double) Since you didn't provide such an operator, your compiler complains. 由于您没有提供这样的运算符,您的编译器会抱怨。

The problem is that when C++ begins the execution of the constructor code all the member variables must have been already constructed (what if you for example call a method of Circle before constructing it?). 问题是,当C ++开始执行构造函数代码时,必须已经构造了所有成员变量(如果你在构造之前调用Circle的方法怎么办?)。

If immediate construction is a problem then a possible solution is to add to your member a default constructor and the using assignment in the body of the constructor of the containing class. 如果立即构造是一个问题,那么可能的解决方案是向您的成员添加默认构造函数和包含类的构造函数体中的using 赋值

You can imagine that native types like int or double do have a default constructor, that's why you can initialize them later (note however that for one of the many ugly quirks of the language the default constructor for an int or a double doesn't actually do anything in this case and you're not allowed to do anything with such a member except assigning it a value - for example reading it is not allowed). 你可以想象像intdouble这样的本地类型确实有一个默认的构造函数,这就是你以后可以初始化它们的原因(但是请注意,对于该语言的许多丑陋的怪癖之一, intdouble的默认构造函数实际上并不是这样的在这种情况下做任何事情并且你不允许对这样的成员做任何事情,除非给它赋值 - 例如,不允许读取它。

You cannot use base(r) in the body because that's not a valid statement... following a name with an opening parenthesis is only used for function call, for initialization in a declaration or for member initialization in the constructor member initialization list. 您不能在正文中使用base(r) ,因为它不是有效的语句...在带有左括号的名称之后仅用于函数调用,声明中的初始化或构造函数成员初始化列表中的成员初始化。

If you provide Circle with a default constructor then you can do 如果您为Circle提供默认构造函数,那么您可以这样做

Cylinder(double r, double h) {
    base = Circle(r);
    height = h;
}

Note however that the approach of constructing non-working objects to fix them later is not the best approach for C++. 但请注意,构建非工作对象以便以后修复它们的方法并不是C ++的最佳方法。 The language likes the idea that if an object is constructed then it's usable and deviations from this are considered only when necessary (C++11 drifted away a bit from this original path with move constructor... but that's another story). 该语言喜欢这样的想法:如果一个对象被构造,那么它是可用的,只有在必要时才会考虑与它的偏差(C ++ 11从移动构造函数的原始路径中稍微偏离......但这是另一个故事)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM