构造和析构函数是类的基础
- 类中有构造函数、拷贝构造函数和赋值构造函数
- 析构函数只有一个
- 若没有定义这些函数,编译器会合成默认构造函数
- 有些情况下会自动调用构造函数和析构函数,导致学习者忽视其调用过程。当涉及到继承和派生时,整个过程就更复杂
- 这里自己定义了一些类型的构造函数,以观察构造和析构的过程
代码如下
#include <iostream>
using namespace std;
class A
{
public:
A()
{
cout<<"A construct\n";
}
~A()
{
cout<<"A destruct\n";
}
A(const A &)
{
cout<<"A copy construct\n";
}
A & operator=(const A &)
{
cout<<"A copy assignment\n";
}
virtual void foo()
{
cout<<"A foo\n";
}
};
class B: public A
{
public:
B()
{
cout<<"B construct\n";
}
~B()
{
cout<<"B destruct\n";
}
void foo()
{
cout<<"B foo\n";
}
};
B gb;
int main()
{
A la = gb;
cout<<"haha0\n";
A * p = &gb;
cout<<"haha1\n";
la.foo();
cout<<"haha2\n";
(&gb)->foo();
cout<<"haha3\n";
p -> foo();
cout<<"haha4\n";
la = gb;
cout<<"haha5\n";
la.foo();
cout<<"haha6\n";
gb.foo();
cout<<"haha7\n";
return 0;
}
运行结果:
A construct
B construct
A copy construct
haha0
haha1
A foo
haha2
B foo
haha3
B foo
haha4
A copy assignment
haha5
A foo
haha6
B foo
haha7
A destruct
B destruct
A destruct
需要注意的几个问题
- 全局对象的构造函数
全局对象gb出现在main()函数之前,但是第一次使用的时候才对其进行构造,之后再用到gb时不需再次调用构造函数
注意main()的第一句,定义类A的一个对象,并用类B的gb初始化时:先调用gb的构造函数创建并初始化gb,因为gb为派生类B的对象,会先调用基类构造函数(第一行输出),然后调用自身的构造函数(第二行);最后调用la的拷贝构造函数创建并初始化la(第三行) - 指针对象的构造函数
创建类A的指针时,不管用是谁初始化,该过程没有创建新的对象,不涉及到调用构造函数
但是类A的指针指向了派生类B的对象,指针装载的是gb对象的首地址,因此在调用虚函数foo()时候,执行的是类B的foo()函数 - 拷贝构造函数和赋值构造函数的区别
对已经定义的对象使用”=”操作符时,才调用赋值构造函数 - 注意析构顺序,与创建顺序相反