您如何管理指向在派生类中都扩展的基类的指针?
最近,我一直在抽象和清理我的一个项目,以便为新功能做好准备。当我意识到我想将指向图形上下文和窗口的指针作为抽象类进行管理时,我遇到了一个设计问题。我已经搜索了答案,但还没有找到任何令人满意的东西。我有一种情况,我正在创建一个扩展窗口类和图形上下文类的窗口,就像这样......
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);
}
虽然这在对象的生命周期中或多或少是有效的,但在销毁时它会成为一个问题,因为根据销毁的顺序,您可能会删除空内存。拥有指向两者的指针很有用,因为我需要访问虚函数,并且如果可能的话,我希望保持图形上下文和窗口解耦。有没有办法做到这一点?
编辑:改变unique_ptr以shared_ptr作为前者是不正确的
回答
使用 ashared_ptr来管理derived类的所有权。然后使用std::shared_ptr的别名构造函数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()));
...
这提供了对基类的安全访问,而不会冒提前删除或重复删除的风险。只有当所有这些指针中的最后一个超出范围时,derived实例(及其两个基类对象)才会被销毁。
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
编辑:虽然上述内容适用于成员对象和基类子对象,但shared_ptr已经定义了基类指针的转换,正如@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