其他分享
首页 > 其他分享> > explicit——为毁灭而生的补丁

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