面试题答案
一键面试多重继承场景中重写拷贝构造函数的复杂性
- 基类初始化顺序:在多重继承中,基类的初始化顺序是按照它们在类定义中声明的顺序进行的。如果拷贝构造函数没有正确遵循这个顺序初始化基类,可能会导致未定义行为。
- 重复基类子对象:如果存在菱形继承结构(多个基类继承自同一个基类),可能会出现基类子对象的重复。拷贝构造函数需要确保只对基类子对象进行一次正确的拷贝,避免数据冗余和不一致。
- 成员变量拷贝:除了基类,派生类自身的成员变量也需要正确拷贝。要保证成员变量的拷贝顺序和正确性,避免数据丢失或错误拷贝。
处理复杂性的方法
- 明确基类初始化顺序:在拷贝构造函数的初始化列表中,按照基类在类定义中的声明顺序初始化基类。
- 虚继承解决菱形继承问题:使用虚继承可以确保在菱形继承结构中,基类子对象只被初始化一次。在拷贝构造函数中,正确处理虚基类的拷贝。
- 正确拷贝成员变量:在初始化基类后,在构造函数体中正确拷贝派生类的成员变量。
代码示例
#include <iostream>
#include <string>
// 虚基类
class Base {
public:
int value;
Base(int v) : value(v) {}
// 拷贝构造函数
Base(const Base& other) : value(other.value) {}
};
// 继承自Base的类
class Derived1 : virtual public Base {
public:
std::string str1;
Derived1(int v, const std::string& s) : Base(v), str1(s) {}
// 拷贝构造函数
Derived1(const Derived1& other) : Base(other), str1(other.str1) {}
};
// 继承自Base的类
class Derived2 : virtual public Base {
public:
std::string str2;
Derived2(int v, const std::string& s) : Base(v), str2(s) {}
// 拷贝构造函数
Derived2(const Derived2& other) : Base(other), str2(other.str2) {}
};
// 多重继承类
class FinalDerived : public Derived1, public Derived2 {
public:
double d;
FinalDerived(int v, const std::string& s1, const std::string& s2, double num)
: Base(v), Derived1(v, s1), Derived2(v, s2), d(num) {}
// 拷贝构造函数
FinalDerived(const FinalDerived& other)
: Base(other), Derived1(other), Derived2(other), d(other.d) {}
};
int main() {
FinalDerived obj(10, "Hello", "World", 3.14);
FinalDerived objCopy(obj);
std::cout << "objCopy.value: " << objCopy.value << std::endl;
std::cout << "objCopy.str1: " << objCopy.str1 << std::endl;
std::cout << "objCopy.str2: " << objCopy.str2 << std::endl;
std::cout << "objCopy.d: " << objCopy.d << std::endl;
return 0;
}
在上述代码中:
Base
是虚基类,通过虚继承避免了在FinalDerived
中出现多个Base
子对象。Derived1
和Derived2
分别继承自Base
,并实现了各自的拷贝构造函数。FinalDerived
多重继承自Derived1
和Derived2
,其拷贝构造函数正确初始化了所有基类和自身的成员变量。- 在
main
函数中,创建了FinalDerived
对象并进行拷贝,验证了拷贝构造函数的正确性。