因爲編譯器會盡量的爲全部的警告和錯誤作出解釋。但也所以致使了部分狀況下的過分解析。
書中給的例子是編譯器因爲過分解析,使用了類型轉換運算符的解析代碼,致使隱藏了真正的錯誤。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裏。