explicit 避免对象的隐式转换

    最近项目中出现了隐式类型转换引起的BUG,使用关键字explicit解决了问题。本文使用简化后的例子说明该问题。

    首先,定义一个分数类Fraction,它包含构造函数,将其转化为double类型的成员函数,并且重载了运算符+。

    代码如下(该代码会有编译错误,先思考一下错在哪里)。

#include<iostream>
using namespace std;
class Fraction
{
public:
	Fraction(int numerator, int denominator = 1)
		:m_numerator(numerator), m_denominator(denominator)
	{
	}
	operator double() const
	{
		return (double)m_numerator / m_denominator;
	}
	Fraction operator+(const Fraction &f)
	{
		return Fraction(m_numerator + this->m_numerator, m_denominator + this->m_denominator);
	}
private:
	int m_numerator;        //分子
	int m_denominator;      //分母
};

int main()
{
	Fraction obj(3, 5);
	double sum = obj + 4;
	std::cout << "sum = " << sum << std::endl;   
	return 0;
}

     你想到了吗?没错!是代码具有二义性。出现二义性的代码是main()函数中一行语句:

Fraction sum = f + 4;

      下面我将详细分析二义性的原因。当编译器看到上述代码时,它发现有两种可行的解释:(1)将4隐式转为Fraction(4)(该转换由构造函数实现),然后由于重载了运算符+,两个Fraction对象相加得到的对象Fraction对象,然后转化为double(该转换由函数double()实现);(2)将对象 obj 转换为double(该转换由函数double()实现),然后两个double相加得到一个double。

       编译器在面对代码上述两种可行的解释时,彻底蒙圈,它不知道该选择哪种方法执行,因此向程序员报告二义性的错误,希望将问题交给聪明的程序员来解决。

        面对这样的二义性,程序员该如何解决呢?没错,用explicit修饰构造函数,明确的告诉编译器,不希望将double隐式转换为Fraction类型的对象,第一种道路被封死,编译器只有第二条路可走。

        修改后的构造函数如下,此时程序不再有编译错误。

explicit  Fraction(int numerator, int denominator = 1)
		  :m_numerator(numerator), m_denominator(denominator)
{ 
}

猜你喜欢

转载自blog.csdn.net/liyazhen2011/article/details/86633125