类中具有相同变量名的多重继承
Multiple inheritance with the same variable name in the classes
我意外地遇到了在多重继承中使用的类中具有相同名称的成员变量的问题。我的基本想法是,成员变量是简单的"合并",即发生多重声明。编译器甚至没有告诉我一个警告,请参阅下面的MWE。我知道变量同名是个坏主意,所以我认为用我的方式称呼它们至少是模棱两可的;所以我预计至少会有一个警告或错误。
1) 为什么编译器不写至少一个警告?
2) 如何在内部解决这些变量的处理?(我猜像HW::I和Other::I这样的别名被使用了,但它们与SW1::I、SW2::I的关系如何?)
#include <iostream>
struct Other { int I;};
struct HW { int I;};
struct SW1 : Other, HW { int I;};
struct SW2 : HW, Other { int I;};
struct D : SW1 { };
struct E : SW2 { };
int main()
{
E* e = new E;
D* d = new D;
e->I = 3;
SW1* pc1 = dynamic_cast<SW1*>(d);
pc1->I = 2;
std::cerr << d->I;
std::cerr << e->I;
SW2* pc2 = dynamic_cast<SW2*>(e);
pc2->I = 1;
std::cerr << d->I;
std::cerr << e->I;
}
为什么编译器至少不写一个警告?
因为你没有写任何错误、危险或模棱两可的东西。你或我可能会感到困惑,但编译器有一组特定的查找规则来处理它
当您编写像e->I
这样的类成员访问表达式时,编译器不仅会查找名称I
,还会查找包含以这种方式命名的成员和成员的子对象。它还从最派生的对象类型开始,在基类子对象上"查找",直到找到一些东西(简而言之,这也是隐藏在C++中的成员名称的工作方式)。
所以对于e->I
,它在E
中查找I
。该搜索一无所获,因此进入基类主题。它找到SW2::I
,一个引用SW2
中定义的唯一成员的名称。所以它停止了。
如果没有SW2::I
,它将继续查找并找到Other::I
和HW::I
。现在,在两个不同的基类子对象中发现了相同的名称,我们得到了一个歧义。不是对歧义的警告,而是直截了当地使表达式e->I
歧义,这是一个错误。
编译器不诊断代码中的任何问题是正确的。正如您构建的代码一样,它并不含糊。从本质上讲,如果一个名称与多个变量(或者在您的情况下是类成员)同样匹配,那么它就是不明确的。
当评估e->I
时,找到的第一个候选是I
,它是类SW2
的成员(通过继承)。SW2
从其基类继承的I
的成员不如Sw2
直接定义的成员匹配。
类似地,pc1->I
明确地是SW1
的成员,d->I
是相同的,并且pc2->I
明确地是基类SW2
的成员。
如果SW2
没有自己的名为I
的成员(即struct SW2: HW, Other {};
),则在评估e->I
时会出现歧义(.在这种情况下,在评估e->I
时,名称解析会在SW2
中查找名为I
的成员,但没有找到它。然后解析名称会考虑两个基类HW
和Other
,这两个基类都有一个名为I
的成员。它们同样匹配,因此表达式e->I
不明确,编译器会发出诊断,即错误(不仅仅是警告)。在这种情况下,程序员可以使用scope(::
)运算符显式地解决歧义。例如,完全限定名称的e->HW::I
或e->Other::I
。
你说得对,在类层次结构中多次使用一个名称是个坏主意。这既是因为很难以对编译器有意义的方式正确解决歧义,也是因为普通人通常难以遵循逻辑。
变量没有合并,您只需同时获得所有3个变量。您需要将指针强制转换为正确的类型才能访问所需的变量。
#include <iostream>
struct Other { int I; };
struct HW { int I; };
struct SW1 : public Other, public HW { int I; };
struct D : public SW1 { };
int main() {
D* d = new D;
d->I = 1;
SW1* pc1 = dynamic_cast<SW1*>(d);
pc1->I = 2;
static_cast<Other*>(pc1)->I = 3;
static_cast<HW*>(pc1)->I = 4;
std::cerr << d->I;
std::cerr << static_cast<Other*>(d)->I;
std::cerr << static_cast<HW*>(d)->I;
}
打印:
234
也就是说,同一个对象d
包含3个不同版本的I
,这取决于您如何查看它
- 你能重载对象变量名本身返回的内容吗
- 在C/C++中将变量名定义为__00000001有什么好处吗
- 关于C++中具有多重继承"this"指针的说明
- C++变量名(可以将 main 声明为变量,但对于其他函数名称则不然)
- C++中模板化异常类的多重继承
- C++ - 声明中变量名后面的括号
- 虚拟继承中是否存在多重继承?
- 如何在 c++ 多重继承中调用父非虚函数?
- 如何使替换 c 函数的变量名成为错误?
- 多重继承相同的方法名,没有歧义
- 是否可以创建没有变量名的变量
- fstream库,试图创建一个变量名为(c++)的文件
- 使用enable_if解决多重继承歧义
- 多重继承导致虚假的模糊虚拟函数过载
- 类中具有相同变量名的多重继承
- 在同级之间继承相同的变量名
- 多重继承C++-BaseA从派生类访问BaseB变量
- C 多重继承,虚拟方法覆盖问题和协变量返回类型
- 继承受保护的函数和公共变量C++时发生多重继承编译错误
- 一个c++问题,涉及多重继承、模板和静态变量