探秘对象构造和析构(一)
首先我们先看我们的类代码:
class Test
{
public:
//带一个整型参数的构造函数
Test(int a = 10) :ma(a)
{ cout << "Test(int)" << endl; }
//析构函数
~Test()
{ cout << "~Test()" << endl; }
//拷贝构造函数
Test(const Test &t) :ma(t.ma)
{ cout << "Test(const Test&)" << endl; }
//赋值函数
Test& operator=(const Test &t)
{
cout << "operator=" << endl;
ma = t.ma;
return *this;
}
private:
int ma;
};
再来看我们的main函数:
int main()
{
//调用test(int)构造
Test t1;
//调用拷贝构造
Test t2(t1);
//调用拷贝构造
Test t3 = t1;
/* 这里Test(20)是显式生成临时对象 但是C++编译器在生成新对象的时候会对临时对象进行优化,减少开销 这里其实就t4(20); */
Test t4 = Test(20);
cout << "--------------" << endl;
//相当于调用了t4的operator =函数,其中t2是参数
t4 = t2;
/* 1.这里先显式的调用构造函数,Test(int),30是参数 2.然后调用operator=,临时对象是参数 3.临时对象析构 */
t4 = Test(30);
// 这是隐式生成临时对象,相当于int -> Test(int),其他步骤和显式一样的
t4 = (Test)30;
//这个也是隐式生成,相当于int -> Test(int),其他步骤和显式一样的
t4 = 30;
cout << "--------------" << endl;
//先构造一个临时对象,然后析构,p此时是失效指针
Test *p = &Test(40);
//这里,临时对象和引用结合,相当于临时对象有了别名(ref),生存期被延长了
const Test &ref = Test(50);
cout << "--------------" << endl;
return 0;
}
运行结果:
Test(int)
Test(const Test&)
Test(const Test&)
Test(int)
--------------
operator=
Test(int)
operator=
~Test()
Test(int)
operator=
~Test()
Test(int)
operator=
~Test()
--------------
Test(int)
~Test()
Test(int)
--------------
~Test()
~Test()
~Test()
~Test()
~Test()
构造顺序
先看类代码:
class Test
{
public:
// Test() Test(10) Test(10, 10)
Test(int a = 5, int b = 5)
:ma(a), mb(b)
{
cout << "Test(int, int)" << endl;
}
~Test()
{
cout << "~Test()" << endl;
}
Test(const Test &src)
:ma(src.ma), mb(src.mb)
{
cout << "Test(const Test&)" << endl;
}
void operator=(const Test &src)
{
ma = src.ma;
mb = src.mb;
cout << "operator=" << endl;
}
private:
int ma;
int mb;
};
再看main函数代码:
Test t1(10, 10); // 第一个构造,调用Test(int, int)
int main()
{
Test t2(20, 20); // 第三个构造,调用Test(int, int)
Test t3 = t2; // 第四个构造,调用Test(const Test&)
// 静态关键字只有被用到才会构造,相当于static Test t4(30, 30);
static Test t4 = Test(30, 30); // 第五个构造,调用Test(int, int),临时对象被优化了
t2 = Test(40, 40); // 第六个,Test(int, int) operator= ~Test()
// 这个看第二个参数,也就是第二个50,相当于(50, 50) = (Test)50; Test(int)
t2 = (Test)(50, 50); // 第七个,Test(int,int) operator= ~Test()
t2 = 60; //Test(int) 第八个,Test(int,int) operator= ~Test()
Test *p1 = new Test(70, 70); // 第九个, Test(int,int)
Test *p2 = new Test[2]; // 第十个,相当于两次 Test(int,int) Test(int,int)
Test *p3 = &Test(80, 80); // 第十一个 Test(int,int) ~Test()
const Test &p4 = Test(90, 90); // 第十二个 Test(int,int)
delete p1; // 析构~Test()
delete[]p2; // 析构两次~Test() ~Test()
}
Test t5(100, 100); // 第二个调用,调用Test(int, int)
构造顺序和析构顺序相反。
全局变量永远都比main函数先行构造,想知道原因可以去看我的程序员的自我修养博客专栏,C++相关问题。
运行结果:
Test(int, int)
Test(int, int)
Test(int, int)
Test(const Test&)
Test(int, int)
Test(int, int)
operator=
~Test()
Test(int, int)
operator=
~Test()
Test(int, int)
operator=
~Test()
Test(int, int)
Test(int, int)
Test(int, int)
Test(int, int)
~Test()
Test(int, int)
~Test()
~Test()
~Test()
~Test()
~Test()
~Test()
~Test()
~Test()
~Test()
参考文献
[1] 施磊.腾讯课堂——C++高级.图论科技,2020.7.