【C++ 基础】构造函数、析构函数

2 阅读4分钟

构造函数和析构函数是类的特殊成员函数:

构造函数

  • 用于创建对象时初始化对象的成员变量,为对象分配必要的资源(如内存、文件句柄等)。它的名字和类名完全相同,没有返回值(连 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)触发赋值。