C++关键字:explicit与构造函数
C++关键字explicit常常用来放在接受一个实参的构造函数(non-explicit-one-argument-constructor)前,以防止编译器在某些条件下的默认行为——调用该构造函数来实现类型转换。当声明一个构造函数为explicit时,表示这个构造函数只能通过用户显示调用来创建对象。
首先谈谈explicit常常使用的地方:non-explicit-one-argument-constructor——非显式接收一个实参的构造函数。
class Fraction
{
public:
Fraction(int num, int den=1):m_numerator(num), m_denominator(den)//接收两个参数,分子和分母,分母的默认值为1
{
cout<<"call constructor"<<" num: "<< num<< " den: "<< den <<endl;
}
~Fraction()
{}
Fraction operator+ (const Fraction& f)
{
int den = this->m_denominator * f.m_denominator;//通分
int num = this->m_numerator * f.m_denominator + f.m_numerator * this->m_denominator;
return Fraction(num, den);
}
private:
int m_numerator; //分子
int m_denominator; //分母
};
上面这段代码定义了一个描述分数的类Fraction
,该类含有两个数据成员m_numerator,m_denominator
分别表示分子和分母。Fraction
类的构造函数接受两个参数分别代表分子和分母,其中分母有默认值1(这是合理的,比如整数4可以写成分数4/1)。这个构造函数虽然有两个参数,但是真正调用这个构造函数只需要给出第一个参数,而第二个参数使用默认值即可,这种在调用时只需要传递一个参数的构造函数叫做non-explicit-one-argument-constructor,下面看看在有这种构造函数时,编译器使用该构造函数进行类型转换的默认行为
主函数:
int main()
{
Fraction f(3, 5);
Fraction f2 = f + 4;
return 0;
}
主函数中第二行Fraction f2 = f + 4;
调用Fraction
重载的+运算符,+运算符接收的右操作数类型为Fraction
,实际语句中的数为整数4,这时编译器为了让该语句通过编译,会将4作为实参,调用上面定义的non-explicit-one-argument-constructor:Fraction(int num, int den=1)
,调用完毕之后,4被转换为Fraction
类,所以加法操作能够顺利执行了。如下:
main
中创建分数3/5
第一次调用构造函数,当执行加法时,编译器自动调用构造函数将4转换为Fraction
,最后在重载运算符+内,显示调用构造函数创建对象并返回。
有时候这种编译器“好心”的转换并不是我们想要的。
如果不需要这种默认转换功能则只需要在构造函数前加入explicit关键字即可。
explicit Fraction(int num, int den=1):m_numerator(num), m_denominator(den)//接收两个参数,分子和分母,分母的默认值为1
{
cout<<"call constructor"<<" num: "<< num<< " den: "<< den <<endl;
}
这时再执行main函数,语句Fraction f2 = f + 4;
则会报如下的错误error: no match for 'operator+' (operand types are 'Fraction' and 'int')
4不能转换成Fraction
,从而因为没有定义Fraction + int
的方法报错。
编译器不会帮我们进行自动类型转换,而想让该语句通过只能显式调用构造函数将4转化为Fraction。Fraction f2 = f + Fraction(4);
以上就是explicit最常用来使用的地方了,就是在只接受一个实参的构造函数前加入explicit关键字,表示该构造函数只是构造函数,编译器不再自动使用构造函数进行类型转换,除非显示调用。