面试题答案
一键面试功能区别
- 拷贝构造函数:用于创建一个新对象,该对象是另一个同类对象的副本。它主要用于初始化新对象。
- 赋值运算符重载:用于将一个已存在对象的值赋给另一个已存在对象。它主要用于改变已存在对象的状态。
调用场景区别
- 拷贝构造函数:
- 对象初始化:当使用一个已存在对象初始化新对象时,例如
ClassA a; ClassA b(a);
或者ClassA b = a;
(这种初始化形式会调用拷贝构造函数,而非赋值运算符)。 - 函数参数传递:当对象以值传递方式作为函数参数时,会调用拷贝构造函数创建一个临时副本传入函数。
- 函数返回值:当函数返回一个对象时,会调用拷贝构造函数创建一个临时对象作为返回值。
- 对象初始化:当使用一个已存在对象初始化新对象时,例如
- 赋值运算符重载:
- 对象赋值:当对已存在的对象进行赋值操作时,例如
a = b;
,这里a
和b
都已经是初始化过的对象。
- 对象赋值:当对已存在的对象进行赋值操作时,例如
实现区别
- 拷贝构造函数:
- 其函数签名形式为
ClassName(const ClassName& other)
。 - 在实现时,通常为新对象分配内存并将源对象的数据成员逐一复制到新对象中。对于包含动态分配内存的类,需要深拷贝,避免浅拷贝带来的内存管理问题。
- 其函数签名形式为
- 赋值运算符重载:
- 其函数签名形式为
ClassName& operator=(const ClassName& other)
。 - 在实现时,首先要检查是否是自赋值(
if (this == &other) return *this;
),然后释放当前对象的资源(如果有动态分配的资源),再为当前对象重新分配内存并复制源对象的数据成员。
- 其函数签名形式为
举例说明
#include <iostream>
#include <cstring>
class MyString {
private:
char* str;
int length;
public:
// 构造函数
MyString(const char* s = nullptr) {
if (s == nullptr) {
length = 0;
str = new char[1];
str[0] = '\0';
}
else {
length = strlen(s);
str = new char[length + 1];
strcpy(str, s);
}
}
// 拷贝构造函数
MyString(const MyString& other) {
length = other.length;
str = new char[length + 1];
strcpy(str, other.str);
}
// 赋值运算符重载
MyString& operator=(const MyString& other) {
if (this == &other)
return *this;
delete[] str;
length = other.length;
str = new char[length + 1];
strcpy(str, other.str);
return *this;
}
// 析构函数
~MyString() {
delete[] str;
}
void print() {
std::cout << str << std::endl;
}
};
int main() {
MyString s1("Hello");
MyString s2(s1); // 调用拷贝构造函数
MyString s3;
s3 = s1; // 调用赋值运算符重载
s1.print();
s2.print();
s3.print();
return 0;
}
在上述代码中,MyString
类展示了拷贝构造函数和赋值运算符重载的实现。s2(s1)
调用拷贝构造函数初始化 s2
,s3 = s1
调用赋值运算符重载为 s3
赋值。