⓪著作 :蕭沖


傳統C語言裡若要初始物件(結構體struct),需使用{ }陣列初始的方法來初始之。但已經不合用於cpp中的class型別,初始化的方式已有所不同。c中使用bitwise copy,一個byte一個byte的copy值。但class中有constructor,並非是簡單的bit copy就可以的。此外,C的其他型別都是用 = 號來初始值。在cpp中擴展了初始化的方法,即用()來做。如: ClassType obj(data); 為了和C的包伏問題,也可以使用 ClassType obj = data來代表同一件事。當然,當建構子的參數超過一個以上你就只能ClassType obj(data1, data2, data3);

cpp裡還有一個功能,允許operator被overloading。於是 = 號則也可能被overloading。造成了某些觀念上會有誤解。比如說:
Foo rhs;
String obj = rhs // statement A
String obj; obj = rhs ; // statments B
A 與 B 這二種寫法是一樣的嗎?

「通常」是一樣的結果,但根子裡是不一樣的。
第二種的寫法compile是先用default constructor先創出一個String物件。然後再使用String裡的 = operator 複載(overload)來做物件copy。值得注意的是當用 = copy時,左右二邊的型別決定了是否可copy。

第一種則單純依overloading 的constuction的型別媒合而create一次!


問題通常會發生在一個物件它的建構子的所有overloading型別與它自己 = operator 的overloading的型別不全然一樣!
實例說明: 以以BCB中Variant這個類別來說
它的reference construction overloading裡有 short*, int*.........
它的 = operator 則是 Variant& __fastcall operator =(const Variant& rhs);
也就是說它接等號右邊可以是 Variant&,說明檔裡更指出如下:
If the Variants can be converted to types that make sense for the given operation, the assignment is performed
好了,實驗一下:
Variant vv =cat->get_ActiveConnection(); // wrong! no such constructor match
Variant vv;
vv = cat->get_ActiveConnection(); //using Variant::operator= overload is match,ok!
結論:
1/ ClassType obj = rhs 與 ClassType obj(rhs) 是等價的! 但用cpp style ( ) 在bcb中會在design time 出現有錯誤,但不用理會。
2/ ClassType objA; objA = rhs ; 這二行就不一定等於上面1說講的一樣。
3/ 我建議使用cpp style 來初始建構,這樣比較不會被 = 號給搞亂了。因為 = 時而是用建構子,時而又是表達二個物件copy。
4/ 是否要分二行陳述則要依情形來看。以剛我講的例子就需要二行。若是一般情形則用一行就可以。而我個人又強力的建議使用cpp的( ) 建構型態!
5/ 一行的效能一定比二行好,所以不要全都使用二行的方式!!
創作者介紹
創作者 aftcast 的頭像
aftcast

蕭沖的書房

aftcast 發表在 痞客邦 留言(1) 人氣()


留言列表 (1)

發表留言
  • hi
  • 意見

    結論1有問題,當"單一引數建構子"被以 explicit 修飾即將出問題; 前者是編譯器隱式呼叫建構子, 後者是編譯器顯式呼叫, 這狀況亦發生在 copy constructor!

    結論2更明確來說就是:
    objA.operaotr=(rhs)
    的簡寫形式.

    結論3:C++ 的物件生成初始通常用顯式方式初始, 原因在於當傳入引數超過 1 個仍可適用, 但是為了相容於 C 的變數初始風格, 亦允許作等號的初始方式,但此種方式被 C++視為隱式呼叫"單一引數建構子", 再呼叫複製建構子進行物件的複製, 其過程猶如傳統數值的右值型態先轉型成左值的型態再進行複製!

    結論4:分一行扯到的過程是"單一引數建構子" 與"複製建構子" 被喚起;
    分兩行扯到的是"預設建構子" 與 "指派運算子" 的喚起.

    結論5:這無法比較, 因為 2 個寫法扯到的建構子或運算子都沒有重複!

    通常編譯器對於形式一的
    "單一引數建構子" 再 呼叫 "複製建構子時", 會直接省略複製建構子的呼叫, 因為有無呼叫都不影響其物件初始的結果!