2013-03-13 101 views
14

考虑:现在私人基类和多重继承

struct A { int x;}; 
struct B : A {}; 
struct C : private A {}; 

,符合市场预期,代码

struct D : C 
{ 
    D() { C::x = 2; } 
}; 

int main() { D d; } 

不会编译:

test2.cc: In constructor ‘D::D()’: 
test2.cc:1:16: error: ‘int A::x’ is inaccessible 
test2.cc:7:12: error: within this context 

现在,如果我做

struct D : B, C 
{ 
    D() { C::x = 2; } 
}; 

int main() { D d; } 

然后错误消失!是不是A::x也应该是无法访问?这里的解释是什么?

我正在使用gcc version 4.7.2 (GCC),linux x86_64,如果这很重要。

编辑:它不锵3.2编译:clang 3.2

但用gcc 4.7.2作用:gcc 4.7.2

+0

编译[有](http://ideone.com/clone/VvWyUW)(尽管同样的编译器)。似乎GCC的错误呢? – 2013-03-13 23:37:44

+1

有趣的是:相同的编译器,不同的结果。无论如何,我无法想象任何东西 – 2013-03-13 23:39:34

+0

g ++ 4.7.2成功地在两个位置编译相同的源代码。 – Aneri 2013-03-13 23:39:51

回答

10

这肯定是一个错误。没有理由继承B类,也应该改变C的成员的可访问性。

甚至没有GCC 4.8.0(测试版)似乎已经解决了这个问题。另一方面,Clang 3.2和ICC 13.0.1,correctly refuse to compile this code

+1

@ValeriAtamaniouk:什么? – 2013-03-14 00:36:22

+2

@ValeriAtamaniouk:我不知道,'C :: x'很清楚,范围是'C'。 – GManNickG 2013-03-14 00:38:17

+0

@GManNickG:你确定吗?这个名字是'A :: x'。它没有命名'C'子对象。如果你想命名'C'子对象的成员,使用'C * p = this; p-> x' – 2013-03-14 00:41:00

-1

我不知道确切原因,但我知道这一点:

,当你在这样一个菱形图案使用多重继承,你将有基类的多个副本中,你得到的对象D.

在你的情况下,对象D有2个成员命名为A :: x,这可能会引起编译器的混淆。

这是被称为Diamon Problem

+0

钻石问题与这个问题有什么关系?他创建一个钻石形状的继承图的唯一场景是第二个,他说工作正常! – 2013-03-14 00:23:48

3

答案是铛是正确的。但是,根据标准,代码也可能会失败。

如果你看看11.2p5它有一个相关的说明(是的,我知道笔记非规范):

[注:这个类可以是明确的,例如,当一个合格的-ID是使用, 或隐式,例如,当使用类成员访问运算符(5.2.5)时 (包括添加了隐含“this->”的情况)。 如果012xx成员访问运算符和合格ID都用于命名成员 (如p->T::m中所示),则命名该成员的类是由 指定的类。qualified-id的嵌套名称说明符即T)。末端注意 ]

这是什么意思音符,是,如果你然后添加到this->C::x = 2;C是类命名的成员和gcc 4.7.2 correctly fails when this is the case

现在的问题是谁是为C::x命名成员的班级? 该naming class由相同11.2p5指定:由类

到成员的接入会受到影响,其中所述构件是 命名。 这个命名类是查找并找到成员名称为 的类。

现在,类成员名称查找在10.2指定,阅读这一切后,我的结论是x是子对象集工会按:

否则,新的S(f,C)是一个查找集,其中共享集 声明和子对象集的联合。

这意味着根据构件查找规则x可以是从BA!这使得代码不良形成:Name lookup can result in an ambiguity, in which case the program is ill-formed. 然而,这种不确定性可以被解析为每10.2p8:

歧义往往可以通过与同级车 名排位赛的名称来解决。

而且从Clang source,我们可以看到这是他们选择这样做:

// If the member was a qualified name and the qualified referred to a 
// specific base subobject type, we'll cast to that intermediate type 
// first and then to the object in which the member is declared. That allows 
// one to resolve ambiguities in, e.g., a diamond-shaped hierarchy such as: 
// 
// class Base { public: int x; }; 
// class Derived1 : public Base { }; 
// class Derived2 : public Base { }; 
// class VeryDerived : public Derived1, public Derived2 { void f(); }; 
// void VeryDerived::f() { 
//  x = 17; // error: ambiguous base subobjects 
//  Derived1::x = 17; // okay, pick the Base subobject of Derived1 
// } 

但是,请注意上述报价的措辞canoften can be resolved。这意味着他们不一定要解决。所以,我认为根据标准,代码应该失败,因为模糊或作为私人成员访问失败。

编辑

有关于can解释一些竞争和是否一个歧义发生在这里。我发现Defect report 39. Conflicting ambiguity rules谈到了这个问题。

+0

我不确定我是否同意你的阅读,你看到10.1 p5的例子吗?似乎很清楚,即使没有“this->”,也不会有任何含糊之处。 (这个案例几乎与问题中引用的和你的回答完全一样。) – 2013-03-15 00:20:15

+0

@StephenLin:注意'可以使用'的措词。我把它理解为它​​不是强制性的。 – 2013-03-15 00:23:52

+0

我相信这里的“can”这个词意味着,如果qual-id解析为仅有一个该名称的成员的子对象(但可能不是,如果给定的限定id仍然有多个子对象具有相同的成员名称),而不是标准允许判断是否解决它。如果标准在基本的编译时语义问题上真正赋予实现自由裁量权,而不是简单地未指定的运行时行为,我会发现它非常不寻常。 – 2013-03-15 00:23:53