如果您想实现一个shared_from_this()
函数,@evoskuil 的类似解决方案可以减少派生类中的样板,从而在类中的使用点产生以下代码:
auto shared_from_this() {
return shared_from(this);
}
这使用了类之外的“shim”函数。通过这样做,它还为那些接口不能修改但派生自的类提供了一种干净的方法enable_shared_from_this
- 例如
auto shared_that = shared_from(that);
注意:auto
此处使用 for 返回类型取决于编译器的年龄。
可以放置在库头文件中的 Shim 函数:
template <typename Base>
inline std::shared_ptr<Base>
shared_from_base(std::enable_shared_from_this<Base>* base)
{
return base->shared_from_this();
}
template <typename Base>
inline std::shared_ptr<const Base>
shared_from_base(std::enable_shared_from_this<Base> const* base)
{
return base->shared_from_this();
}
template <typename That>
inline std::shared_ptr<That>
shared_from(That* that)
{
return std::static_pointer_cast<That>(shared_from_base(that));
}
上面的代码依赖于这样一个事实,即传递给的类型shared_from(...)
继承自std::enable_shared_from_this<Base>
其祖先的某个点。
调用shared_from_base
将找出最终是什么类型。由于我们知道That
继承自Base
,因此可以进行静态向下转换。
可能存在一些带有类型转换运算符的类的病态极端情况。但这不太可能发生在并非旨在打破这种情况的代码中。
例子:
struct base : public std::enable_shared_from_this<base> {};
struct derived : public base
{
auto shared_from_this() {
return shared_from(this);
}
// Can also provide a version for const:
auto shared_from_this() const {
return shared_from(this);
}
// Note that it is also possible to use shared_from(...) from
// outside the class, e.g.
// auto sp = shared_from(that);
};
template <typename X>
struct derived_x : public derived
{
auto shared_from_this() {
return shared_from(this);
}
};
编译测试:
int main()
{
auto pbase = std::make_shared<base>();
auto pderived = std::make_shared<derived>();
auto pderived_x = std::make_shared<derived_x<int> >();
auto const& const_pderived = *pderived;
const_pderived.shared_from_this();
std::shared_ptr<base> test1 = pbase->shared_from_this();
std::shared_ptr<derived> test2 = pderived->shared_from_this();
std::shared_ptr<derived_x<int> > test3 = pderived_x->shared_from_this();
return 0;
}
https://onlinegdb.com/SJWM5CYIG
我发布的先前解决方案一直使评论仍然有意义 - 这将函数放置在有一些问题的基类中 - 特别是“普通”类和模板类所需的实现之间的不一致性。
此外,对于新的类层次结构,需要重复基类中的实现,这并不是那么干燥。此外,通过提供来自不同对象的基类指针,基类函数存在被滥用的可能性。上面的较新方案完全避免了这种情况,并且运行时 assert(...) 检查进行。
旧实现:
#include <cassert>
#include <memory>
class base : public std::enable_shared_from_this<base>
{
protected:
template <typename T>
std::shared_ptr<T> shared_from(T* derived) {
assert(this == derived);
return std::static_pointer_cast<T>(shared_from_this());
}
};
class derived : public base
{
public:
auto shared_from_this() {
return shared_from(this);
}
};
template <typename X>
class derived_x : public derived
{
public:
auto shared_from_this() {
return this->template shared_from(this);
}
};
int main()
{
auto pbase = std::make_shared<base>();
auto pderived = std::make_shared<derived>();
auto pderived_x = std::make_shared<derived_x<int> >();
std::shared_ptr<base> test1 = pbase->shared_from_this();
std::shared_ptr<derived> test2 = pderived->shared_from_this();
std::shared_ptr<derived_x<int> > test3 = pderived_x->shared_from_this();
return 0;
}