以線段(Line)類爲例子,梳理C++組合類中構造函數的調用順序。ios
//Line類計算線段長度
#include<iostream>
#include<cmath>
using namespace std;
class Point { //Point類定義
public:
Point(int xx = 0, int yy = 0) { //Point類構造函數
x = xx;
y = yy;
cout << "Calling constructor of Point" << endl;
}
Point(Point& p); //Point類複製構造函數
int getX() { return x; }
int getY() { return y; }
private:
int x, y;
};
Point::Point(Point& p) { //Point類複製構造函數的實現
x = p.x;
y = p.y;
cout << "Calling the copy constructor of Point" << endl;
}
//類的組合
class Line { //Line類定義
public: //外部接口
Line(Point xp1, Point xp2); //Line類構造函數
Line(Line& l); //Line類複製構造函數
double getLen() { return len; }
private: //私有數據成員
Point p1, p2; //Point類的對象p1,p2
double len;
};
//組合類的構造函數
Line::Line(Point xp1, Point xp2) :p1(xp1), p2(xp2) {
cout << "Calling constructor of Line" << endl;
double x = static_cast<double>(p1.getX() - p2.getX());
double y = static_cast<double>(p1.getY() - p2.getY());
len = sqrt(x * x + y * y);
}
//組合類的複製構造函數
Line::Line(Line& l) :p1(l.p1), p2(l.p2) {
cout << "Calling the copy constructor of Line" << endl;
len = l.len;
}
//主函數
int main() {
Point myp1(1, 1), myp2(4, 5); //創建Point類的對象
Line line(myp1, myp2); //創建Line類的對象
Line line2(line); //利用複製構造函數創建一個新對象
cout << "The length of the line is:";
cout << line.getLen() << endl;
cout << "The length of the line2 is:";
cout << line2.getLen() << endl;
return 0;
}
複製代碼
程序從main函數開始執行,當執行至Point myp1(1, 1), myp2(4, 5);
時,因爲生成了兩個Point類的對象myp1
、myp2
,調用Point類構造函數兩次,對應程序運行結果中前兩行Calling constructor of Point
(由藍色一、2標出)。c++
構造函數調用條件:在對象被建立時自動調用函數
main函數繼續執行,至Line line(myp1, myp2);
,這裏比較複雜,其結果對應程序運行結果中用紅色標出的1~4以及綠色的1,即執行Point類複製構造函數四次,執行Line類構造函數一次。下面來逐一分析爲何。spa
首先明確複製構造函數的三個調用條件。code
複製構造函數調用條件:cdn
(1)當用類的一個對象去初始化該類的另外一個對象時對象
(2)若是函數的形參是類的對象,調用函數時,進行實參和形參結合時blog
(3)若是函數的返回值是類的對象,函數執行完成返回調用者時接口
如今,回過頭看這行代碼Line line(myp1, myp2);
get
1.因爲在建立一個Line類的對象line,符合構造函數調用條件,因此會調用Line類的構造函數,又因爲Line類的構造函數的形參是Point類的對象xp一、xp2,故知足複製構造函數調用條件中的(2),因此調用Line類的構造函數進行形參實參結合時,會調用Point類的複製構造函數兩次(對應紅色一、2)。
2.Line類構造函數的初始化列表爲p1(xp1), p2(xp2)
,是在用Point類的一個對象xp1(xp2)去初始化Point類的另外一個對象p1(p2),符合複製構造函數調用條件中的(1),故會調用Point類的複製構造函數兩次(對應紅色的三、4)。
3.Line類構造函數繼續執行,控制檯打印出Calling constructor of Line
,表示調用了一次Line類的複製構造函數(對應綠色的1)。
main函數繼續執行,至Line line2(line);
,這是在用Line類的一個對象line去初始化Line類的另外一個對象line2,符合複製構造函數調用條件中的(1),故這裏會調用一次Line類的複製構造函數,又因爲Line類的複製構造函數的初始化列表爲p1(l.p1), p2(l.p2)
,是在用Point類的一個對象l.p1(l.p2)去初始化Point類的另外一個對象p1(p2),符合複製構造函數調用條件中的(1),因此這裏會調用Point類的複製構造函數兩次(對應紅色的五、6)。
Line類的複製構造函數繼續執行,控制檯打印出Calling the copy constructor of Line
,表示調用了一次Line類的複製構造函數(對應橙色的1)。
而後main函數繼續執行,後邊沒有調用構造函數及複製構造函數的地方了,不在講解。
對於組合類中構造函數及複製構造函數的調用,主要是要牢記而且充分理解。
在建立一個組合類的對象時,不只它自身的構造函數的函數體將被執行,並且還將調用其內嵌對象的構造函數。這時構造函數調用順序以下:
(1)調用內嵌對象的構造函數,調用順序按照內嵌對象在組合類的定義中出現的次序。注意,內嵌對象在構造函數的初始化列表中出現的順序與內嵌對象構造函數的調用順序無關。
(2)執行本類的構造函數函數體。
注:析構函數的調用執行順序與構造函數恰好相反。