一个隐式类型转换引起的重载函数二义性错误

介绍因为隐式类型转换而引起的一个非常隐晦的错误

下述代码的目的是设计一个简单的类A,希望A的对象在标准输出和文件输出时的表现不同

#include <iostream>
#include <fstream>
using namespace std;
class A
{
public:    
	int a, b;    
	A(int n1 = 0, int n2 = 0): a(n1),b(n2) {}  // 加上explicit,阻止隐式转换,则代码没问题;
};
istream& operator>>(istream& in, A& a)
{  
	in >> a.a >> a.b;
	return in;
}
ostream& operator<<(ostream& out, const A& a)
{   
	out << a.a << " " << a.b << endl;
	return out;
}
ofstream& operator<<(ofstream& fout, const A& a)
{    
	fout << a.a << "xxx" << a.b << endl;    // 如果注释掉这一句,则可以通过编译,说明问题出在这一句  
	return fout;
}
void main()
{ 
	A a;   
	cin >> a;   
	cout << a;   
	ofstream ff("output.txt"); 
	ff << a;
}
乍一看,这段代码不会有什么问题,但实际上其中隐藏了一个错误,会导致不能通过编译,分析如下:

        代码段中有语句 fout << a.a,我们相当然以为这段代码实际会调用ostream& operator<<(ostream &, int)函数,这个失误导致了上述错误代码的编写

        实际上这句代码还可以与ofstream& operator<<(ofstream& fout, const A& a)匹配,因为fout是ofstream类型对象,a.a是int类型对象但是却可以隐式转换为类型A的一个临时对象参与函数调用

选择最佳匹配函数的规则如下:

1.最佳匹配函数的每个实参的匹配都不劣于其它可行函数需要的匹配

2.最佳匹配函数至少有一个实参的匹配优于其他可行函数需要的匹配

         基于上述规则,编译器无法在两个候选匹配函数中找出最佳匹配的那个,所以会导致编译出现二义性错误


解决方法:

我们的解决办法肯定是要控制int类型对象隐式转换为类型A的一个临时对象参与函数调用

办法一:将A的构造函数声明为explicit,防止在隐式转换的上下文中使用构造函数

办法二:将函数ofstream& operator<<(ofstream& fout, const A& a)声明改为ofstream& operator<<(ofstream& fout, A& a),防止这个函数的第二个参数由int隐式转换成A的临时对象

注:非const的引用参数只能是相同类型,加上const才能接受"右值(right value)"引用


总结:重载函数时要注意由隐式类型转换引起的非常难以辨识出来的二义性错误

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值