您如何管理指向在派生 class 中扩展的基 classes 的指针?

How do you manage pointers to base classes that are both extended in a derived class?

最近,我一直在抽象和清理我的一个项目,为新功能做好准备。当我意识到我想管理指向图形上下文和 window 的指针作为抽象 classes 时,我遇到了一个设计问题。我已经搜索了答案,但还没有找到令人满意的答案。我有一种情况,我正在创建一个扩展 window class 和图形上下文 class 的 window,就像这样...

class base_a
{
// base_a virtual methods
};

class base_b
{
// base_b virtual methods
};

class derived : public base_a, public base_b
{
//other methods
};

int main ()
{
    derived* d = new derived();
// This is what I want to do
    std::shared_ptr<base_a> ptr1 (d);
    std::shared_ptr<base_b> ptr2 (d);
}

虽然这在对象的生命周期内或多或少地起作用,但在析构时它会成为一个问题,因为根据析构的顺序,您可能会删除空内存。拥有指向两者的指针很有用,因为我需要访问虚拟函数,并且我希望尽可能保持图形上下文和 window 分离。有办法吗?

编辑:将 unique_ptr 更改为 shared_ptr,因为前者不正确

使用 shared_ptr 管理 derived class 的所有权。然后使用 std::shared_ptraliasing constructor 通过指向基 class 之一的指针共享 derived 实例的所有权。这可能是这样的:

class base_a {
public:
    int x = 1;
};

class base_b {
public:
    int y = 2;
};

class derived : public base_a, public base_b {
public:
    int z = 3;
};

int main() {
    auto d_ptr = std::make_shared<derived>();
    
    auto a_ptr = std::shared_ptr<base_a>(d_ptr, static_cast<base_a*>(d_ptr.get()));
    auto b_ptr = std::shared_ptr<base_b>(d_ptr, static_cast<base_b*>(d_ptr.get()));
    ...

这提供了对基础 classes 的安全访问,而不会有提前删除或双重删除的风险。只有当所有这些指针中的最后一个超出范围时,derived 实例(以及它的两个基础 class 对象)才会被销毁。


std::cout << "x : " << d_ptr->x << '\n';
std::cout << "y : " << d_ptr->y << '\n';
std::cout << "z : " << d_ptr->z << '\n';

std::cout << "---\n";
a_ptr->x = 4;
b_ptr->y = 5;

std::cout << "x : " << d_ptr->x << '\n';
std::cout << "y : " << d_ptr->y << '\n';
std::cout << "z : " << d_ptr->z << '\n';

输出:

x : 1
y : 2
z : 3
---
x : 4
y : 5
z : 3

Live Demo


编辑: 虽然以上内容适用于成员对象和基础 class 子对象,shared_ptr 已经为基础 [=42= 定义了转换] 指针,正如@BenVoigt 所指出的那样。这将代码简化为:

auto d_ptr = std::make_shared<derived>();

auto a_ptr = std::shared_ptr<base_a>(d_ptr);
auto b_ptr = std::shared_ptr<base_b>(d_ptr);

Updated Live Demo