组合类构造函数、析构函数、拷贝构造函数的调用顺序
这些天在看C++的过程中一直搞不太懂构造函数和析构函数的调用顺序,特别是析构函数,不带参数不好进行测试,这里把这几天遇到的问题写了个代码跑了一下,和大家分享一下,写的有不对的地方,欢迎大家批评指正。
测试代码
#include<cstdio>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
class Point{
private:
int m_x;
int m_y;
public:
Point(int x, int y) : m_x(x), m_y(y){
cout << "Point的初始化列表构造函数调用" << m_x << " " << m_y << endl;
}
~Point(){
cout << "Point的析构函数调用" << m_x << " " << m_y << endl;
}
Point(Point &P){
m_x = P.m_x; m_y = P.m_y;
cout << "Point的拷贝构造函数调用" << m_x << " " << m_y << endl;
}
int getX(){
return m_x;
}
int getY(){
return m_y;
}
};
class Line{
private:
Point m_s, m_e;
public:
Line(Point s, Point e) : m_s(s), m_e(e){
cout << "Line的初始化列表构造函数调用" << endl;
}
Line(Line &L) : m_s(L.m_s), m_e(L.m_e){
cout << "Line的拷贝构造函数调用" << endl;
}
~Line(){
cout << "Line的析构函数调用" << endl;
}
double getDis(){
double x = double(m_s.getX() - m_e.getX());
double y = double(m_s.getY() - m_e.getY());
return sqrt(x * x - y * y);
}
};
int main(){
Point p1(1, 2), p2(3, 4);
cout << "---------------------" << endl;
Line L1(p1, p2);
cout << "---------------------" << endl;
Line L2(L1);
return 0;
}
运行结果
下面逐一对输出结果进行解释
Point的初始化列表构造函数调用1 2
Point的初始化列表构造函数调用3 4
上面两句的输出很好理解,对应的是源码的第52行,即创建Point类的对象p1、p2时,调用了Point类的初始化列表构造函数,于是输出了上述结果。
---------------------
Point的拷贝构造函数调用3 4
Point的拷贝构造函数调用1 2
上面的这两句是创建组合类Line的对象L1的时候,首先需要形参传递给实参,这个过程会调用Point类的拷贝构造函数【当对象作为函数参数或者返回值的时候会调用拷贝构造函数】,注意此时参数的传递顺序是从右到左,所以这里会调用Point的拷贝构造函数两次,又因为从右到左,所以先拷贝e,后拷贝s。
Point的拷贝构造函数调用1 2
Point的拷贝构造函数调用3 4
这里的两句是调用Point的拷贝构造函数,分别完成内嵌对象m_s、m_e的初始化,即执行的是Line构造函数中的这个部分[m_s(s), m_e(e)]。
Line的初始化列表构造函数调用
上面的这句就是执行Line构造函数的函数体输出的结果。
Point的析构函数调用1 2
Point的析构函数调用3 4
这里是对形参的析构,上面说到了先拷贝的e,后拷贝的s,所以释放的时候,先释放s所占内存,后释放e所占内存。【系统在栈中为对象分配内存空间,而栈是采用后进先出的工作方式】
---------------------
Point的拷贝构造函数调用1 2
Point的拷贝构造函数调用3 4
这上面的两句执行的是Line的拷贝构造函数,具体对应的是Line拷贝构造函数中的这个部分[ m_s(L.m_s), m_e(L.m_e) ]。
Line的拷贝构造函数调用
执行Line拷贝构造函数的函数体时输出的结果
Line的析构函数调用
Point的析构函数调用3 4
Point的析构函数调用1 2
以上的三句需要一起解释,在对Line的拷贝构造函数之中,我们使用的是L1来实例化L2,这个过程中需要注意,三个对象的定义顺序为L2.m_s、L2.m_e、L2,所以对应的析构顺序为L2、L2.m_e、L2.m_s。
Line的析构函数调用
Point的析构函数调用3 4
Point的析构函数调用1 2
同理。这里的三句输出和上面的一样,三个对象的定义顺序为m_s、m_y、L1,所以对应的析构顺序为L1、m_y、m_x。
Point的析构函数调用3 4
Point的析构函数调用1 2
上面两句是对p1、p2的析构,与定义它们的顺序相反。