今天我们了解一下类的构造函数、析构函数。其中构造函数会提到默认构造函数、重载构造函数和复制构造函数。好了,现在开始我们的旅程吧。
首先温习一下C和C++中分配内存的方法。我们知道,C中的malloc/free和C++中的new/delete是用来分配内存和释放内存的,这里的内存是前面博文提到的“堆”。(如果不了解什么是堆,请参考文章《C\C++的内存存储》 )他们的区别如下:
new=malloc+构造函数;//分配内存和调用构造函数,这是new的主要作用
delete=析构函数+free;//调用析构函数,释放内存,这是delete的主要作用
好了,现在进入正题。提到构造函数和析构函数,我们的了解一下他们的概念。构造函数是在创建类对象的时候使用给定的值来将对象初始化;析构函数的功能是释放一个对象,在对象被删除之前做一些对象清理工作。需要说明的是,构造函数和析构函数都没有返回值。构造函数可以带参数,可以重载;析构函数没有参数,不能重载。表1是构造函数与析构函数特点的对比。
表1 构造函数与析构函数特点的对比
构造函数 | 析构函数 |
名字与类名相同 | 名字与类名相同,并在前面加一个~字符 |
可以重载,一个类中可以有多个构造函数 | 一个类中只能有一个析构函数 |
程序中不能直接调用构造函数 | 析构函数可以直接在程序中被调用 |
实例化对象时最先被调用的函数 | 类对象在析构时最后一个被调用的函数 |
了解了构造函数和析构函数的基本特点后,我们先着重学习构造函数的相关知识。
1 默认构造函数
默认构造函数是指不需要指定实参就能被调用的构造函数。需要注意的问题有一下几点:
1)一个类中不能有多个默认构造函数,这会导致在使用这个类去实例化类对象的时候编译出错,因为编译器不知道要调用哪一个默认构造函数去实例化类对象。
2)一个类中可以没有默认构造函数的定义。因为编译的时候,编译器会自动产生一个默认构造函数,以便这个类在变异阶段能通过编译。但是,最好不要使用编译器提供的默认构造函数,因为你永远不知道编译器提供的默认构造函数会做些什么,这可能导致不可预知的问题,所以还是自己定义默认构造函数吧,哪怕是一个空的默认构造函数。
2 重载构造函数
带参数的构造函数也就是构造函数的重载。通过形参列表初始化类中的数据成员。需要强调的是,如果重载了构造函数,那么必须自定义默认构造函数,否则编译器会提示错误:
IntelliSense: no default constructor exists for class "XXX"
可以有多个重载构造函数,但是这些函数的形参列表必须不同,以达到编译时编译器能够识别被调用的是哪个构造函数。
3 复制构造函数
复制构造函数的功能是用一个已知对象来初始化另一个同类的对象。复制构造函数其实也是类的构造函数,只不过被调用的时候,会自动将一个已知对象的数据成员的值拷贝给另一个同类对象。复制构造函数的特点如下:
-
复制构造函数名称与类名相同;
-
复制构造函数必须有且只有一个参数,是该类对象的引用;
-
每个类必须有一个复制构造函数。如果定义类的时候自己没有写,编译器编译时会自动生成一个复制构造函数;
-
复制构造函数格式:<类名>::<类名>(const<类名>&<引用名>)
-
下面给一个简单的类定义。
1: #include <iostream>2: using namespace std;3:4: class Test
5: {6: public:
7: Test(){a=0;cout<<"This is a default constructor. The value="<<a<<endl;}
8: Test(int valuea):a(valuea){cout<<"This is a override constructor. The value="<<a<<endl;}9: ~Test(){cout<<"This is a destructor. The value="<<a<<endl;}
10: Test(Test const& test){a=test.a;cout<<"This is a copy constructor. The value="<<a<<endl;}11: private:
12: int a;
13: };14:15: int main()
16: {17: Test t1;18: Test t2(12);19: Test t3(t2);20: return 0;
21: }22:23:
现在我们尝试把Test(int valuea)注释掉,看看会有什么结果。不出意外,得到的答案是
这就是我在前面提到需要注意的问题:如果重载了构造函数,那么必须自定义默认构造函数。
好了,本文先写到这,在下一篇博文中我们会谈到什么情况下必须构造自己的复制构造函数。如有问题,欢迎指正。
感谢:《C++编程关键路径——程序员求职指南》