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 valid use case for Base
is to live in a shared_ptr
- bar
is an important method. How can I ensure that the following is impossible:
struct BadDerived : Base {
void foo() override { ... }
};
BadDerived bd;
bd.bar();
One technique is to make the constructor of Base
private and friend
a factory 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>();
}
Usage:
struct Impl {
void foo(Base* self) { std::cout << "Hello!" << std::endl; }
};
auto gd = makeDerived<Impl>();
gd->bar();
This does require you to rewrite any existing derived classes.
Building off of ecatmur's answer , we could also make Base
constructible from a type that only has 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{});
}
Every Derived
type will have to take an extra constructor argument of type PrivateT
that it will have to forward through... but it will still be able to 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();
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.