构造函数和析构函数是类的特殊成员函数:
构造函数
- 用于创建对象时初始化对象的成员变量,为对象分配必要的资源(如内存、文件句柄等)。它的名字和类名完全相同,没有返回值(连 void 都不需要写)。
- 是由编译器自动调用的。
- 分类:
- 无参构造函数(默认构造函数)
- 有参构造函数
- [[类构造函数和析构函数#拷贝构造函数|拷贝构造函数]]
- 调用时机
- 直接创建对象(栈/堆)
- 创建对象数组;
- 函数返回类对象;
- 使用new动态分配内存。
- 特点:
- 无返回值,且不能使用void;
- 函数名与类名相同;
- 构造函数也可以进行重载;
- 当没有定义构造函数时,编译器会自动加一个无参构造函数。但当定义了任何类型的构造函数后,编译器不再添加默认构造函数;
- 如果构造函数私有将无法创建对象。
拷贝构造函数
拷贝构造函数是构造函数的重载版本,用于用一个已存在的对象 “拷贝” 创建一个新对象,本质是初始化新对象的成员变量为源对象的副本。 默认拷贝构造函数是 “浅拷贝”(直接复制成员变量的值);如果类有指针成员(如动态数组),需要手动实现 “深拷贝”(重新分配内存并复制内容),否则会导致多个对象共用同一块内存,析构时重复释放。
- 调用时机
- 用一个对象直接初始化另一个对象(person p1 = p2);
class Person {
public:
// 无参构造函数
Person()
{
cout << "调用了无参构造函数" << endl;
}
// 有参构造函数
Person(string name, int age)
{
cout << "调用有参构造函数" << endl;
this->name = name;
this->age = age;
}
// 拷贝构造函数
Person(const Person& p)
{
cout << "调用拷贝构造函数" << endl;
this->name = p.name;
this->age = p.age;
}
// 析构函数
~Person()
{
cout << "调用析构函数" << endl;
}
public:
string name;
int age;
};
int main()
{
Person p("zs", 10);
// 第一种
Person p1(p);
// 第二种
Person p2 = p1;
return EXIT_SUCCESS;
};
- 函数参数以值传递的方式接收类对象;
#include <string>
using namespace std;
class Person {
public:
// 无参构造函数
Person()
{
cout << "调用了无参构造函数" << endl;
}
// 有参构造函数
Person(string name, int age)
{
cout << "调用有参构造函数" << endl;
this->name = name;
this->age = age;
}
// 拷贝构造函数
Person(const Person& p)
{
cout << "调用拷贝构造函数" << endl;
this->name = p.name;
this->age = p.age;
}
// 析构函数
~Person()
{
cout << "调用析构函数" << endl;
}
public:
string name;
int age;
};
// 这里函数的参数以值传递的方式接受一个对象
// 调用拷贝构造函数
void test01(Person p)
{
cout << p.name << p.age << endl;
}
int main()
{
Person p("zs", 10);
test01(p);
return EXIT_SUCCESS;
};
- 函数以值返回类对象(C++17 后可能被 RVO 优化,但语义上仍会触发);
- 创建对象数组时用单个对象初始化所有元素。
- 使用注意事项
- 参数必须使用引用,如果不是引用则变成了赋值操作;
- class obj1 = obj2这种方式也会使用拷贝构造;
析构函数
- 析构函数是构造函数的 “反向操作”,用于对象销毁时释放对象占用的资源(如堆内存、关闭文件、释放锁等)。它的名字是
~类名,无参数、无返回值,一个类只能有一个析构函数。 - 调用时机
- 栈对象超出作用域(如函数执行完毕、代码块结束);
- 堆对象被
delete销毁; - 对象数组被销毁;
- 程序结束时,全局 / 静态对象被销毁。
- 特点
- 不能重载
- 无返回值,不能使用void;
- 无参数
- 析构函数必须公有,否则无法调用
赋值函数(赋值运算符重载,opertor=)
赋值函数是重载 = 运算符的成员函数,用于将一个已存在的对象的值 “赋值” 给另一个已存在的对象。
[! 注意] 是 “赋值” 不是 “初始化”
调用时机:
- 直接用
=给已创建的对象赋值(p2 = p1;); - 连续赋值(
p3 = p2 = p1;); - 某些容器操作(如
vector::assign)触发赋值。