因为编译器会尽量的为全部的警告和错误作出解释。但也所以致使了部分状况下的过分解析。
书中给的例子是编译器因为过分解析,使用了类型转换运算符的解析代码,致使隐藏了真正的错误。html
cin << intval; int temp = cin.operator int(); temp << intval;
分析一下:ios
要注意因为隐式转换可能形成的不良后果。程序员
隐式类型转换虽然会"暗地里"作一些转换操做,但这种机制的好处也是显而易见的。并且C++为了让这个"暗地里"的隐式操做可以被程序员察觉显形,提供了一个修饰符"explicit",类型转换构造函数和类型转换函数声明前加上explicit关键字将阻止编译器隐式类型转换操做。任未尝试隐式转换的操做都会报错。
以下:函数
#include<iostream> using namespace std; class A { public: //explicit A(int a):m_a(a) { cout << "construct A from int" << endl; } //explicit operator int() { cout <<"convert A to int " << end; return m_a; } public: int m_a; }; int main(void) { A a(5);//显式类型转换构造 A b = 5;//隐式类型转换构造 int i = a;//隐式类型转换函数 return 0; }
讨论trivial和notirvial其实就是讨论构造函数存在的必要性。构造本质上要为对象的生成作一些辅助操做。
但若是对象生成的需求仅仅是分配空间就够了,那么构造函数其实也没有什么意义。
构造函数确实不是必须的,甚至于某些状况下,编译器连系统默认构造函数都不会提供
。
好比有一个类就像C中结构体的同样,struct A* pa = new (sizeof(struct A));就足够,即不须要初始化成员变量,也不须要负责成员变量的构造,更不须要初始化虚函数表,或者虚基类表。那么编译器也没有必要提供一个默认构造画蛇添足了。优化
综合来看,做者想要说明的是:在基类或者类成员没有自定义构造函数时默认构造函数的做用,在如下几种条件下会体现即:spa
看做者总结的四种状况(没有自定义构造函数的状况下):指针
public class B { B(){} }; class A { class B b; };
public class B { B(){} }; class A:public class B { };
class A { virtual fun(){} };
class A : virtual public class B { };
类须要执行拷贝构造的三种情形code
注意:拷贝构造的本质是仍是构造,本质操做是初始化操做,而非拷贝操做。
拷贝构造一样被分红了trivial和notirvial,是trivial仍是notrivial和默认构造解释差很少。先理解下几个名词。htm
bitwise copy是编译器默认提供的位拷贝,即memcpy系列,以bit为单位。加个semantics(语意)引伸意义后面讲。
memberwise init即基本类型成员的赋值,以成员为单位。对象
bitwise copy semantics:位拷贝语意,即一个类的拷贝构造过程当中的初始化操做应该是固定且连续的memwise init,不能被安插子对象或者类类型的成员变量的拷贝构造(尽管子对象或者类类型的成员变量内部也是递归mmwise init的),另外也不能因为存在虚函数或者虚基类增长拷贝构造操做而在该类的拷贝构造中额外增长虚表指针或者虚基类表指针的重定位操做。
换句话说:bitwise copy semantics上只能有 POD数据类型C++ POD(Plain Old Data)类型
某些状况下对象不能有bitwise copy semantics,不然拷贝构造会出现问题。即上述的几个不能。
如下四种状况不该该表现出bitwise copy semantics,默认构造必须是notrivial的
前两种,基类子对象或者类类型成员的拷贝构造必须被当前对象的拷贝构造调用。默认拷贝构造必须是notrivial。
类存在虚函数表vtbl时或者继承自虚基类时,须要重定虚表指针,默认拷贝构造必须是notirvial的。
也就是默认拷贝构造必需要有才行。
最终要回归trivial和notrivial,不要陷在bitwise copy semanstics里。