我有2个非常简单的类,ClassA和ClassB。我希望能够从ClassB转换为ClassA。使用Sun C ++ 5.11,它可以很好地编译并按照我的预期运行,根据这个:Conversion constructor vs. conversion operator: precedence。
当我尝试使用gcc版本4.8.2编译它时,它给出了一个关于对重载函数的模糊调用的错误。当铸造似乎是一个相当明确的行为时,为什么这会表现不同?
守则:
main.cc
#include <iostream>
class ClassB;
class ClassA
{
public:
ClassA( const int& num )
: _number( num )
{ std::cout << "ClassA int constructor\n"; }
private:
int _number;
};
class ClassB
{
public:
ClassB( const int& num )
: _number( num )
{ std::cout << "ClassB int constructor\n"; }
operator ClassA() const throw()
{
std::cout << "ClassB operator ClassA()\n";
return ClassA( _number );
}
operator int() const throw()
{
std::cout << "ClassB operator int()\n";
return _number;
}
private:
int _number;
};
int main( int argc, const char* argv[] )
{
std::cout << "Creating b:\n";
ClassB b( 5 );
std::cout << "Casting b to a ClassA:\n";
ClassA a = static_cast<ClassA>( b );
}
使用Sun C ++ 5.11,它可以很好地编译并吐出以下输出:
Creating b:
ClassB int constructor
Casting b to a ClassA:
ClassB operator ClassA()
ClassA int constructor
使用gcc,编译器会发出以下错误:
main.cc: In function 'int main(int, const char**)':
main.cc:43:36: error: call of overloaded 'ClassA(ClassB&)' is ambiguous
ClassA a = static_cast<ClassA>( b );
^
main.cc:43:36: note: candidates are:
main.cc:8:2: note: ClassA::ClassA(const int&)
ClassA( const int& num )
^
main.cc:5:7: note: ClassA::ClassA(const ClassA&)
class ClassA
如果我注释掉ClassB :: operator int()或ClassA :: ClassA(const int&amp;),它会编译好并提供相同的输出。如果我注释掉ClassB :: operator CLassA(),我得到以下输出:
Creating b:
ClassB int constructor
Casting b to a ClassA:
ClassB operator int()
ClassA int constructor
为什么gcc认为这两个转换序列是等价的:
ClassB :: operator ClassA()
ClassB :: operator int() - &gt; ClassA :: ClassA(const int&amp;)
答案 0 :(得分:4)
如果您的编译器支持C ++ 11功能,您可以明确声明转换运算符:
class ClassB
{
public:
explicit ClassB( const int& num );
explicit operator ClassA() const throw();
explicit operator int() const throw();
explicit operator float() const throw();
int getNumber() const;
private:
int _number;
}
因此,编译器不会因为模糊调用而在重载决策中感到困惑
由于隐式转化,static_cast<>
必须选择。
答案 1 :(得分:1)
这应该有效:
int main( int argc, const char* argv[] )
{
std::cout << "Creating b:\n";
ClassB b( 5 );
std::cout << "Casting b to a ClassA:\n";
ClassA a = b.operator ClassA();
}
这里发生的事情是static_cast
在您的各种转换运算符之间混淆了。它试图从ClassA到ClassB,但由于C ++允许在函数调用中进行一次隐式转换,并且有多个可能的转换路径(ClassB要浮动到ClassA,ClassB要转换为int到ClassA,ClassB直接转换为ClassA),编译器会抱怨关于歧义。 (好吧,在你编辑浮动路径之前......)
直接调用所需的转换运算符可以解决歧义,因为不再存在任何潜在的隐式转换。
编辑:下面的两个答案(在转换运算符上使用explicit
)也很好地删除了模糊路径,同时仍允许直接转换。这可能是你想要的方式。