Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/visual-studio-2008/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 私有基类与多重继承_C++ - Fatal编程技术网

C++ 私有基类与多重继承

C++ 私有基类与多重继承,c++,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: e

考虑:

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版本4.7.2(gcc)
,linux x86_64,如果这很重要的话

编辑:它不使用Clang 3.2进行编译:


但GCC4.7.2确实如此:

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


甚至GCC4.8.0(测试版)似乎都没有解决这个问题。另一方面,Clang 3.2和ICC 13.0.1。

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

在菱形模式中使用多重继承时,派生对象D中会有基类a的多个副本

在您的例子中,对象D有两个名为A::x的成员,这可能会导致编译器的混淆


这被称为

答案是,叮当声是正确的。然而,根据标准,该代码也可能因不明确而失败

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

[注:此类可以是显式的,例如,当使用限定id时, 或隐式,例如,当使用类成员访问运算符(5.2.5)时 (包括添加隐式“this->”的情况)。如果 成员访问运算符和限定id用于命名成员 (如在
p->T::m
)中,命名成员的类是由 限定id的嵌套名称说明符(即T)
-结束说明 ]

这个注释的意思是,如果将
this->
添加到
C::x=2
然后
C
是命名成员和成员的类

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

对成员的访问受成员所在的类的影响 命名的此命名类是成员名称所在的类 查找并找到。

现在,在10.2中指定了类成员的名称查找,在阅读了所有内容后,我得出结论,
x
是子对象集的并集,如下所示:

否则,新的S(f,C)是一个具有 声明和子对象集的并集

这意味着根据成员查找规则,
x
可以来自
B
A
!这使得代码的格式错误为:
Name
查找可能导致歧义,在这种情况下,程序的格式不正确。
但是,这种模糊性可以按照10.2p8解决:

歧义通常可以通过使用名称的类限定名称来解决 名字

从中我们可以看出,这就是他们选择做的:

// 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
//   }
但是,请注意上面引号中的
可以
通常可以解决
。这意味着不一定要解决这些问题。因此,我认为,根据标准,代码应该失败为含糊不清或作为私有成员访问失败

编辑


关于
can
的解释以及此处是否出现歧义,存在一些争议。我发现有人谈论这个问题。

编译(尽管是同一个编译器)。看起来是一个GCC错误吗?有趣的是:相同的编译器,不同的结果。无论如何,除了一个bug,我想不出别的什么了。G++4.7.2在两个位置成功地编译了同一个源代码。复制粘贴错误。对不起,是叮当声。钻石问题与这个问题有什么关系?他创建菱形继承图的唯一场景是第二个,他说这很好@瓦莱里亚塔曼纽克:我不知道,
C::x
非常清楚地涉及到
C
@GManNickG:你确定吗?它命名为A::x
。它不命名
C
子对象。如果要命名
C
子对象的成员,请使用
C*p=this;p->x
@BenVoigt:我不明白:
C::x
应该解析为
C::A::x
,还是我遗漏了什么?GCC似乎将其分解为
B::A::x
,这不会导致sense@BenVoigt我可能误解了您的意思,但我认为
C::x
应该专门指
C
子对象中的
A::x
,不要含糊不清,请参见example@BenVoight10.1 p5(在N3242草案中,C++11之前的最后一个公共草案)“在这样的格中,可以使用显式限定来指定所指的子对象。函数体
C::f
可以引用每个
L
子对象:
void C::f(){A::next=B::next;}
如果没有
A:
B:
限定符,上述
C::f
的定义将由于歧义而格式错误(“此类晶格”指的是基类多次出现的多继承层次结构)我不确定我是否同意您的阅读,您是否看到10.1 p5中的示例?似乎很清楚,即使没有
this->
,也不意味着有任何歧义。(这里的情况与问题和您的答案中引用的情况几乎完全相同。)@StephenLin:请注意,
可以使用
。我认为这意味着它不是强制性的。我相信这里的“can”一词意味着,如果提供了限定id,并且限定id解析为只有该名称的一个成员的子对象,则情况“可以解决”(但如果给定了限定id,仍有多个子对象具有相同的成员名称,则可能不是),这并不意味着标准允许自由裁量是否