第5课_拷贝构造与赋值
热度🔥:66 免费课程
授课语音
C++中的拷贝构造函数与赋值运算符重载
在C++中,拷贝构造函数和赋值运算符重载是两个重要的特性,它们主要用于控制对象如何复制,以避免默认行为导致的问题。正确理解和实现它们对管理资源和编写健壮的程序至关重要。
1. 拷贝构造函数
1.1 拷贝构造函数的定义
拷贝构造函数是一种特殊的构造函数,用于通过同类型的对象来初始化新对象。其语法如下:
class ClassName {
public:
ClassName(const ClassName& obj);
};
1.2 作用与特点
- 默认拷贝构造函数会逐成员复制对象的非静态成员(浅拷贝)。
- 如果类中包含指针或需要深拷贝的资源,必须自定义拷贝构造函数。
1.3 拷贝构造函数的代码案例
#include <iostream>
#include <cstring>
class MyString {
private:
char* data; // 动态分配的字符数组
size_t length; // 字符串长度
public:
// 构造函数
MyString(const char* str) {
length = strlen(str);
data = new char[length + 1]; // 分配内存
strcpy(data, str); // 复制字符串内容
std::cout << "Constructor called for: " << data << std::endl;
}
// 拷贝构造函数
MyString(const MyString& other) {
length = other.length;
data = new char[length + 1]; // 分配新内存
strcpy(data, other.data); // 深拷贝数据
std::cout << "Copy Constructor called for: " << data << std::endl;
}
// 打印字符串
void print() const {
std::cout << data << std::endl;
}
// 析构函数
~MyString() {
std::cout << "Destructor called for: " << data << std::endl;
delete[] data; // 释放内存
}
};
int main() {
MyString str1("Hello"); // 调用普通构造函数
MyString str2 = str1; // 调用拷贝构造函数
str1.print();
str2.print();
return 0;
}
代码解析
MyString(const MyString& other)
:通过other
对象初始化当前对象。new char[length + 1]
和strcpy
实现深拷贝,避免多个对象共享同一块内存。- 调用顺序展示了构造、拷贝构造和析构函数的执行情况。
2. 赋值运算符重载
2.1 赋值运算符的定义
赋值运算符重载用于定义两个已存在对象之间赋值操作的行为,其语法如下:
class ClassName {
public:
ClassName& operator=(const ClassName& obj);
};
2.2 作用与特点
- 默认赋值运算符也是逐成员复制(浅拷贝)。
- 自定义赋值运算符需要考虑深拷贝、资源管理以及自赋值问题。
2.3 赋值运算符的代码案例
#include <iostream>
#include <cstring>
class MyString {
private:
char* data;
size_t length;
public:
// 构造函数
MyString(const char* str) {
length = strlen(str);
data = new char[length + 1];
strcpy(data, str);
std::cout << "Constructor called for: " << data << std::endl;
}
// 赋值运算符重载
MyString& operator=(const MyString& other) {
std::cout << "Assignment operator called for: " << other.data << std::endl;
if (this == &other) {
// 检查自赋值
return *this;
}
// 释放原有资源
delete[] data;
// 深拷贝新资源
length = other.length;
data = new char[length + 1];
strcpy(data, other.data);
return *this;
}
// 打印字符串
void print() const {
std::cout << data << std::endl;
}
// 析构函数
~MyString() {
std::cout << "Destructor called for: " << data << std::endl;
delete[] data;
}
};
int main() {
MyString str1("Hello");
MyString str2("World");
str2 = str1; // 调用赋值运算符重载
str1.print();
str2.print();
return 0;
}
代码解析
- 检查
if (this == &other)
防止自赋值。 delete[] data
释放原资源,避免内存泄漏。- 深拷贝
other.data
,确保两个对象互不干扰。
3. 拷贝构造与赋值运算符的区别
特性 | 拷贝构造函数 | 赋值运算符重载 |
---|---|---|
适用场景 | 初始化新对象 | 对现有对象赋值 |
是否需检查自赋值 | 不需要 | 需要 |
默认行为 | 浅拷贝 | 浅拷贝 |
3.1 实践建议
- 如果类中涉及动态内存分配或资源管理,必须实现深拷贝逻辑。
- 推荐遵循“拷贝构造函数、赋值运算符和析构函数同时实现或同时不实现”的原则(即“三法则”)。
通过掌握拷贝构造函数和赋值运算符重载,能够有效避免浅拷贝导致的内存管理问题,提高代码的健壮性和可维护性。