调用过载操作员时出现歧义
Ambigulty while calling overloaded operator
以下是示例代码:
struct A
{
virtual int operator & ( A & ) { return 0; }
};
struct B : public A {};
struct C : public A {};
struct D : public C, public B {};
int main()
{
D d;
std::cout << &d << std::endl;
return 0;
}
它在VS2008中完美工作,但GCC未能编译它:
../src/TestCast.cpp: In function ‘int main()’:
../src/TestCast.cpp:26:16: error: request for member ‘operator&’ is ambiguous
../src/TestCast.cpp:15:14: error: candidates are: virtual int A::operator&(A&)
../src/TestCast.cpp:15:14: error: virtual int A::operator&(A&)
make: *** [src/TestCast.o] Error 1
就我所见,它在寻找运营商&按名称重载,而不是按签名重载,因此它会发现不明确的重载并产生错误。
问题是:标准是否正确?如果没有,哪一段描述它?有没有什么方法可以让GCC接受这个代码(我的意思是,通过签名查找,而不是通过名称查找)。
顺便说一句,我知道,如何修复这个代码。我只想知道,为什么会出现错误。
您造成的是一个钻石继承问题,您可以通过虚拟继承来解决它。
在A中,您已经声明了虚拟operator&
,它也在B
和C
中定义。现在,这两种方法都是在D
中定义的,因为您正在使用多重继承。
来自标准(10.1多个基类)。
一个类不应多次被指定为派生类的直接基类。[注意:一个类可以是一个间接基类多次,并且可以是直接基类和间接基类。有有限的用这样一个类可以做的事情。直接的非静态数据成员和成员函数基类不能在派生类的作用域中引用。但是,静态成员、枚举和类型可以明确地引用。--尾注][示例:
和
不包含关键字virtual的基类指定器指定非虚拟基类。基地类指定器包含关键字virtual,指定一个虚拟基类。对于每个不同的事件对于最派生类的类格中的非虚拟基类,最派生对象(1.8)应包含该类型的相应的不同基类子对象。对于每个不同的基类指定的虚拟对象,派生最多的对象应包含该类型的单个基类子对象。[示例:对于类类型C的对象,(非虚拟)基类L在的类格中的每次不同出现C与类型C的对象中的一个不同的L子对象一一对应。给定定义的类C如上所述,类C的对象将具有两个类L的子对象,如下所示。
L L
| |
A B
/
C
图3——非虚拟基础5在这种格中,可以使用显式定性来指定所指的子对象。函数体C: :f可以引用每个L子对象旁边的成员:void C::f(){A::next=B::next;}//形式良好如果没有A::或B::限定符,上述C::f的定义将因歧义而不正确(10.2)。
我在Standard中发现了什么:
3.4名称查找[基本查找]
1名称查找规则统一适用于所有名称(包括typedef名称(7.1.3)、命名空间名称(7.3)和类名(9.1)),只要语法允许在特定规则讨论的上下文中使用这些名称。名称查找将名称的使用与该名称的声明(3.1)相关联名称查找应为名称找到一个明确的声明(见10.2)。如果名称查找发现名称是函数名称,则可以将多个声明与名称关联;据说这些声明形成了一组重载函数(13.1)。重载解析(13.3)发生在名称查找成功之后只有在名称查找和函数重载解析(如果适用)成功后,才会考虑访问规则(第11条)。只有在名称查找、函数重载解析(如果适用)和访问检查成功之后,名称声明引入的属性才会在表达式处理中进一步使用(第5条)。
此代码所实现的内容称为diamond-inheritance
问题。简单解释一下,在编译过程中,编译器发现operator &
不明确,因为它无法判断是调用B类继承版本还是C类继承版本。
要克服这一点,请将类定义声明为
struct B : virtual public A {};
这使得D类中只有一个可用的函数副本。
- 构造对象的歧义
- <<操作员在下面的行中工作
- 我知道函数调用中存在歧义.有没有办法调用foo()函数
- C++ 与操作员不匹配<<
- 操作员C++的模棱两可的过载
- C++中>>操作员过载时出现问题?
- NaN 上的宇宙飞船操作员
- 数组初始值设定项的构造函数歧义
- 消除好友和成员二进制运算符的歧义
- 用' . '代替' :: '会在C++中造成歧义吗?
- 为什么下面带有非常量转换函数的代码没有歧义?
- 比根<操作员
- SFINAE不能防止模棱两可的操作员过载吗?
- 什么是现实中的"endl"(或任何输出操纵器)?它是如何实现的,它如何与操作员<<一起工
- std::bind 是否实现了 std::ref 和 std::cref 来消除函数调用的歧义?
- 为什么"delete"操作员给我访问权限冲突
- 如何避免操作员[](const char*)`歧义
- 如何解决嵌入结构内嵌入的操作员中的歧义
- C :操作员过载:课堂上和班级.歧义前操作员的模棱两可
- 调用过载操作员时出现歧义