【发布时间】:2014-05-23 18:33:52
【问题描述】:
当从一个类转换到另一个类时,C++ 编译器如何决定使用哪个类型转换运算符或构造函数?为什么这种行为会在编译器之间发生变化?
编辑:B::operator 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”到“ClassA”的转换
file2.cc:123:45 错误:调用 'SomeOtherClass::someFunction(ClassB&)' 没有匹配的函数
当我注释掉 ClassB 中的类型转换运算符时,它将不再在 Solaris 上编译,并且所有错误消息都明显指出该运算符丢失。 Linux 上的错误消息没有改变。
根据这个:Conversion constructor vs. conversion operator: precedence,它应该同时查看运算符和构造函数,并且只有在它们同样有用时才抱怨歧义,对吧?
而且根据这个:conversion operator overloading ambiguity, compilers differ,编译器在转换时具有不同的行为可能是因为人们更努力地寻找可以完成转换的不同方式,但奇怪的是 gcc 甚至不会在之后寻找类型转换运算符找不到合适的构造函数。
为什么编译器在 Linux 上不使用 ClassB 的 ClassA 运算符将 ClassB 转换为 ClassA,而在 Solaris 上却这样做?
【问题讨论】:
-
您可能需要澄清
methodOfClassA()是否为 const。 -
methodOfClassA()不是常量。我认为该行的错误来自从 ClassB 到 ClassA 的演员。 -
我很想知道当被调用的方法是
const时会发生什么,因此它所操作的引用也可以是。它可能不会有什么不同,但如果没有别的,值得一看。 -
它不会帮助任何人隐藏一半的错误消息。例如,我只能假设在第一种情况下,编译器还可能提供 ambiguous 替代方案......
-
我会更详细地编辑;我认为消息中唯一重要的部分是它抱怨对构造函数的模棱两可的调用,而它显然应该使用类型转换运算符。
标签: c++ gcc casting compiler-errors