explicit C++
来源:互联网 发布:微博有mac版 编辑:程序博客网 时间:2024/05/20 02:21
一个只带一个参数,且为非explicit的构造函数,充当两个角色(http://baike.baidu.com/view/2422253.htm)。一是一个构造器;二是隐式类型转换器,即把构造函数的参数类型对象隐式转换为该类对象。如果把构造函数声明为explicit,那么就会屏蔽第二个作用。
例如:
class Complex{private: double real; double imag; public: Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) {} bool operator == (Complex rhs) { return (real == rhs.real && imag == rhs.imag)? true : false; }}; int main(){ Complex com1(3.0, 0.0); if (com1 == 3.0) cout << "Same"; else cout << "Not Same"; return 0;}输出:same
因为构造函数的参数有默认值,所以可以看作是只有一个参数。那么就存在一个隐式的转换,在必要的时候把double类型的数据转换为Complex类型的对象。所以 if(com1 == 3.0)会隐式地调用构造函数把3.0转换成一个Complex对象,假设该匿名对象为c,那么c是由Complex(double=0.0,double=0.0)构造出来的,所以c=(3.0,0.0)。
如果在构造函数前加上explicit关键字,那么3.0就不能够隐式地转换为Complex对象。当然,可以进行显示类型转换,如下的代码是正确的,且输出也为same
class Complex{private: double real; double imag; public: explicit Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) {} bool operator == (Complex rhs) { return (real == rhs.real && imag == rhs.imag)? true : false; }}; int main(){ Complex com1(3.0, 0.0); if (com1 == (Complex)3.0) cout << "Same"; else cout << "Not Same"; return 0;}问题1:为什么上面的 bool operator==(Complex rhs) 换成 bool operator==(Complex& rhs),就编译通不过,上面两个都通不过?
问题1的解释是:隐式转换得到的对象是一个右值,不能被改变。C++规定,当参数为引用传递时,non-const可以传递给const,const不能传递给non-const。上述问题就是因为隐式转换得到的对象为const,而形参为non-const,所以出错。其实改成 bool operator==(const Complex& rhs); 就没问题(已验证)。
还有下面问题
class A{public:A(int i = 0){ data = i;}A(const A& a){ data = a.data + 1;}int data;};A a(A(1));
A a = A(1);
问题2:上面两个语句并没有调用拷贝构造函数,a.data仍然是1,为什么?
问题2可能是因为,编译器作了一些优化,只执行了第一个构造函数。见 http://zh.wikipedia.org/wiki/%E8%A4%87%E8%A3%BD%E5%BB%BA%E6%A7%8B%E5%AD%90
虽然没有执行拷贝构造函数,但是重载时还是不能写成A(A& a)。如下代码中A a1(A(1));依然是错的,必须把拷贝构造函数定义成 A(const A& a);
class A{public:A(int i = 0){ data = i;}A(A& a){ cout << "A(const A& a)" << endl;}int data;};void f(const A& a){}int main(){<span style="white-space:pre"></span>A a1(A(1));// 当A(int)与A(const A&)为non-explicit时,等价于 A a1 = A(1); 或 A a1 = 1;cout << a1.data << endl; <span style="white-space:pre"></span>return 0;}问题3:为什么当拷贝构造函数为explicit时,A a = a1;编译通不过?如下代码编译通不过
问题3可能的解释为:explicit构造函数不仅禁止类型的默认转换,还禁隐式地调用该构造函数。http://www.tuicool.com/articles/2ANrQbj
问题3代码延伸,下面代码编译通过,且输出为 A(const A& a)
class A{public:A(int i){ data = i;}A(const A& a){ cout << "A(const A& a)" << endl;}explicit A(A& a){ cout << "explicit A(A& a)" << endl;}int data;};int main(){A a1 = 1;A a2 = a1; return 0;}
那么综上可以做这样的总结:
每一个单参数的non-explicit构造函数,都定义了一个隐式转换,把构造函数参数类型的数据转换成该类对象。当构造函数被声明为explicit时,该构造函数不能参与到隐式转换中去,同时也不支持隐式调用该构造函数。
explicit构造函数的作用就是抑制隐式转换与隐式调用,隐式调用主要是问题3中的情况
explicit构造函数可以参与显示转换,比如强制转换:(type)value,static_cast等等
Q:什么情况下构造函数要声明为explict,什么情况下不需要?
A:把构造函数声明为explicit主要是为了防止隐式转换,这样会降低代码的可阅读性。比如上面的Complex,如果构造函数未声明为explicit,这样的语句Complex c = 3.0则会编译通过,但是很难被程序员理解,不知道3.0到底是real还是image。一般情况下,转换构造函数要声明为explicit,当然,有些情况下,转换构造函数不能声明为explicit。比如在list与deque中,const_iterator应该可以由iterator构造的,因为下面的这个语句从需求上来说应该被接受const_iterator cit = begin();begin()返回的是一个iterator,那么在构造cit时就会调用const_iterator(const iterator& it)把begin()转换成一个const_iterator,然后再调用拷贝构造函数。如果该转换构造函数被声明为explicit,则上面的语句就会编译出错,用户就会觉得很奇怪。
- C++, explicit
- c++-explicit
- [C++]explicit解释
- [C++]explicit解释
- [C++]explicit解释
- C++:explicit 关键字
- C++explicit关键字
- 【C++】explicit关键字
- explicit构造函数(C++)
- C++explicit关键字
- 【C++】explicit构造函数
- 【C++】explicit关键字
- C++explicit的用法
- 【C++】explicit关键字
- [C++]explicit构造函数
- C++explicit的使用
- c/c++ explicit
- 【C++】explicit关键字
- hdu4539 郑厂长系列故事——排兵布阵 + POJ1158 炮兵阵地
- cocos2dx编译android时,libs\armeabi下的第三方库会删掉
- Unit 2: Reading The Parts of Speech
- poj 1269
- wikioi 1001 舒适的路线
- explicit C++
- 【无限互联】瀑布流CHTCollectionViewWaterfallLayout
- C 四舍五入取整(实验二)
- 分析java中的类(static)变量和类(static)方法
- yii2 - 增加actions
- NOUNS
- Unit 2: Pronouns
- yii2 关于construct 和init函数
- 适配器模式(PHP实现)