c 初始化列表和直接賦值的區別

2021-08-22 19:36:16 字數 2347 閱讀 2052

定義兩個建構函式:

sales_data(const std::string &s): bookno(s) {}
sales_data(const std::string &s, unsigned n, double p):bookno(s), units_sold(n), revenue(p*n)
這兩個定義中,冒號以及冒號和花括號之間的**,其中花括號定義了(空的)函式體。我們把這部分稱為建構函式初始化列表,它負責為新建立的物件的乙個或幾個資料成員賦初值。建構函式初始值是成員名字的乙個列表,每個名字後面緊跟括號括起來(或者在花括號內的)成員初始值。不同成員的初始化通過逗號分隔開來。

含有三個引數的建構函式分別使用它的前兩個引數初始化成員 bookno 和 units_sold, revenue的初始值則通過將售出圖書總數和每本書單價相乘計算得到。

只有乙個 string 型別的引數的建構函式使用這個 string 物件初始化bookno,對於 units_sold 和 revenue 則沒有顯式地初始化。當某個資料成員被建構函式初始值列表忽略時,它將以與合成預設建構函式相同的方式隱式初始化。在此例中,這樣的成員使用類內初始值初始化,因此只接受乙個 string 引數的建構函式等價於

// 與上面定義的那個建構函式效果相同

sales_data (const std::string &s) :

bookno(s), units_sold(0), revenue(0)

通常情況下,建構函式使用類內初始值不失為一種好的選擇,因為只要這樣的初始值存在我們就能確保為成員賦予了乙個正確的值。不過,如果你的編譯器不支援類內初始值,則所有建構函式都應該顯式地初始化每個內建型別的成員。

注意:建構函式不應該輕易覆蓋掉類內的初始值,除非新賦的值與原值不同。如果你不能使用類內初始值,則所有建構函式都應該顯式地初始化每個內建型別地成員。

在上面的兩個建構函式中函式體都是空的。這是因為這些建構函式的唯一目的就是為資料成員賦初值,一旦沒有其他任務需要執行,函式體也就為空了。

當我們定義變數時習慣於立即對其進行初始化,而非先定義、再賦值:

string foo = "hello world!";    // 定義並初始化

string bar; // 預設初始化成空 string 物件

bar = "hello world!"; // 為bar賦乙個新值

就物件的資料成員而言,初始化和賦值也有類似的區別。如果沒有在建構函式的初始值列表中顯式地初始化成員,則該成員將在建構函式體之前執行預設初始化。例如:

// sales_data建構函式的一種寫法,雖然合法但比較草率:沒有使用建構函式初始值

sales_data::sales_data(const string &s,unsigned cnt, double price)

這段**和上面建構函式的原始定義效果是相同的:當建構函式完成後,資料成員的值相同。區別是原來的版本初始化了它的資料成員,而這個版本是對資料成員執行了賦值操作。這一區別到底會有什麼深層次的影響完全依賴於資料成員型別。

建構函式的初始值有時必不可少

有時我們可以忽略資料成員初始化和賦值之間的差異,但並非總能這樣。如果成員是 const 或者是引用的話,必須將其初始化。類似的,當成員屬於某種類型別且該類沒有定義預設建構函式時,也必須將這個成員初始化。例如:

class constref;
和其他常量物件或者引用一樣,成員 ci 和 ri 都必須被初始化。因此,如果我們沒有為它們提供建構函式初始值的話將引發錯誤:

//錯誤:ci 和 ri 必須被初始化

constref::constref(int ii)

隨著構造體函式一開始執行,初始化就完成了。我們初始化 const 或者引用型別的資料成員的唯一機會就是通過建構函式初始值,因此該建構函式的正確形式應該是:

//正確:顯式地初始化引用和const成員

constref::constref(int ii): i(ii), ci(ii), ri(i) {}

建議:

在很多類中,初始化和賦值的區別事關底層效率問題:前者直接初始化資料成員,後者則先初始化再賦值。

除了效率問題外更重要的是,一些資料成員必須被初始化。所以建議養成使用建構函式初始值的習慣,這樣能避免某些意想不到的編譯錯誤,特別是遇到有的類含有需要建構函式初始值的成員時。

初始化列表和賦值的區別

1 區別 賦值 和 初始化 這兩個概念 我們知道普通變數編譯器都會預設的替你初始化。他們既能初始化,也能被賦值的,而常量 const 按照其意思只能被初始化,不能賦值。否則與變數就無區別了。所以常量成員 const member 只能用成員初始化列表來完成他們的 初始化 而不能在建構函式內為他們 賦...

成員初始化列表 初始化同賦值的區別

成員初始化列表 初始化同賦值的區別 1.我們可以認為建構函式的執行過程被分成兩個階段,隱式或顯式初始化階段以及一般的計算階段。計算階段由建構函式體內的所有語句構成,在計算階段中資料成員的設定被認為是賦值而不是初始化。初始化階段可以是顯式的或隱式的,取決於是否存在成員初始化表。隱式初始化階段按照宣告的...

初始化和賦值的區別

區別說明 賦值操作是在兩個已經存在的物件間進行的,而初始化是要建立乙個新的物件,並且其初值 於另乙個已存在的物件。編譯器會區別這兩種情況,賦值 的時候呼叫過載的賦值運算子,初始化的時候呼叫拷貝建構函式。如果類中沒有拷貝建構函式,則編譯器會提供乙個預設的。這個預設的拷貝建構函式只是簡單地復 製類中的每...