私有基类和多重继承

时间:2013-03-13 23:34:44

标签: c++

考虑一下:

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,如果这很重要的话。

编辑:不能使用Clang 3.2进行编译:clang 3.2

但它适用于gcc 4.7.2:gcc 4.7.2

3 个答案:

答案 0 :(得分:10)

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

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

答案 1 :(得分:3)

答案是铿锵有力的。但是,根据标准,代码也可能会失败。

如果你看11.2p5它有一个相关的注释(是的,我知道注释是非规范性的):

  

[注意:此类可以是显式的,例如,当使用qualified-id时,   或隐式的,例如,当使用类成员访问运算符(5.2.5)时   (包括添加隐式“this->”的情况)。 如果是一个班级   成员访问运算符和qualified-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可以来自B A!这使得代码格式不正确: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谈到了这个问题。

答案 2 :(得分:-1)

我不确定原因,但我知道:

当您在像这样的菱形图案中使用多重继承时,您将在派生对象D中拥有基类A的多个副本。

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

这被称为Diamon Problem