Make sure the abstract bass class is shared_ptr

I have an abstract base class:

struct Base : std::enable_shared_from_this<Base> { virtual ~Base() = default; virtual void foo() = 0; void bar() { baz(shared_from_this()); } }; 

The only legal use case for Base is to live in shared_ptr - bar is an important method. How can I guarantee that the following is not possible:

 struct BadDerived : Base { void foo() override { ... } }; BadDerived bd; bd.bar(); 
+8
c ++ c ++ 11 shared-ptr
source share
2 answers

One of the methods is to create the constructor of Base private and friend a factory of a class or method:

 struct Base : std::enable_shared_from_this<Base> { virtual ~Base() = default; virtual void foo() = 0; void bar() { baz(shared_from_this()); } private: template<class Impl> friend std::shared_ptr<Base> makeDerived(); Base() {} }; template<class Impl> std::shared_ptr<Base> makeDerived() { struct Derived : Base, Impl { void foo() override { Impl::foo(static_cast<Base*>(this)); } }; return std::make_shared<Derived>(); } 

Using:

 struct Impl { void foo(Base* self) { std::cout << "Hello!" << std::endl; } }; auto gd = makeDerived<Impl>(); gd->bar(); 

This requires that you rewrite all existing derived classes.

+5
source share

Based on ecatmur's answer, we could make the Base construct constructive from a type that has only a private constructor:

 class PrivateT { PrivateT() { } template <typename Impl, typename... Args> friend std::shared_ptr<Impl> makeDerived(Args&&... ); }; struct Base : std::enable_shared_from_this<Base> { Base(PrivateT ) { } virtual void foo() = 0; void bar() { baz(shared_from_this()); } }; template <typename Impl, typename... Args> std::shared_ptr<Impl> makeDerived(Args&&... args) { return std::make_shared<Impl>(std::forward<Args>(args)..., PrivateT{}); } 

Each type of Derived will have to take an additional argument from a constructor of type PrivateT , which it will have to forward ... but it can still inherit from Base !

 struct Impl : Base { Impl(PrivateT pt) : Base(pt) { } void foo() override { std::cout << "Hello!" << std::endl; } }; auto gd = makeDerived<Impl>(); gd->bar(); 
0
source share

All Articles