C++构造函数与析构函数
1.构造函数——初始化成员的函数
A.构造函数的形式
- 构造函数没有返回值(连void都没有)
- 构造函数与类名同名
- 构造函数可以重载
-
C++中,构造函数不能相互调用来构造同一个函数
class A{ private: int a; public: A(int a = 0); }; A::A(int a){ this->a = a; }
B.构造函数的调用——创建对象(分配空间),然后调用构造
a.初始化时调用
//隐式调用
class_name obj; //隐式调用无参构造函数
class_name obj(参数列表); //隐式调用有参构造
注意,隐式调用无参构造,对象名后没有括号,如果有 calss_name obj();这样就变成了一个函数声明
//显式调用
class_name obj = class_name();
class_name obj = class_name(参数列表);
初始化时显式调用分两种情况(与编译器有关):
第一种,与隐式调用一样。
第二种:生成一个临时变量,然后将临时变量的值赋给声明的对象
/*我使用的时VS2017*/
class A {
private:
int a;
public:
A(int a = 0);
void show() const;
};
A::A(int a) {
this->a = a;
cout << this << "调用构造" << endl;
}
void A::show() const {
cout << "a = " << a << endl;
}
int main() {
A obj = A(1);
obj.show();
return 0;
}
输出:
00AFFED8调用构造
a = 1
可见,这样的环境下初始化显式调用与隐式调用没有区别
C++11,可以使用{}初始化
class_name obj{参数列表};
上述初始化有一个条件,参数列表必须与一个构造函数对应
b.改变一个对象的值
调用构造,生成一个临时变量,然后将临时变量的值赋给声明的对象
obj = class_name(); //调用无参构造,改变obj的值
这里与初始化时不同,这里一定会生成临时变量调用构造
int main() {
A obj; //第一次调用构造
obj.show();
obj = A(3); //第二次调用构造,生成临时变量
obj.show();
return 0;
}
输出:
00EFFEB4调用构造
a = 0
00EFFDE8调用构造
a = 3
c.注意,C++构造函数无法相互调用(与JAVA的区别)
除了初始化的时候情况不确定,其他情况下c++调用构造时,都会产生临时对象
class A {
private:
int a;
public:
A(int a);
A();
};
A::A(int a) {
this->a = a;
cout << this << "调用有参构造" << endl;
}
A::A(){
outFile << this << "调用无参构造" << endl;
A(0);
}
上述代码的目的,就是想要在无参构造时,默认的调用有参构造进行初始化,然而,事与愿违
输出:
00D7FBA4调用无参构造
00D7F9F8调用有参构造
可见,两次调用构造的对象不一样,说明不是初始化一个对象,C++可以用默认参数解决这个问题
C.创建对象,调用系统默认生成复制构造函数构造函数的情况
复制构造函数 classname(classname &object);
在初始化时,直接进行赋值 classname obj = anotherobj;这里实际这样调用classname(anotherobj)
对象初始化时,直接将一个已有对象的值赋给它,将会调用系统生成的复制构造函数
A obj1;
A obj2 = obj1;
输出:
00CFFC0C调用无参构造
2.构造函数的调用——对象空间释放(定位new分配的空间除外),就要调用
A.析构函数形式
- 没有返回值
- 没有形参
- 不可重载
- 函数名——~class_name()
B.析构函数的调用——空间释放时系统自动调用
只要是对象空间(我们声明的、系统临时的),一旦释放,就要调用析构
例子: A::A(int a) { this->a = a; cout << this << "调用构造" << endl; }
A::~A() {
cout << this << "调用析构" << endl;
}
我我进行如下调用: int main(){
A obj(3);
obj = A(3);
return 0;
}
输出:
0035FDE4调用构造 //obj调用构造
0035FD18调用构造 //临时变量调用构造
0035FD18调用析构 //临时变量空间释放
0035FDE4调用析构 //main()执行完毕,obj释放
C.注意:
临时变量包括了函数的返回值,也被存储在一个临时的变量,这个临时变量释放时,也会调用析构函数,我的另一篇博客会说到
D.通过定位new分配的对象,要在buffer释放前显式调用析构
int main(){
char *buffer = new char[BUF];//创建一个用于定位new的区域
A *pa = new(buffer)A(); //使用定位new
... //一些操作
pa->~A(); //下一步要释放定位new使用的buffer区域
//如果这里不显式调用,则不会调用析构
delete[] buffer;
return 0;
}