C ++编译器如何决定从一个类转换到另一个类时要使用哪个类型转换运算符或构造函数?为什么这种行为会从编译器变为编译器?
编辑:B ::运算符ClassA()应该是公共的,固定的。
EDIT2:经过进一步调查,我认为我取得了一些进展:
第一个示例代码的完整错误消息如下:
file1.cc:123:45 error: call of overloaded 'ClassA(ClassB&)' is ambiguous
someFunction( ( (ClassA) cbObject ).methodOfClassA() )
file1.cc:123:45 notes: candidates are:
In file included from ...:
/path/to/file/class_a.hh:123:4: note: ClassA::ClassA( some_type )
/path/to/file/class_a.hh:133:4: note: ClassA::ClassA( some_other_type )
重要的是,ClassB还为some_type和some_other_type提供了类型转换运算符。如果我为some_type注释掉类型转换运算符,则编译器不再将其列为ClassA(ClassB&)调用的候选者。
这意味着编译器正在使用ClassB的运算符将ClassB转换为某种中间类型,然后使用该类型调用ClassA的构造函数,而不是使用ClassB的运算符ClassA()。我现在还不确定为什么......
EDIT2结束
我试图将一些为Solaris编写的代码移植到Linux上。它在Solaris上编译并运行良好,但我在Linux上遇到了一些编译器错误。
Solaris编译器:CC:Sun C ++ 5.11
Linux编译器:gcc版本4.8.2
以下是相关代码:
class_a.hh
class ClassA
{
public:
// Several constructors, none of which take a ClassB
ClassA( some_type source )
...
ClassA( some_other_type source )
...
}
class_b.hh
class ClassB
{
public:
// constructors and such
...
virtual operator ClassA() const throw();
...
}
class_b.cc
ClassB::operator ClassA() const throw()
{
ClassA newClassA;
// logic to initialize classA with classB's data
return newClassA;
}
使用这些类的代码中充斥着从ClassB到ClassA的强制转换。一些例子:
ClassB cbObject;
// cbObject is initialized with data somehow
someFunction( ( (ClassA) cbObject ).methodOfClassA() )
或将ClassB传递给带有ClassA
的函数int someOtherFunction( ClassA caObject )
{
...
}
...
ClassB cbObject;
// cbObject initialized with data somehow
int someNumber = someOtherFunction( cbObject );
再一次,在Solaris上,这一切都编译并运行良好,并做了预期的事情。但是,在Linux上我遇到如下错误:
对于第一个示例代码,我收到此错误:
file1.cc:123:45错误:调用过载' ClassA(ClassB&)'含糊不清
对于第二个,我明白了:
file2.hh:234:56注意:没有已知的转换参数1来自' ClassB'到'A级'
file2.cc:123:45错误:没有匹配的函数用于调用' SomeOtherClass :: someFunction(ClassB&)'
当我在ClassB中注释掉类型转换运算符时,它将不再在Solaris上编译,并且错误消息都明显指向此运算符丢失。 Linux上的错误消息没有改变。
根据这个:Conversion constructor vs. conversion operator: precedence,它应该同时考虑运算符和构造函数,并且只有在它们同样有用时才会抱怨歧义,对吧? 而且根据这个:conversion operator overloading ambiguity, compilers differ,编译时有不同行为的编译器可能是因为一个人更难以找到不同的方式来完成演员表,但是奇怪的是gcc甚至不会寻找类型转换找不到合适的构造函数后的运算符。
为什么编译器使用ClassB的ClassA运算符在Linux上从ClassB转换为ClassA,而在Solaris上呢?
答案 0 :(得分:1)
转换会创建一个临时对象;临时数不能绑定到非const
左值引用。 (这似乎不适用于您的“示例”代码,但错误消息也不完全匹配示例,因此很难判断这是否是原因)。
有许多流行的编译器会出错并允许不正确的代码。
此外,还会对转换运算符执行辅助功能检查。在您的示例中,B::operator ClassA()
是私有的。但是,这应该在错误消息中提及。