目录
一、什么是构造函数与析构函数?
当我们创建一个类并且将它实例化成一个对象的时候,在创建对象的时候,若是我们没有指定构造函数,编译器会默认提供一个无参构造函数并调用它,默认的构造函数中没有东西能让给我们显示的看到它的调用情况,但是它是是实实在在存在的;而析构函数就是在这个对象的生命周期结束的时候被调用,在调用析构函数后,这个实例化的对象就会被销毁
二、构造函数与析构函数
1.构造函数
#include<iostream>
using namespace std;
class Circle {
public:
Circle() {
cout <<"我调用了Circle类的构造函数" << endl;
}
public:
int R = 3;
const int pi = 3;
};
int main() {
Circle c1;
}
其中,在类中声明在public权限中的Circle函数就是这个类的构造函数,在程序调用对象的时候会由编译器自动调用
(1)构造函数的要求
- 构造函数名与类名一致;
- 构造函数无返回值,函数名前不需要加上viod,int一类的返回类型;
- 构造函数有参数,因此可以发生函数重载;
- 只被调用一次。
(2) 构造函数的类型
- 按照是否传入参数分为:有参构造和无参构造;
- 按照构造函数的类型分为:普通构造和拷贝构造。
(3)比较特殊的构造函数——拷贝构造函数
#include<iostream>
using namespace std;
class Circle {
public:
Circle() {
cout <<"调用了Circle类的构造函数" << endl;
}
Circle(const Circle& c) {
cout << "调用了Circle类的拷贝构造函数" << endl;
}
~Circle() {
cout << "调用了Circle类的析构函数" << endl;
}
public:
int R = 3;
const int pi = 3;
};
void text01(Circle c) {};
int main() {
Circle c1;
text01(c1);
}
运行这段代码我们不难知道,由于函数text01使用的是值传递的方式传递参数,因此我们在调用text01时创建了一个新的临时的局部变量在函数中,因此调用了一次拷贝构造函数,在函数结束时,编译器由自动调用了一次析构函数去销毁这个临时变量。
拷贝构造函数何时被调用?
- 以值传递的形式给函数参数传值的时候;
- 用一个已经存在的对象去初始化一个新对象的时候;
- 以值的方式返回一个局部对象的时候
(4)拷贝构造函数的注意点
拷贝构造函数的形参一定要是引用类型(&),这是确保在调用拷贝构造函数的时候使用的是引用传参,确保传入拷贝构造函数的参数不会在其中被误操作,可以思考一下如果使用的是值传递的话,首先编译器会直接报错,如果它不给报错呢?在调用拷贝构造函数的时候要先对传入的参数进行拷贝,这个过程就需要调用拷贝构造函数,那岂不是就进入了一个死循环?
#include<iostream>
using namespace std;
class Circle {
public:
Circle() {
cout <<"调用了Circle类的构造函数" << endl;
}
Circle(Circle& c) {
cout << "" << endl;
cout <<"传入的参数c1的地址是" << &c << endl;
cout << "调用了Circle类的拷贝构造函数" << endl;
}
~Circle() {
cout << "调用了Circle类的析构函数" << endl;
}
public:
int R = 3;
const int pi = 3;
};
void text01(Circle c) {
cout <<"临时变量的地址是" << &c << endl;
};
int main() {
Circle c1;
cout << &c1 << endl;
text01(c1);
}
通过这段代码,我们这样可以很直观的看出地址的变化情况,更利于我们理解拷贝构造函数。
2.析构函数
析构函数就是当我们实例化出来的这个对象结束生命周期时被调用的一个函数,在析构函数被调用之后,这个对象也就不存在了。
#include<iostream>
using namespace std;
class Circle {
public:
Circle() {
cout <<"我调用了Circle类的构造函数" << endl;
}
~Circle() {
cout << "我调用了Circle类的析构函数" << endl;
}
public:
int R = 3;
const int pi = 3.14;
};
int main() {
Circle c1;
}
析构函数会由编译器默认提供,但是我们也可以自己去编写它。
-
析构函数的要求
- 跟构造函数一样,没有返回值也没有返回类型;
- 函数名跟类名一致,并且一定要在函数名前加上一个”~”,如果没有这个“~”,这个函数就是构造函数了;
- 不能有参数,因此析构函数不能发生函数重载
- 只被调用一次。
三、编译器提供构造函数的规则
一般情况下,编译器至少提供三个默认函数,分别是默认构造函数、默认析构函数与默认拷贝构造函数。
规则:如果我们写了普通构造函数,那么编译器不再提供默认构造函数,但是依然提供默认拷贝构造函数与默认析构函数;如果我们写了默认拷贝构造函数,那么编译器就不再提供其他的普通构造函数了。