构造函数的特征:
构造函数无返回类型,函数名和类名相同能重载
1. 在定义对象时,调用构造函数
class A
{
public:
A(int t=0):m(t)
{
cout << "调用构造函数" << endl;
}
~A()
{
cout<<"调用析构函数!<<endl;
}
private:
int m;
};
int main()
{
A a;
}
在主函数定义了A类型的一个对象A时才调用了构造函数。
2.构造函数为对象开辟空间,并且初始化对象的数据成员。
在上程序中,定义了一个对象A,我们首先调用构造函数为a对象里面的数据成员开辟相应的空间。之后通过按照数据成员在类中的声明顺序给数据成员通过初始化列表进行初始化。
3.一个类中只能有一个缺省构造函数,构造函数可以进行重载。当我们在程序中没有写构造函数时,程序会默认生成一个不带参数的构造函数。
析构函数的特征
析构函数无返回类型,函数名和类名相同,无参。
1.析构函数在对象生存期结束时调用。
2.对于我们动态创建的对象:
A *p=new A;
此时当我们new时,则时创建了一个对象。我们需要delete p,来释放掉对象。释放时会调用析构函数。
3.一个类中只能有一个析构函数。当我们在程序中没有写析构函数时,程序会默认生成一个析构函数。
4.当我们的数据成员为指针时,指针开辟了一段空间,这时假若只简单调用程序自带的析构函数,那么程序只会销毁指针所占的空间,而指针所指向的那段空间不会被释放。所以我们需要写析构函数释放掉指针所指的那段空间。例如:
class A
{
public:
A()
{
int *p = new int[10];//自己写构造函数申请空间,系统不提供
cout << "调用构造函数" << endl;
}
~A()
{
delete p; //需要我们自己写析构函数来释放p所指向的内存空间防止泄露。系统不会提供
p = nullptr;
}
private: int* p;
};
int main()
{
A a;
}
5.析构函数的调用顺序:
例:1.对于局部非静态对象,后定义的对象先调用析构函数。
2.对于局部静态对象和非静态对象,非静态对象先调用析构,局部静态后调用
3.全局对象后定义的对象先调用析构函数,但相比于局部对象全局对象是最后调用析构函数的。
例如下面测试:
class A
{
public:
A(int i = 0) :m_i(i) { cout << "A" << m_i << endl; }
~A() { cout << "~A" << m_i << endl; }
private:
int m_i;
};
A b(20);
static A a(666);
void fn()
{
cout << "fn start" << endl;
static A ss(40);
A tt(50);
cout << "fn end" << endl;
}
void main()
{
cout << "main begin" << endl;
A a(10);
A c(30);
fn();
fn();
cout << "main end" << endl;
}
测试结果如下: