前言
构造函数和析构函数是两个特殊的成员函数,分别用于创建和销毁类的对象。若是不进行定义,那编译器则会提供默认的构造和析构函数,两者都是无参且函数体为空。
普通构造函数
基本使用
构造函数用于初始化对象的数据成员,函数名和类名一致,无返回值(不写void)。构造函数在对象创建时自动调用,用于完成对象的初始化操作。构造函数还可以接受参数,可以根据参数的数量、类型不同实现不同的初始化方法,称为构造函数的重载。
class A {
public:
A() {
std::cout << "no param constructor!" << std::endl;
}
//有参构造函数
A(int m) {
std::cout << "1 param constructor!" << std::endl;
}
A(int m,float n) {
std::cout << "2 param constructor!" << std::endl;
}
A(float m, int n) {
std::cout << "2__ param constructor!" << std::endl;
}
};
int main()
{
A a;//调用无参构造(正确)
A e();//调用无参构造(错误)
A b(1);
A c(1, 1.0);
A d(1.0,1);
system("pause");
return 0;
}
运行结果
其中A e( );是无参构造的错误调用方法,虽然编译器没有报错,但是没有任何结果。
避开带有默认值的构造函数
A(int m,float n) {
std::cout << "2 param constructor!" << std::endl;
}
A(int m, float n,int s=10) {
std::cout << "3 param constructor!" << std::endl;
}
上述两个构造函数会具有二义性,编译无法通过
析构函数
析构函数也是一种特殊的成员函数,用于在对象销毁时执行清理操作。析构函数的名称和类名相同,但前面加上一个波浪号(~)作为前缀。析构函数没有参数,也没有返回值包括(void)。当对象生命周期结束,即超出其作用域或程序结束时,析构函数会自动调用。
示例1
class A {
public:
A() {
std::cout << "no param constructor!" << std::endl;
}
~A(){
std::cout << u8"析构函数" << std::endl;
}
};
int main()
{
A a;//调用无参构造(正确)
}
运行结果:
示例二
int main()
{
A *a;
}
运行结果:
这是因为这里只是声明了一个对象指针,所以既不调用构造函数也不调用析构函数
示例三
但如果改成如下这样:
int main()
{
A *a;
a = new A();
}
运行截图:
这里会调用构造函数,但是自动不会调用析构函数。原因是这是通过new开辟的空间,需要手动通过delete释放掉
示例四
class A {
public:
A() {
std::cout << "no param constructor!" << std::endl;
}
~A(){
std::cout << u8"析构函数" << std::endl;
}
};
void func(A a) {
}
int main()
{
A a;
func(a);
}
运行结果:
func函数对形参a进行了拷贝构造,而非普通的构造函数,创建了a的一个副本,为浅拷贝,指向了同一块内存空间,但依旧会自动调用析构函数。
示例五
class A {
public:
A() {
std::cout << "no param constructor!" << std::endl;
}
~A(){
std::cout << u8"析构函数" << std::endl;
}
};
void func(const A &a) {
}
int main()
{
A a;
func(a);
}
运行结果:
这里func函数不会调用拷贝构造函数,只是对a对象取地址而已,操作的是同一个对象,故只有一个构造函数和析构函数。