一、构造函数的定义规则
- 构造函数函数名和类名完全相同
- 不能定义构造函数的类型(返回类型),也不能使用void
- 通常情况下构造函数应声明为公有函数,否则它不能像其他成员函数那样被显式地调用
- 构造函数被声明为私有有特殊的用途。
- 构造函数可以有任意类型和任意个数的参数,一个类可以有多个构造函数(重载)
构造函数定义如下:
class Test
{
public:
// 如果类不提供任何一个构造函数,系统将为我们提供一个不带参数的
// 默认的构造函数
Test();
Test(int num);
void Display();
private:
int num_;
};
上例显示声明默认构造函数,并且有一个重载了构造函数。
二、全局对象的构造先于main函数
#include <iostream>
using namespace std;
class Test
{
public:
Test() { cout<<"default construct function"<<endl; }
Test(int num){};
void Display(){};
~Test(){ cout<<"deconstruct funtion"<<endl; }
private:
int num_;
};
Test a;
int main()
{
<span style="white-space:pre"> </span>cout<<"begin"<<endl;
<span style="white-space:pre"> </span>cout<<"end"<<endl;
}
程序运行结果:
default construct function
begin
end
deconstruct funtion
这说明全局对象在进入main函数之前就已经被构造,在退出main函数之后才析构这个全局对象
三、析构函数
- 函数名和类名相似(前面多了一个字符“~”)
- 没有返回类型
- 没有参数
- 析构函数不能被重载
- 如果没有定义析构函数,编译器会自动生成一个默认析构函数,其格式如:类名::~默认析构函数名( ) { }
上面的例子已经有了构造函数的定义,这里不再举例。
四、构造函数和数组、构造函数和new运算符、析构函数和delete运算符、析构函数和数组
对于上面的Test类,我们如何声明一个Test的对象数组呢,如下:
int main()
{
Test t[2] = {10, 20};//调用带一个int参数的构造函数,列表里的值分别作为每个对象构造函数参数
Test* t2 = new Test(2); //声明一个对象指针指向一个Test对象,2作为构造函数参数
delete t2; //new的空间需要手动释放
Test* t3 = new Test[2]; //声明一个对象指针指向一大小为2个Test对象数组(调用的是默认构造函数)
delete[] t3; //释放数组,用delete[]
return 0;
}
代码第4行,new的操作分为两个步骤:
1、分配内存
2、调用构造函数
new的这种用法我们叫做new operator(new 运算符)。
在堆上分配的空间,需要手动delete,在delete时,delete的操作也分为两个步骤
1、调用析构函数
2、释放内存
五、显示调用析构函数
显示调用析构函数如下:
int main()
{
Test t;
t.~Test();
return 0;
}
在这个例子中,析构函数实际上被调用了两次,一次显示调用,一次在对象t出了作用域之后。除非在特殊的场合,一般不推荐这么使用。