[英]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.