explicit——为毁灭而生的补丁
作者:互联网
构造函数的隐式转换
如果构造函数只有1个参数,则可以用等号隐式地调用构造函数,如下所示
#include <iostream>
using namespace std;
class A
{
public:
/* explicit */ A(int n) : number(n)
{
cout << n << " create" << endl;
}
private:
int number;
};
int main()
{
A a1 = 1;
A a2(1);
return 0;
}
以上,main函数中的2种构造方式是等价的。
另外,对于有多个参数的构造函数,如果除了第1个参数外,其余的参数都提供了默认值,则也可以进行上述隐式转换动作。
禁用构造函数的隐式转换
一般情况下,这种特性并没有带来多大的好处,所以通常是要禁用掉这个隐式转换的特性的。
正如上面注释掉的代码所示,在相应的构造函数前面加上关键字explicit
,即可阻止构造函数的隐式转换。此时,main函数中的第1种构造方式会报错。
转换函数
通过一种特殊的成员函数,可以使某个class具有「隐式地转换为其它类型数据」的能力。
比如如下代码中,operator int()
函数使得class A可以隐式地转换为int类型数据。
#include <iostream>
using namespace std;
class A
{
public:
explicit A(int n) : number(n)
{
cout << n << " create" << endl;
}
/* explicit */ operator int() const
{
return number / 2;
}
private:
int number;
};
int main()
{
A a(10);
cout << a + 2 << endl;
cout << int(a) + 2 << endl;
}
以上,尽管operator int()
的函数声明形式比较诡异(严格来说连返回值的类型都没有标明),但是这个函数是必须要返回int型数据的,并且这个函数是不能有参数的。
另外,也可以把int替换为double、char等其他数据类型。
禁用转换函数的隐式转换
与前面「禁用构造函数的隐式转换」一样,可以在相应的转换函数前面加上关键字explicit
,来阻止相应的隐式转换。此时上述main函数中的第1个cout会报错,第二个cout仍旧可用。
这种隐式转换机制建立的初衷暂时还不知道为什么,不过显然这种特性引起的困惑也不小,所以还是建议禁用掉这种特性。而且,如果确实需要这样一种类型转化功能,最好还是通过成员函数来实现,比如说ConvertToInt
这种。
不只是过度灵活
注意,如下代码是编译不过的,main函数中进行的加法有错误。
#include <iostream>
using namespace std;
class A
{
public:
A(int n) : number(n)
{
cout << n << " create" << endl;
}
operator int() const
{
return number / 2;
}
A operator+(const A &rv) const
{
return A(this->number + rv.number);
}
private:
int number;
};
int main()
{
A a1(10);
A a2 = a1 + 2; /* 错误,有2种加法匹配 */
}
在进行a1 + 2
动作时,编译器认为有2种路径可以选:
1、将a1通过转换函数,隐式地转换成int,然后再与2相加,得到int型的结果后,再通过A的构造函数隐式转换为A类型对象。此时上述加法对应的实际动作为A a2 = A(int(a1) + 2);
2、通过A的构造函数,隐式地将数值2转化为A类型对象,然后调用重载后的加法运算符进行2个A类型对象的加法。此时上述加法对应的实际动作为A a2 = a1 + A(2);
显然这种二义性是不允许的,vscode中的错误提示为:
有多个运算符 “+” 与这些操作数匹配: – 内置运算符 “arithmetic + arithmetic” – 函数 “A::operator+(const A &rv) const” – 操作数类型为: A + int
一些感慨
经过上述讨论,至少我认为「转换函数」是可以彻底封杀掉了,而「构造函数的隐式转换」功能也没有什么存在的意义了,explicit关键字的产生似乎也就是为了在保证向前兼容的前提下,堵住这2个窟窿,扼杀掉一些抖机灵的code技巧,避免了实际工作中在一些犄角旮旯的问题上耗费过多的工时。
我觉得在不久的将来,会有一家公司率先在内部的《C++开发基本规范》中追加对explicit关键字的强制使用,以及对转换函数的禁用。或者直接把这个规则写到代码规范检查的脚本里去。立个flag,拭目以待吧。
Renekton_bhk 发布了2 篇原创文章 · 获赞 0 · 访问量 73 私信 关注标签:转换,函数,int,explicit,补丁,而生,隐式,构造函数 来源: https://blog.csdn.net/Renekton_bhk/article/details/104128186