简体   繁体   English

确保抽象低音类是shared_ptr

[英]Ensure abstract bass class is a 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 valid use case for Base is to live in a shared_ptr - bar is an important method. 唯一有效的使用情况Base是生活在一个shared_ptr - bar是一个重要的方法。 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: 一种技术是使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>();
}

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: 根据ecatmur的答案 ,我们还可以从仅具有私有构造函数的类型使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{});
}

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 ! 每个“ 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();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM