回答了继承过程中同名的问题。我编写了以下代码(见下文)。Visual C++ 编译它并运行它。但许多其他编译器发誓
d.C::A::x = 2;
d.B::A::x = 3;
和挑战out()
,认为选择存在模糊性A::x
。坦白说,我不这么认为;VC++ 的输出符合预期。
有人可以通过明确引用标准的条款来证明这个或那个编译器的正确性吗?B
当明确指出通过or 的路径时,歧义从何而来C
?如何在这样的编译器中消除它,谁不满意?
#include <iostream>
using namespace std;
struct A
{
int x;
void out() { cout << x << endl; }
};
struct B: public A
{
int x;
void out() { cout << x << endl; }
};
struct C: public A
{
int x;
void out() { cout << x << endl; }
};
struct D: public B, public C
{
int x;
void out() { cout << x << endl; }
};
int main()
{
D d;
d.C::x = 0;
d.B::x = 1;
d.C::A::x = 2; // неоднозначность в не-MSVC
d.B::A::x = 3; // неоднозначность в не-MSVC
d.B::A::out(); // неоднозначность в не-MSVC
d.C::A::out(); // неоднозначность в не-MSVC
d.B::out();
d.C::out();
}
当你写的时候
B::A
(不管它后面是什么- 它在任何地方都一样) - 它与简单的(if - 继承人).
是一样的,所以它变成- 这显然是一个歧义和错误。A
B
A
d.C::A::x
d.A::x
为什么
B::A
和 一样A
?因为注入类名。Injected-class-name 类似于一个隐藏的名称
using ИмяКласса = ИмяКласса;
,它在每个类中自动创建,并以与所有其他类成员相同的方式继承。也就是说,
B
它继承自A
类似的东西using A = A;
,所以B::A
它的意思是A
。(它也应该遵循它
A::A
的含义A
,但这并不是在任何地方都有效:它struct B : A::A {};
有效,但A::A a;
不再有效 - 因为[class.qual]/1
(在第二种情况下,编译器认为A::A
它是构造函数的名称A
- 就像继承时一样)构造函数 -using A::A;
)。它如何按照与其他地方相同的规则
::
获得工作权?毕竟, (where is a non-static member).
似乎只能在!之后才起作用。A::x
x
.
但不,
A::x
对于非静态成员它在很多地方都有效。只要不计算表达式的结果,例如在sizeof
and中decltype
:这个怎么样:
::
一般来说,该标准不会在任何地方专门描述右侧的行为。.
它在任何地方的工作方式都是相同的。即没有“始终进入父母的父母”的过程;您能够在 in 之后指定多个父级的唯一原因d.C::A::x
是注入的类名。他清楚地谈到你的案件说
[expr.ref]/7
:这里,“命名类”是点左边的对象类型。
还有另一种访问父字段的方法 - 将对象转换为对父字段的引用:
或者像这样: