【问题标题】:C++ hiding inherited class?C ++隐藏继承的类?
【发布时间】:2013-12-16 02:54:54
【问题描述】:

我试图从链接它的可执行文件中隐藏在我编写的库的主类头中包含第三方文件。我的意思是:

我编写了一个定义类 A 的库。类 A 继承自类 B(在第三方库中定义)。 示例:

// In A.h
#include “B.h”
class A : public B
{
    A* something(A* val);
}

// In A.cpp
A* A::something(A*val)
{
    // Do something
    return val;
}

B 类的头文件对环境进行了一些更改,这些更改对我的库来说是理想的,但对链接我的库的任何可执行文件都是有害的。有人向我指出不透明指针是一种潜在的解决方案,尽管我不知道如何使用它们来隐藏“B”。

有谁知道隐藏包含 B.h 的方法?对于解决方案,C++11 是可以的,但链接到其他依赖项(如 boost)不是一种选择。

【问题讨论】:

  • 真的需要A继承B吗?
  • @drescherjm 不幸的是。
  • 对于继承,您必须参见B 的定义。您可以通过在您的类 A 中向 B&const B& 提供强制转换运算符并在您的实现中使用 Pimpl 习惯用法来避免这种情况。
  • @RalphTandetzky,这无济于事 - 任何使用 B& 的代码都必须包含 B.h,这又会导致问题。
  • @MarkRansom 我知道,但无论如何都隐藏了包含,并且客户端代码不必包含B.h,即使它可以。以这种方式,至少避免了编译时依赖性。如果B 接口根本不可用,那么公共继承又有什么意义呢?

标签: c++ inheritance c++11 opaque-pointers


【解决方案1】:

在 C++ 世界中隐藏“实现”的一种常用方法是使用 Pimpl/Handle-body/bridge 习惯用法。

不要将您的 A 类公开给 API 的用户,而是有一个句柄类只公开您想要的内容:

在 A.h

class AImpl;  // forward declaration

class A {
private:
  AImpl* impl;

public:
  foo();
  bar();
}

然后将您的实际实现放在另一个文件中:

AImpl.h

#include <B.h>

class AImpl: public B {
private:
public:
  foo();
  bar();
  somethingThatYouDontWantToExpose();
}

【讨论】:

  • 好的,这绝对可以工作,并回答了原来的问题,但看看我的代码,在实施上述建议后,我将有一个孤立的 typedef,它使用“B.h”中的某些东西并声明 typedef就像我想上面的 AImpl 类一样,没有任何信息,似乎不起作用。
【解决方案2】:

使用不透明指针的方法是转发声明你需要使用的类,这样你就不需要include他们的定义。由于您不包括B.h,因此您图书馆的客户不会被他们的定义所污染。

// In A.h
class B;

class A
{
private:
    B* opaque;
};

【讨论】:

  • 但我并没有将 B 声明为 A 的成员。A 必须从 B 继承。由于在这种情况下 B 不是指针,我如何用不透明的指针隐藏它?这似乎不是一个可行的解决方案。我提到它只是因为它是向我建议的,我看不出它会如何解决我的问题。
  • @latreides,如果你真的必须B派生,那么你就别无选择了,你不得不在其定义中包含B.h。但是,如果您可以简单地使用相同的方法,只需在A 中复制B 的每个方法,并让它调用不透明指针来实现。
  • 它是一个复杂的继承,不仅仅是一些成员和方法。具体来说,这是 Boehm 垃圾收集器要求您执行的操作,以便正确收集 A 类的实例。