构造函数:数据成员初始化(可带参数,无返回类型)
析构函数:对象删除前执行一些清理善后和数据保存工作。(无参数和返回类型)
均为自动调用。如果不提供两者定义时,编译器默认添加默认的构造函数和析构函数,执行空操作。注意如果你定义了构造或者析构函数,那就调用你自定义的,系统不会再添加默认构造或者析构函数。注意语法,否则容易出错。比如自定义的析构函数和不带参数的构造函数都必须有定义,不能只声明不实现。
当创建一个对象时(包括声明一个对象和利用new动态创建对象),系统先根据类定义的数据成员为对象分配内存空间,然后自动调用对象的构造函数对分配的内存空间进行初始化处理,从而完成对象的初始化。
当删除一个对象时(包括生存期结束和利用delete回收内存空间),系统先调用对象的析构函数,进行善后工作,然后释放对象所占内存。
来个类的定义:
class Time{
private:
int hour;
int minute;
int second;
public:
Time(int, int, int){...}
~Time(){...}
};
声明多个对象,调用析构函数的顺序和调用构造函数的顺序相反:
进入main函数
Time t1(11,45,0); // 声明对象1,调用构造函数
Time t2(12,30,0); // 声明对象2,调用构造函数
...
调用对象2析构函数,释放对象2所占内存
调用对象1析构函数,释放对象1所占内存
退出main函数
原因:在栈为对象分配内存空间,采用“后进先出”。
注意,本例中自定义的构造函数只有一个,且带参数,所以创建Time类对象时必须带参数,否则报错。
初始化数据成员:构造函数内、初始化列表
Time::Time(int h, int m, int s) : hour(h), minute(m), second(s) { }
构造函数放在类体内定义,自动成为内联函数。在外部,加inline成为内联函数。
拷贝构造函数:把一个已有的对象的数据成员赋值给正在创建的新对象。只有一个参数:本类的对象引用。
Time(Time &t)
{
hour = t.hour;
minute = t.minute;
second = t.second;
}
拷贝构造使用:
1. 创建新对象时,使用已有的对象进行初始化
2. 对象作为函数的参数或函数的返回值
int main()
{
Time t1(11,45,0);
Time t2(t1);
return 0;
}
构造函数和拷贝构造函数分别调用一次,析构函数调用两次。声明对象t1:自动调用构造函数;声明t2:自动调用拷贝构造函数
事实上,如果类没有定义拷贝构造函数,编译系统也会自动为类添加一个默认的拷贝构造函数。功能是:利用作为初始值对象的每个数据成员的值,去初始化新创建的对象的数据成员。和本例的其实一样。
但要强调的是,默认的拷贝构造函数采用浅拷贝工作方式,即只进行二进制内存空间上的数据简单复制,不为数据成员分配内存空间。
浅拷贝只能完成基本数据类型的拷贝,若本类中含有指针类型的数据成员(需要为数据成员动态分配内存空间),浅拷贝就有潜在危险。因为有可能使两个对象的指针都指向同一片内存区域。解决办法:采用深拷贝,在拷贝构造函数中为数据成员动态分配内存空间。
深拷贝与浅拷贝概念参考:http://www.cnblogs.com/Phoenix-Rock/archive/2006/11/07/ShallowCopy_DeepCopy.html