使用boost shared_from_this
和多重继承时,我目前遇到了一些麻烦。
该方案可描述如下:
类A
实现了一些功能,应该继承自shared_from_this
类B
实现了另一项功能,应该继承自shared_from_this
班级D
继承了A
和B
(class D : public A, public B {}
)
使用课程B
中的某些课程D
时,我遇到了异常(weak_ptr
)
从班级shared_from_this
继承D
不是我的选择
我不确定如何解决这个问题。
哦,我正在使用Visual C ++ 2010。
答案 0 :(得分:8)
扩展Potatoswatter的解决方案,如果你可以改变A和B使用与enable_shared_from_this略有不同的东西。代码使用标准库版本,但boost实现应该类似。下面的说明
#include <memory>
template<typename T>
struct enable_shared_from_this_virtual;
class enable_shared_from_this_virtual_base : public std::enable_shared_from_this<enable_shared_from_this_virtual_base>
{
typedef std::enable_shared_from_this<enable_shared_from_this_virtual_base> base_type;
template<typename T>
friend struct enable_shared_from_this_virtual;
std::shared_ptr<enable_shared_from_this_virtual_base> shared_from_this()
{
return base_type::shared_from_this();
}
std::shared_ptr<enable_shared_from_this_virtual_base const> shared_from_this() const
{
return base_type::shared_from_this();
}
};
template<typename T>
struct enable_shared_from_this_virtual: virtual enable_shared_from_this_virtual_base
{
typedef enable_shared_from_this_virtual_base base_type;
public:
std::shared_ptr<T> shared_from_this()
{
std::shared_ptr<T> result(base_type::shared_from_this(), static_cast<T*>(this));
return result;
}
std::shared_ptr<T const> shared_from_this() const
{
std::shared_ptr<T const> result(base_type::shared_from_this(), static_cast<T const*>(this));
return result;
}
};
因此,意图是struct A
将从enable_shared_from_this_virtual<A>
公开继承而struct B
将从enable_shared_from_this_virtual<B>
公开继承。由于它们共享相同的公共虚拟对象,因此层次结构中只有一个std::enable_shared_from_this
。
当你调用类shared_from_this
时,它执行从enable_shared_from_this_virtual<T>*
到T *的转换,并使用shared_ptr的别名构造函数,以便新的shared_ptr指向T *并与单个共享所有权共享指针。
使用顶部的朋友是为了防止任何人直接访问虚拟基地的shared_from_this()成员。他们必须经过enable_shared_from_this_virtual<T>
提供的那些。
一个例子:
#include <iostream>
struct A : public enable_shared_from_this_virtual<A>
{
void foo()
{
shared_from_this()->baz();
}
void baz()
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
struct B : public enable_shared_from_this_virtual<B>
{
void bar()
{
shared_from_this()->baz();
}
void baz()
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
struct D: A, B {};
int main()
{
std::shared_ptr<D> d(new D);
d->foo();
d->bar();
return 0;
}
答案 1 :(得分:4)
shared_ptr
是不可见容器对象或“控制块”的观察者。这个容器总是在堆上,永远不在堆栈上,你无法直接处理它。虽然shared_ptr
和weak_ptr
提供了唯一的观察方法,但仍然有一个拥有该对象的隐藏层。这是隐藏层,填充enable_shared_from_this
。
不允许来自enable_shared_from_this
的多重继承,因为所有enable_shared_from_this
个基都需要单独初始化,但控制块无法获取给定类型的所有基础子对象的列表。它所能得到的只是一个模糊的基本错误。
我看到的唯一解决方案是添加virtual
基类A
和B
,其继承自enable_shared_from_this
。您可以为此目的指定一个特定的类:
struct shared_from_this_virtual_base
: std::enable_shared_from_this< shared_from_this_virtual_base >
{};
struct shared_from_this_base : virtual shared_from_this_virtual_base {};
struct A : shared_from_this_base { … };
struct B : shared_from_this_base { … };
但是,还有另一个问题:你不能从virtual
基础向下投射,因为A
或B
包含shared_from_this_virtual_base
是不明确的。要恢复A*
或B*
,您必须将这些指针添加到shared_from_this_virtual_base
中的某种注册表结构中。这可能会通过向shared_from_this_base
添加另一个CRTP模式来填充。对于C ++来说,这比通常的步法要多一些,但我没有看到任何概念上的捷径。
编辑:啊,获得向下转发的最简单方法是将void*
成员放入shared_from_this_virtual_base
,然后将其转发到D*
的任何客户端代码具有D
的知识。相当可行,如果不是非常优雅。或者boost::any
可以提供更安全的替代方案。
答案 2 :(得分:2)
标准对于shared_from_this
应该如何实现有点模糊,但所有实现似乎都同意,因为Boost提供了参考实现。
当您创建boost::shared_ptr<D> myD(new D())
时,shared_ptr
构造函数会检查某些D*
是否存在从enable_shared_from_this<X>*
到X
的明确转换(这意味着D
1}}有一个类型为enable_shared_from_this<X>
的基类。如果转换有效,则基类中的weak_ptr<X>
将设置为引用新创建的shared_ptr
。
在您的代码中,有两种可能的转化,enable_shared_from_this<A>
和enable_shared_from_this<B>
,这是不明确的,因此没有设置weak_ptr
来引用myD
。这意味着如果B
之后的成员函数调用shared_from_this()
,它将获得bad_weak_ptr
例外,因为其enable_shared_from_this<B>
成员从未设置过。