目录
一、C++ 三大函数是什么
在 C++ 编程的世界里,拷贝构造函数、拷贝赋值运算符(拷贝复制)和析构函数,堪称是支撑起对象管理与资源控制大厦的三大支柱 ,理解并掌握它们,是 C++ 进阶之路上绕不开的关键节点。
1.1 拷贝构造函数
拷贝构造函数,是一种特殊的构造函数,专门用于创建一个新对象,并将其初始化为另一个已存在对象的副本 。它的函数声明形式通常为ClassName(const ClassName& obj) ,其中ClassName是类的名称,obj是对已存在对象的引用。
举个例子,假设我们有一个Student类,包含姓名和年龄两个成员变量:
class Student {
public:
std::string name;
int age;
// 普通构造函数
Student(const std::string& n, int a) : name(n), age(a) {}
// 拷贝构造函数
Student(const Student& other) : name(other.name), age(other.age) {}
};
当我们使用一个已有的Student对象去初始化另一个新的Student对象时,拷贝构造函数就会被调用:
Student s1("Alice", 20);
Student s2(s1); // 调用拷贝构造函数
在这个过程中,s2的成员变量name和age会被初始化为与s1相同的值,就像是克隆出了一个新的学生对象 。
1.2 拷贝赋值运算符(拷贝复制)
拷贝赋值运算符,即operator=,用于将一个已存在对象的值赋给另一个对象,实现对象之间的赋值操作 。它的声明形式为ClassName& operator=(const ClassName& obj) ,返回值是对调用对象的引用,以便支持链式赋值。
继续以Student类为例,我们来实现拷贝赋值运算符:
class Student {
public:
// ...其他成员和构造函数
// 拷贝赋值运算符
Student& operator=(const Student& other) {
if (this != &other) { // 防止自赋值
name = other.name;
age = other.age;
}
return *this;
}
};
使用时:
Student s1("Bob", 22);
Student s2("Charlie", 25);
s2 = s1; // 调用拷贝赋值运算符
此时,s2原有的值会被s1的值覆盖,就像是给s2重新 “注入” 了s1的信息 。
1.3析构函数
析构函数与构造函数的作用相反,用于在对象被销毁时执行清理操作,释放对象所占用的资源,比如动态分配的内存、打开的文件句柄等 。它的名称是在类名前加上波浪号~,没有返回值,也不接受任何参数 。
还是以Student类为例,假设我们为其添加一个动态分配的数组成员:
class Student {
public:
std::string name;
int age;
int* scores;
Student(const std::string& n, int a, int size) : name(n), age(a) {
scores = new int[size];
// 假设这里对scores进行初始化
for (int i = 0; i < size; ++i) {
scores[i] = 0;
}
}
~Student() {
delete[] scores; // 释放动态分配的内存
}
};
当Student对象的生命周期结束,比如离开其作用域或者被手动删除时,析构函数就会被自动调用,释放scores所占用的内存,防止内存泄漏 。
二、拷贝构造函数:对象复制的幕后英雄
拷贝构造函数作为 C++ 中一种特殊的构造函数,在对象的初始化与复制过程中扮演着极为关键的角色 。接下来,我们就深入了解一下它。
2.1 定义与语法
拷贝构造函数的定义,是用一个已经存在的对象来初始化另一个同类型的新对象 。它的语法形式为:ClassName(const ClassName& obj) ,其中ClassName是类的名称,obj是对已有对象的引用,并且这个参数必须是本类型的引用变量 。
比如,我们定义一个简单的Point类:
class Point {
public:
int x;
int y;
Point(int a, int b) : x(a), y(b) {}
// 拷贝构造函数
Point(const Point& other) : x(other.x), y(other.y) {}
};
在这个Point类中,拷贝构造函数Point(const Point& other)接受一个Point类型的引用参数other,并通过它来初始化新对象的x和y成员变量 。
2.2 调用时机
拷贝构造函数在以下三种常见情况下会被调用:
-
对象以值传递的方式传入函数参数:当我们把一个对象作为参数传递给函数,且函数参数不是引用类型时,就会调用拷贝构造函数来创建一个临时对象,这个临时对象是传入对象的副本 。
void printPoint(Point p) {
std::co