确保抽象低音类是shared_ptr

时间:2015-04-16 19:05:41

标签: c++ c++11 shared-ptr

我有一个抽象的基类:

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

2 个答案:

答案 0 :(得分:5)

一种技巧是使Base私有和friend的构造函数成为工厂类或方法:

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

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

答案 1 :(得分:0)

建立ecatmur's answer,我们也可以从只有私有构造函数的类型构造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();