【发布时间】:2013-12-19 23:43:33
【问题描述】:
我将以下称为“多重再继承”:
- 直接继承一个类一次,并通过继承其一个或多个后代间接继承一次或多次
- 通过继承一个类的两个或多个后代来间接继承一个类两次或多次
我想知道它是否存在以及如何明确地访问嵌入的子对象。
1.) [Professional C++, 2nd ed.]† 声明可编译程序不能有直接继承的类它的直接父级和所述父级的父类。是真的吗?
给定一个扩展GrandParent 的GrandParent 和Parent,VC12 和g++ 允许GrandChild 直接从Parent 和GrandParent 继承。在 VC12 和 g++ 中,可以这样定义这些类:
GrandParent 声明了一个 int num 数据成员。 Parent 除了继承GrandParent 的num 之外,还声明了自己的num。 GrandChild 除了继承Parent 和GrandParent 的nums 之外,还声明了自己的num。
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
}
2.) 为什么 (a) gc.Parent::GrandParent::num 在 g++ 中是模棱两可的,而 (b) gc.Parent::num 不是? (a) 唯一地描述了它在继承树上的位置。 gc 只有 1 个 Parent 子对象,它只有 1 个 GrandParent 子对象,它只有 1 个 num。对于 (b),gc 有一个 Parent,它有自己的 num,还有一个 GrandParent 子对象和另一个 num。
3.) 对于gc.GrandParent::num,VC12 似乎在查看gc 的直接GrandParent 基子对象以获取后者的num。我猜它是明确的原因是它是由gc 限定的名称查找,因此. 右侧的实体首先在gc 的范围内查找,最直接的GrandParent到gc 的作用域是直接继承的,不是通过Parent 间接继承的。我错了吗?
4.) 为什么 gc.GrandParent::num 对 g++ 模棱两可,而 gc.Parent::num 不是?如果一个是模棱两可的,那么两者不应该同样模棱两可吗?对于先前,gc 有两个GrandParents;对于后者,Parent 有 2 个nums。
†Gregoire、Marc R. 等人。 专业 C++,第 2nd 版。印第安纳波利斯:威利出版社,2011 年。 241. 打印。
【问题讨论】:
-
"[Professional C++, 2nd ed.]† 指出可编译程序不能有一个类直接继承其直接父类和所述父类的父类。是真的吗?" 不,那是错误的。 C++ 标准甚至包含一个示例并在其中声明它是格式良好的,请参阅 [class.mi]/3
class D : public A, public L { void f(); /∗ ... ∗/ }; // well-formed,其中class A : public L { /∗ ... ∗/ }; -
在同一段中,注释说:“一个类可以多次作为间接基类,并且可以是直接基类和间接基类。这样可以做的事情有限一个类。不能在派生类的范围内引用直接基类的非静态数据成员和成员函数。”(强调我的)。
-
我认为这些访问不明确的原因是
GrandChild::Parent::GrandParent在名称查找方面等同于GrandChild::GrandParent。同样,struct A { int x; }; struct B : A {}; struct C : A {}; struct D : B, C {}; D d; d.B::A::x = 42;失败。 -
“如何明确地访问嵌入的子对象”你可以通过类似
static_cast<Parent&>(gc).GrandParent::num = 42; -
+1 有趣的问题。添加到编译器组合中,Apple LLVM 版本 5.0 (clang-500.2.79)(基于 LLVM 3.3svn)报告与 gcc 相同的歧义错误。
标签: c++ inheritance multiple-inheritance diamond-problem