这是实现支持继承的pimpl的有效方法吗?


#include <iostream>
#include <memory>
#include <cstdlib>
class IBase
{
public:
    IBase() = default;
    virtual ~IBase() = default;
    virtual void f1() = 0;
};
class IDerived
{
public:
    IDerived() = default;
    virtual ~IDerived() = default;
    virtual void f2() = 0;
};
class BaseImpl : public IBase
{
public:
    BaseImpl() = default;
    virtual ~BaseImpl() override = default;
    virtual void f1() override { /* serious code */}
};
class DerivedImpl : public BaseImpl, public IDerived
{
public:
    DerivedImpl() = default;
    virtual ~DerivedImpl() override = default;
    virtual void f2() override { /* serious code */}
};
class Base : public IBase
{
public:
    Base() : m_impl(std::make_shared<BaseImpl>()) {}
    virtual ~Base() override = default;
    virtual void f1() override { m_impl->f1(); }
protected:
    Base(const std::shared_ptr<BaseImpl>& impl) : m_impl(impl) {}
    std::shared_ptr<BaseImpl> m_impl;
};
class Derived : public Base, public IDerived
{
public:
    Derived() : Base(std::make_shared<DerivedImpl>()) {}
    virtual ~Derived() override = default;
    virtual void f2() override { impl()->f2(); }
private:
    std::shared_ptr<DerivedImpl> impl() { return std::dynamic_pointer_cast<DerivedImpl>(m_impl); }
};
int main()
{
    Base base;
    base.f1();
    Derived derived;
    derived.f1();
    derived.f2();
    std::cin.sync();
    std::cin.get();
    return EXIT_SUCCESS;
}

它是有效的,但是它看起来太奇怪了,我可能会放弃粉刺

想象一下这样定义Base:

class Base {
public:
    Base();
    virtual ~Base();
    virtual void f1();
protected:
    class Impl;
    Impl *p_impl; // or shared_ptr, or unique_ptr, or whatever you like.
};

注意这里没有定义Base::Impl。这是PIMPL习惯用法的一个非常重要的部分,因为您可能不得不在Impl类中使用需要#include的元素-删除您不想包含在头类中的内容。

派生类看起来像这样:

class Derived: public Base {
public:
    Derived();
    ~Derived();
    virtual void f1(); // or not, depends
    virtual void f2();
protected:
    class Impl2;
    Impl2 *p_impl2; // note that Derived::Impl2 might inherit from Base::Impl
};

这仍然隐藏了Base::ImplDerived::Impl2BaseDerived的实现细节,同时给您以任何您喜欢的方式(包括继承)实现Derived的完全自由。

您的Impl类应该只包含私有变量和方法。

不要把任何需要从子类访问的东西放在那里。在c++中,将Impl类子类化是错误的,因为这违背了此模式的目的。

最新更新