您如何管理指向在派生 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_ptr
的 aliasing 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
编辑: 虽然以上内容适用于成员对象和基础 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);
最近,我一直在抽象和清理我的一个项目,为新功能做好准备。当我意识到我想管理指向图形上下文和 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_ptr
的 aliasing 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
编辑: 虽然以上内容适用于成员对象和基础 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);