什么是多重继承?

Cod*_*cks 14 c++ inheritance multiple-inheritance diamond-problem

我将以下内容称为"多重继承":

  • 通过继承一个或多个后代,直接继承一次类,间接继承一次或多次
  • 通过继承两个或多个后代来间接继承一个类两次或更多次

我想知道它是否存在以及如何明确地访问嵌入的子对象.

1.)[ 专业C++,2 编] 中指明了编译程序不能有直接继承其两个直接父类和所述父的父类.这是真的吗?

鉴于a GrandParentParent,扩展GrandParent,VC12和g ++允许a GrandChild直接从两者ParentGrandParent.继承.在VC12和g ++中,可以按如下方式定义这些类:

GrandParent声明一个int num数据成员.除继承之外,Parent声明自己的.除了继承's和s 之外,它还声明了它自己.numGrandParentnumGrandChildnumParentGrandParentnum

VC12似乎允许明确的成员访问,但g ++只允许它在某些情况下.

#include <iostream>
using std::cout;
using std::endl;

struct GrandParent { int num; };
struct Parent : GrandParent { int num; };
struct GrandChild : GrandParent, Parent { int num; };

int main()
{
    GrandChild gc;
    gc.num = 2;
    gc.Parent::num = 1;
    gc.Parent::GrandParent::num = 0; // g++ error: ‘GrandParent’ is an ambiguous base of ‘GrandChild’
    gc.GrandParent::num = 5;         // g++ error: ‘GrandParent’ is an ambiguous base of ‘GrandChild’

                                                 // --VC12 output; g++ output--
    cout << gc.num << endl;                      // 2 ; 2
    cout << gc.Parent::num << endl;              // 1 ; 1
    cout << gc.Parent::GrandParent::num << endl; // 0 ; N/A due to above error
    cout << gc.GrandParent::num << endl;         // 5 ; N/A due to above error
}
Run Code Online (Sandbox Code Playgroud)

2.)为什么(a)gc.Parent::GrandParent::numg ++中的含糊不清楚(b)gc.Parent::num不是?(a)唯一地描述它在继承树上的位置.gc只有1 Parent个子对象,只有1 个子对象,只有1 GrandParent个子对象num.对于(b),gc有一个Parent,它有自己的,num但也有一个GrandParent子对象与另一个num.

3.)因为gc.GrandParent::num,VC12看起来是后者的gc直接GrandParent基础子对象num.我猜这是明确的原因是,它是由合格的名称查找gc,所以实体的右边.是寻找第一次gc的范围,最直接的GrandParentgc的范围是直接继承的,不是间接地继承了一个Parent.我错了吗?

4.)为什么不是gc.GrandParent::numg ++时gc.Parent::num不明确 ?如果一个人含糊不清,那么两者是否应该同样含糊不清?对于先前,gc有两个GrandParent; 对于后者,Parent有2 num秒.


Gregoire,Marc R.等.专业的C++,2 编辑.印第安纳波利斯,印第安纳州:Wiley Pubishing,2011年.241.打印.

Pot*_*ter 3

对此的通用术语是菱形图案(或菱形问题)。

这本身并不是一个错误,但正如此处的注释中所指出的,任何访问在层次结构中其他地方重复的直接基数的尝试都会导致歧义错误。

一种解决方法是使基数间接。C++11 中新的继承构造函数功能允许完美的包装器:

template< typename base, typename tag >
struct disambiguated_base : base
    { using base::base; };
Run Code Online (Sandbox Code Playgroud)

给定未使用的标记类型,这会生成一个从给定基派生且功能相同的新类。标签类型可能是由详细类型说明符表示的不完整类:

struct GrandChild : Parent,
    disambiguated_base< GrandParent, class grandchild_grandparent_tag > {

    typedef disambiguated_base< GrandParent, grandchild_grandparent_tag >
        my_direct_grandparent;

    int num;
};
Run Code Online (Sandbox Code Playgroud)

现在GrandChild可以用来my_direct_grandparent::消除成员访问的歧义。