MST

星途 面试题库

面试题:C++ 中深拷贝在多重继承与虚继承场景下的处理

考虑一个多重继承或虚继承的场景,在某个派生类中存在需要深拷贝的资源。请详细说明如何在这种复杂继承结构下正确实现深拷贝,包括可能遇到的问题及解决方案,并用代码示例加以阐述。
19.4万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

多重继承或虚继承下深拷贝的实现

  1. 理解问题
    • 在多重继承或虚继承中,派生类可能从多个基类继承状态,并且自身可能拥有需要深拷贝的资源(如动态分配的内存)。如果简单地使用默认的浅拷贝(编译器自动生成的拷贝构造函数和赋值运算符),会导致多个对象共享同一份资源,释放资源时可能出现重复释放或悬空指针等问题。
  2. 实现步骤
    • 实现拷贝构造函数
      • 在派生类的拷贝构造函数中,首先调用基类的拷贝构造函数(如果基类有自定义的拷贝构造函数),以确保基类部分被正确拷贝。
      • 然后对派生类自身需要深拷贝的资源进行分配和拷贝。
    • 实现赋值运算符重载
      • 先检查自赋值情况(if (this == &rhs)),避免不必要的操作。
      • 释放当前对象已有的资源(如果有)。
      • 调用基类的赋值运算符(如果基类有自定义的赋值运算符)来拷贝基类部分。
      • 为派生类自身的资源分配内存并进行拷贝。
  3. 可能遇到的问题及解决方案
    • 重复继承:在多重继承中,可能会出现一个基类被多次继承的情况。虚继承可以解决这个问题,它使得派生类中只会存在一份基类的子对象。
    • 资源管理混乱:如果多个基类都对同一个资源有管理权限,可能导致资源管理混乱。通过明确资源的所有权和管理责任来解决,比如让一个类负责资源的分配和释放,其他类通过引用计数等方式共享资源。

代码示例

#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类使用虚继承,避免了在多重继承中可能出现的重复继承问题。