概述
看到一篇文章,对于用explicit关键字限定构造函数的作用,说的简单明了,记录一下。
Why You Should Always Use explicit Constructors
C++的重载规则允许通过单参数构造函数将一个类型转换为另一个类型,编译器对于这种情况一般不会警告,因此可能会出现隐晦的错误。而关键字explicit关键字可以控制这种错误的发生。
例子
class A {};
class B {
public:
B() {}
B(A const&) {}
};
void f(B const&) {}
int main() {
A obj;
f(obj);
return 0;
}
上述代码中,有两个简单的类A、B,其中B有一个接受A对象的单参数构造函数。在调用函数f时,程序默默调用了B类的单参数构造函数,构造了一个临时的B对象作为f函数的参数。其main函数过程等同于下面的代码:
int main() {
A obj;
{
B obj_arg0(obj);
f(obj_arg0);
}
return 0;
}
在这个例子中,构造了一个临时变量B似乎没有太大影响,但是如果B类的那个单参数构造函数相当耗费资源,或者f函数从他的参数(即B对象)中存储了数据,这种情况应该是不应该发生的。因为B类的这个临时对象在调用完函数f后就会被销毁,而f函数从这个对象中存储的数据则是无效的了。
解决办法
解决办法就是explicit关键字。修改代码如下(在单参数构造函数前添加explicit关键字)。
class A {};
class B {
public:
B() {}
explicit B(A const&) {}
};
void f(B const&) {}
int main() {
A obj;
f(obj);
return 0;
}
此时编译则会报错:
编译器无法为我们自动调用B对象的单参数构造函数创建临时对象,因为explicit关键字的限制。而如果确实想要这样做,则需要手动调用这个构造函数。修改main函数为:
int main() {
A obj;
f(B(obj));
return 0;
}
此时编译就可以通过,程序正常执行。这样可以避免并非我们意愿的构造导致的潜在bug。
需要注意的是,带默认参数的多参数构造函数同样适用这种情况:
class A {};
class B {
public:
B() {}
explicit B(A const&) {}
};
class C {
public:
C() {}
C(B const&, A const& a = A()) {}
};
void f(B const&) {}
void f1(C const&) {}
int main() {
B obj;
f1(obj);
return 0;
}
对于上述代码的编译,编译器同样也没有任何的报错或者警告,程序调用了C类的第二个构造函数。因此需要把C类修改为:
class C {
public:
C() {}
explicit C(B const&, A const& a = A()) {}
};
以避免潜在的错误。
最后
以上就是无辜烧鹅为你收集整理的为什么要用explicit指定构造函数的全部内容,希望文章能够帮你解决为什么要用explicit指定构造函数所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复