MST

星途 面试题库

面试题:C++重写拷贝构造函数在复杂继承体系下的注意事项

考虑一个复杂的继承体系,基类`BaseClass`有多个虚函数和一些动态分配的资源,派生类`DerivedClass1`和`DerivedClass2`继承自`BaseClass`,`DerivedClass1`又派生出`DerivedClass3`。在`DerivedClass3`中重写拷贝构造函数时,需要注意哪些方面,包括但不限于对基类资源的处理、虚函数表指针的维护、以及多重继承可能带来的问题等,请详细分析并编写代码示例展示正确的实现方式。
21.4万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试
  1. 注意事项分析
    • 基类资源处理:在DerivedClass3的拷贝构造函数中,首先要调用基类的拷贝构造函数来处理基类中的动态分配资源。因为基类BaseClass有动态分配的资源,若不调用基类拷贝构造函数,会导致资源泄漏或未初始化的问题。
    • 虚函数表指针维护:C++ 编译器会自动维护虚函数表指针。当调用基类拷贝构造函数时,虚函数表指针会被正确初始化。所以在DerivedClass3的拷贝构造函数中,无需手动处理虚函数表指针。
    • 多重继承问题:本题中没有涉及多重继承,若存在多重继承,需要注意每个基类的资源处理和虚函数表指针维护等情况,确保不会出现重复初始化或资源管理混乱的问题。
  2. 代码示例
#include <iostream>
#include <cstring>

class BaseClass {
public:
    BaseClass(const char* str) {
        data = new char[strlen(str) + 1];
        strcpy(data, str);
    }
    BaseClass(const BaseClass& other) {
        data = new char[strlen(other.data) + 1];
        strcpy(data, other.data);
    }
    BaseClass& operator=(const BaseClass& other) {
        if (this != &other) {
            delete[] data;
            data = new char[strlen(other.data) + 1];
            strcpy(data, other.data);
        }
        return *this;
    }
    virtual ~BaseClass() {
        delete[] data;
    }
    virtual void virtualFunction() {
        std::cout << "BaseClass virtualFunction" << std::endl;
    }
private:
    char* data;
};

class DerivedClass1 : public BaseClass {
public:
    DerivedClass1(const char* str) : BaseClass(str) {}
    DerivedClass1(const DerivedClass1& other) : BaseClass(other) {}
    DerivedClass1& operator=(const DerivedClass1& other) {
        if (this != &other) {
            BaseClass::operator=(other);
        }
        return *this;
    }
    void virtualFunction() override {
        std::cout << "DerivedClass1 virtualFunction" << std::endl;
    }
};

class DerivedClass2 : public BaseClass {
public:
    DerivedClass2(const char* str) : BaseClass(str) {}
    DerivedClass2(const DerivedClass2& other) : BaseClass(other) {}
    DerivedClass2& operator=(const DerivedClass2& other) {
        if (this != &other) {
            BaseClass::operator=(other);
        }
        return *this;
    }
    void virtualFunction() override {
        std::cout << "DerivedClass2 virtualFunction" << std::endl;
    }
};

class DerivedClass3 : public DerivedClass1 {
public:
    DerivedClass3(const char* str) : DerivedClass1(str) {}
    DerivedClass3(const DerivedClass3& other) : DerivedClass1(other) {}
    DerivedClass3& operator=(const DerivedClass3& other) {
        if (this != &other) {
            DerivedClass1::operator=(other);
        }
        return *this;
    }
    void virtualFunction() override {
        std::cout << "DerivedClass3 virtualFunction" << std::endl;
    }
};

你可以使用以下方式测试:

int main() {
    DerivedClass3 obj1("test");
    DerivedClass3 obj2(obj1);
    obj1.virtualFunction();
    obj2.virtualFunction();
    return 0;
}

在上述代码中,BaseClass有动态分配的资源(char* data),在拷贝构造函数和赋值运算符重载函数中正确处理了这些资源。DerivedClass1DerivedClass2DerivedClass3在拷贝构造函数和赋值运算符重载函数中都正确调用了基类的相应函数来处理基类资源,同时编译器自动维护了虚函数表指针。