【问题标题】:Publicly inherit from base class, privately inherit from derived class基类公开继承,派生类私有继承
【发布时间】:2014-01-06 21:05:22
【问题描述】:

奇怪的继承情况:

class Base
{
public:
  public virtual foo() = 0;
};

class A : public Base
{
public:
  public virtual foo() override;
protected:
  int bar;
};

class B : public A//something like 'public Base, protected A'
{
public:
  public virtual foo() override;
};

基本上,B 可以继承 A 的所有内容,但只能“看到”(并且只能转换为)Base。基本上,我想在 B 中使用 A 的一堆功能,但希望 B 在语义上与 A 不同:

B b;
Base* valid_ptr = &b;//want this to be ok
A* invalid_ptr = &b;//want this to be invalid
A& invalid_ref = b;//want this to be super invalid
A prevent(b);//want this to not be allowed to happen   

【问题讨论】:

  • 有一个而不是一个?只是想到这个......
  • 当您尝试时发生了什么?
  • 也许您可以将A 作为模板参数传递。
  • A 应该继承自 Base 吗?否则override 将阻止代码编译。
  • 私下继承A

标签: c++ inheritance


【解决方案1】:

首先,只有当 A 派生自 Base 时,您的代码才能编译。如果 Base 对所有人都是公开的,并且 A 受到保护,那么唯一的方法就是不要跨 A 将 Base 继承给 B。

由于 A 无法通过 B 看到,因此可以解决方案

class A: public Base 
{ ... };

class B: public Base 
{
   A a;
public:
  ...
};

如果在B 中存在两个Base 实例(一个作为B 的基础,另一个与a 成员一起出现)是不可接受的,另一种方法可以是通过虚拟基础:

class A: 
  public virtual Base 
{ ... };

class B:
  public virtual Base,
  protected A
{ ... };

这将使 A 通过 B 不可见(不能隐式转换为 A),但只有一个 Base 在 A 和 B 之间是共同的。

在所有情况下,共享虚拟基的使用是一个常见的习惯用法,对象通过成员函数优势(所谓的“堆叠平行四边形继承”)或通过任意数量的接口(“菱形对象”)共享部分实现。

OOP 纯粹主义者倾向于不喜欢这些数字,但它们是适当的 C++ 公民(即使在其他受 OOP 启发的经典语言中找不到任何表示,因为缺少多重继承!)

【讨论】:

  • 嗯...很好的答案,由于使用它的开销,我没有考虑虚拟继承。
  • @MadScienceDreams 我不确定你指的是什么,你说的是哪个开销?
  • 它只需要一个指针......和虚拟调用的双重间接(而不是简单)。现代编译器有时会在链接过程中优化 v-tables,因此开销并不像 1990 年代大多数 OOP 书籍倾向于推荐的那样“可怕”。如果您打算使用虚函数,则您处于间接函数调用域中。到时候……充分利用它们!
【解决方案2】:

我认为您正在处理 Composition vs Inheritance 问题。

您可能让 B 从 Base 继承并使用组合技术来利用 A。

否则,对于您列出的问题,您可能会考虑使构造函数无法访问:

class A
{
public:
    A() {};

};

class B : private A
{
public:
    B() {};
};

例如(MSVC2012)

错误 C2243:“类型转换”:存在从“B *”到“A *”的转换,但是 无法访问

【讨论】:

  • 我没有想到过重载的构造函数/强制转换等。这可能会很好地处理强制转换控制。 (虽然工厂的东西对我来说总是很乱,但不确定实际有用对象的构造)
  • 但是 B 和 A 都从 Base 派生呢?这不是要求吗?
  • 如果用户遇到了钻石问题 (en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem),那就另当别论了。在这种情况下,组合可能会有所帮助
猜你喜欢
  • 1970-01-01
  • 2017-04-14
  • 2016-10-08
  • 2012-12-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-19
相关资源
最近更新 更多