面试题答案
一键面试多重继承或虚继承下深拷贝的实现
- 理解问题:
- 在多重继承或虚继承中,派生类可能从多个基类继承状态,并且自身可能拥有需要深拷贝的资源(如动态分配的内存)。如果简单地使用默认的浅拷贝(编译器自动生成的拷贝构造函数和赋值运算符),会导致多个对象共享同一份资源,释放资源时可能出现重复释放或悬空指针等问题。
- 实现步骤:
- 实现拷贝构造函数:
- 在派生类的拷贝构造函数中,首先调用基类的拷贝构造函数(如果基类有自定义的拷贝构造函数),以确保基类部分被正确拷贝。
- 然后对派生类自身需要深拷贝的资源进行分配和拷贝。
- 实现赋值运算符重载:
- 先检查自赋值情况(
if (this == &rhs)
),避免不必要的操作。 - 释放当前对象已有的资源(如果有)。
- 调用基类的赋值运算符(如果基类有自定义的赋值运算符)来拷贝基类部分。
- 为派生类自身的资源分配内存并进行拷贝。
- 先检查自赋值情况(
- 实现拷贝构造函数:
- 可能遇到的问题及解决方案:
- 重复继承:在多重继承中,可能会出现一个基类被多次继承的情况。虚继承可以解决这个问题,它使得派生类中只会存在一份基类的子对象。
- 资源管理混乱:如果多个基类都对同一个资源有管理权限,可能导致资源管理混乱。通过明确资源的所有权和管理责任来解决,比如让一个类负责资源的分配和释放,其他类通过引用计数等方式共享资源。
代码示例
#include <iostream>
#include <cstring>
// 基类A
class A {
public:
A() : data(nullptr) {}
A(const A& other) {
if (other.data) {
data = new char[strlen(other.data) + 1];
strcpy(data, other.data);
} else {
data = nullptr;
}
}
A& operator=(const A& other) {
if (this == &other) return *this;
if (data) delete[] data;
if (other.data) {
data = new char[strlen(other.data) + 1];
strcpy(data, other.data);
} else {
data = nullptr;
}
return *this;
}
~A() {
if (data) delete[] data;
}
private:
char* data;
};
// 虚基类B
class B {
public:
B() : value(0) {}
B(const B& other) : value(other.value) {}
B& operator=(const B& other) {
if (this == &other) return *this;
value = other.value;
return *this;
}
private:
int value;
};
// 派生类C,多重继承和虚继承的示例
class C : public virtual B, public A {
public:
C() : extraData(nullptr) {}
C(const C& other) : B(other), A(other) {
if (other.extraData) {
extraData = new char[strlen(other.extraData) + 1];
strcpy(extraData, other.extraData);
} else {
extraData = nullptr;
}
}
C& operator=(const C& other) {
if (this == &other) return *this;
A::operator=(other);
B::operator=(other);
if (extraData) delete[] extraData;
if (other.extraData) {
extraData = new char[strlen(other.extraData) + 1];
strcpy(extraData, other.extraData);
} else {
extraData = nullptr;
}
return *this;
}
~C() {
if (extraData) delete[] extraData;
}
private:
char* extraData;
};
在上述代码中,C
类从虚基类B
和普通基类A
继承。C
类有自己需要深拷贝的资源extraData
,通过正确实现拷贝构造函数和赋值运算符重载,保证了在复杂继承结构下的深拷贝正确性。同时,B
类使用虚继承,避免了在多重继承中可能出现的重复继承问题。