C++拷贝构造函数是一个特殊的成员函数,它用于创建类对象的一个副本(即深复制)。当一个新对象被创建并且其初始值来自同类的另一个对象时,拷贝构造函数会被自动调用。以下是拷贝构造函数的主要特点:
定义:
拷贝构造函数具有单个参数,该参数是对本类类型的引用,并且通常为const引用,以防止意外修改原对象。
class MyClass {
public:
// 拷贝构造函数声明
MyClass(const MyClass& other); // 或者 MyClass(MyClass const &other);
// ...其他成员变量和成员函数...
};
调用时机:
行为:
拷贝构造函数负责正确地初始化新对象,这可能包括:
默认行为与自定义:
常量引用参数:
参数通常使用const引用的原因是避免不必要的临时对象创建和销毁,同时表明不会更改传入的对象状态。虽然不强制要求const,但在实际编程实践中几乎总是选择const引用,以遵循最佳实践。
#include <iostream>
#include <cstring> // 用于memcpy
class String {
public:
// 普通构造函数,初始化字符串
String(const char* str) : length(strlen(str)), content(new char[length + 1]) {
memcpy(content, str, length + 1); // 包括结束符'\0'
}
// 拷贝构造函数(深度拷贝)
String(const String& other) : length(other.length), content(new char[other.length + 1]) {
memcpy(content, other.content, length + 1);
}
// 析构函数,释放内存资源
~String() {
delete[] content;
}
// 省略了赋值运算符重载以简化示例,实际项目中也需要进行深拷贝
private:
int length;
char* content;
};
int main() {
String s1("Hello, World!");
String s2(s1); // 这里会调用拷贝构造函数进行深度拷贝
std::cout << s1.content << std::endl; // 输出 "Hello, World!"
std::cout << s2.content << std::endl; // 输出 "Hello, World!"
return 0;
}
在上述例子中,String
类有一个指向动态分配的字符数组的指针成员 content
。默认的浅拷贝行为只会复制这个指针,而不是复制指针所指向的数据。因此,在使用默认的浅拷贝构造函数时,当源对象和副本对象都析构时,它们会试图删除同一块内存区域,导致未定义的行为。通过自定义拷贝构造函数,我们为 s2
分配新的内存,并将 s1
的内容复制到新内存中,这样 s1
和 s2
就各自拥有独立的字符串数据,实现了深度拷贝。
在实现拷贝构造函数时,一定要注意是否存在指针,或者其它资源(不能通过简单赋值完成的),就需要对指针所指的空间进行数据复制,不能只是简单的复制指针复制的浅复制。