最近,我一直在对我的一个项目进行抽象和清理,以便为新功能做好准备。当我意识到我想把指向图形上下文和窗口的指针作为抽象类来管理时,我遇到了一个设计问题。我一直在寻找答案,但还没有找到任何令人满意的答案。我有一种情况,我正在创建一个窗口,扩展窗口类和图形上下文类,比如…
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
,因为前者的不正确
使用shared_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
实时演示
编辑:虽然以上适用于成员对象和基类子对象,但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);
更新的实时演示