确保抽象低音 class 是 shared_ptr

Ensure abstract bass class is a shared_ptr

我有一个抽象基础class:

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

    void bar() {
        baz(shared_from_this());
    }
};

Base 的唯一有效用例是生活在 shared_ptr - bar 是一个重要的方法。我怎样才能确保以下是不可能的:

struct BadDerived : Base {
    void foo() override { ... }
};

BadDerived bd;
bd.bar(); 

一种技术是将 Base 的构造函数设为私有,将 friend 设为工厂 class 或方法:

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>();
}

用法:

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

这确实需要您重写任何现有的派生 classes。

的基础上,我们还可以使 Base 可从仅具有私有构造函数的类型构造:

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{});
}

每个 Derived 类型都必须采用一个额外的 PrivateT 类型的构造函数参数,它必须转发...但它仍然能够继承自 Base!

struct Impl : Base {
    Impl(PrivateT pt) : Base(pt) { }
    void foo() override { std::cout << "Hello!" << std::endl; }
};

auto gd = makeDerived<Impl>();
gd->bar();