MST

星途 面试题库

面试题:C++ 中涉及多态与资源管理的拷贝构造函数重写

假设有一个基类 `Shape`,它有多个派生类如 `Circle`、`Rectangle` 等。`Shape` 类包含一个指向动态分配资源的指针 `Resource* res`,不同派生类对该资源有不同的管理方式。在实现一个能正确处理多态对象拷贝的系统中,如何重写拷贝构造函数以确保资源的正确复制与管理,同时避免切片问题?请详细说明设计思路并给出关键代码片段。
48.2万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试
  1. 设计思路
    • 由于存在多态性和动态分配资源,不能使用默认的拷贝构造函数,因为默认拷贝构造函数进行的是浅拷贝,会导致多个对象共享同一份动态分配的资源,在析构时出现多次释放同一资源的错误。
    • 为了确保资源的正确复制与管理,在基类 Shape 中,需要实现深拷贝构造函数。在深拷贝构造函数中,为新对象分配独立的资源,并将原对象资源的内容复制过来。
    • 为了避免切片问题,需要在基类中定义虚的克隆函数(clone),每个派生类重写这个函数,返回自身的深拷贝。这样在进行对象拷贝时,可以通过调用 clone 函数实现多态的深拷贝。
  2. 关键代码片段
#include <iostream>
#include <memory>

// 资源类
class Resource {
public:
    Resource() { std::cout << "Resource constructed" << std::endl; }
    ~Resource() { std::cout << "Resource destructed" << std::endl; }
};

// 基类 Shape
class Shape {
protected:
    std::unique_ptr<Resource> res;
public:
    Shape() : res(std::make_unique<Resource>()) {}
    // 虚析构函数,确保派生类析构时调用正确的析构函数
    virtual ~Shape() = default;
    // 虚克隆函数
    virtual std::unique_ptr<Shape> clone() const = 0;
    // 深拷贝构造函数
    Shape(const Shape& other) : res(std::make_unique<Resource>(*other.res)) {}
    // 深拷贝赋值运算符重载
    Shape& operator=(const Shape& other) {
        if (this != &other) {
            res = std::make_unique<Resource>(*other.res);
        }
        return *this;
    }
};

// 派生类 Circle
class Circle : public Shape {
public:
    Circle() = default;
    // 重写克隆函数
    std::unique_ptr<Shape> clone() const override {
        return std::make_unique<Circle>(*this);
    }
};

// 派生类 Rectangle
class Rectangle : public Shape {
public:
    Rectangle() = default;
    // 重写克隆函数
    std::unique_ptr<Shape> clone() const override {
        return std::make_unique<Rectangle>(*this);
    }
};

在上述代码中:

  • Resource 类模拟动态分配的资源。
  • Shape 类包含指向 Resourcestd::unique_ptr,实现了深拷贝构造函数和赋值运算符重载。同时定义了虚析构函数和纯虚的 clone 函数。
  • CircleRectangle 派生类重写了 clone 函数,返回自身类型的深拷贝。这样在进行多态对象拷贝时,可以通过 clone 函数实现正确的深拷贝并避免切片问题。例如:
int main() {
    std::unique_ptr<Shape> shape1 = std::make_unique<Circle>();
    std::unique_ptr<Shape> shape2 = shape1->clone();
    return 0;
}

这里 shape2shape1 的深拷贝,且 shape2 的实际类型和 shape1 相同,避免了切片问题。