【问题标题】:C++ Inheritance in the Pimpl idiomPimpl 习语中的 C++ 继承
【发布时间】:2017-03-25 19:39:21
【问题描述】:

假设我有一个class B 和一个继承自Bclass A : public B。我要暴露A的方法,调用B中的一些方法。

现在我想在 pimpl 成语中公开这些方法 - 我真的不知道该怎么做:

  • AB 是否都获得单独的实现类 B::implA::impl : public B::impl 以便实现相互继承?然后常规类不会继承:class Aclass B?

    我意识到这是不可能的,因为实现是 private

  • 实现不会继承 B::implA::impl,但公开的类会继承 class Bclass A : public B。但是A::impl中的方法如何能够调用B::impl中父级的方法呢?

  • 通过参数中的指针 - 请参见下面的示例。

谢谢

编辑:这是一个示例代码 sn-p - 这是正确的吗?

test.hpp

#include <iostream>

class B {
private:
    class impl;
    std::unique_ptr<impl> pimpl;

public:
    B();
    ~B();
    B(B&&) = default; 
    B(const B&) = delete;
    B& operator=(B&&);
    B& operator=(const B&) = delete;

    void my_func() const;
};

class A : public B {
private:
    class impl;
    std::unique_ptr<impl> pimpl;

public:

    A();
    ~A();
    A(A&&) = default; 
    A(const A&) = delete;
    A& operator=(A&&);
    A& operator=(const A&) = delete;

    void access_my_func();
};

test.cpp

#include "test.hpp"

// Implementation of B
class B::impl
{
public:
    impl() {};

    void impl_my_func() { 
        std::cout << "impl_my_func" << std::endl;
        return; 
    };
};

// Constructor/Destructor of B
B::B() : pimpl{std::make_unique<impl>()} {};
B::~B() = default;
B& B::operator=(B&&) = default;

// Exposed method of B
void B::my_func() const {
    std::cout << "B::my_func" << std::endl;
    pimpl->impl_my_func();
    return; 
};


// Implementation of A
class A::impl
{
public:
    impl() {};

    void impl_access_my_func(const A& a_in) {
        std::cout << "impl_access_my_func" << std::endl;
        a_in.my_func();
        return;
    };
};

// Constructor/Destructor of A
A::A() : pimpl{std::make_unique<impl>()} {};
A::~A() = default;
A& A::operator=(A&&) = default;

// Exposed method of A
void A::access_my_func() {
    std::cout << "A::access_my_func" << std::endl;
    pimpl->impl_access_my_func(*this);
    return;
};




// Later in the main.cpp file
int main() {

    // Make an object
    A my_A_object;
    my_A_object.access_my_func();

    return 0;
};

【问题讨论】:

  • Consider 如果 pimpl 真的是您的用例的正确习惯用法。纯虚拟基类可能是一种语法开销较小的替代方案,尤其是在涉及继承时。
  • 谢谢!我没有想过这个。这个项目的最终目标是一个 API,所以我读到 pimpl 是隐藏实现细节并确保未来更改后向后兼容的流行方法。我不确定纯虚拟基类是否可以用于相同目的。
  • 可以这样使用,见this question的第一个例子。不过,ABI 兼容性可能存在问题。见评论this answer

标签: c++ inheritance pimpl-idiom


【解决方案1】:

如果你从 B 继承 A,A 应该能够调用 B 类的接口。它不应该依赖于它的实现。

Pimpl-Ideom 只是一种处理 C++ 限制的方法,您不能拆分类的私有、受保护和公共部分的声明。由于您不想将类的私有部分公开给类用户,也不希望将受保护部分公开给不想子类化的用户,因此 Pimpl-Ideom 将这些部分从头文件中移开。

回答你的问题:

  • A 类必须是 B 的子类,这就是 OOP 的意义所在。
  • A::impl 类不需要依赖 B::impl 来完成其工作。
  • 如果你想走极端,你可以设想一个 B::protected_impl,它可以是 A::impl 的子类。为此,您必须使用 protected_impl 声明创建一个单独的标头,以便 A::impl 可以使用它。

【讨论】:

  • 谢谢!这些观点都有道理。但是class A::impl 怎么才能完成它的工作呢?如果它需要从其父级调用一个方法,是传递一个指向该对象的指针的唯一方法吗(参见示例void impl_access_my_func(const A&amp; a_in))?
猜你喜欢
  • 2010-10-04
  • 2011-09-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-11
  • 2018-12-27
  • 1970-01-01
相关资源
最近更新 更多