建構函式再探

2022-06-21 14:54:14 字數 2957 閱讀 8644

建構函式基礎知識

建構函式初始值列表

初始化與賦值

建構函式使用初始值列表還是在函式體中給資料賦值的區別在於,前者是初始化了它的資料成員,後者是對資料成員執行了賦值操作。

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

除了效率外更重要的是,一些資料成員必須被初始化。如果成員是const、引用,或者屬於某種未提供預設建構函式的類型別,我們必須通過建構函式初始值列表為這些成員提供初始值。

成員初始化的順序

一般來說,初始化的順序沒什麼特別要求。

最好令建構函式初始值列表的順序與成員宣告的順序保持一致。而且如果可能的話,盡量避免使用某些成員初始化其他成員。

預設實參與建構函式

如果乙個建構函式為所有引數都提供了預設實參,則它實際上也定義了預設建構函式。

委託建構函式

乙個委託建構函式使用它所屬類的其他建構函式執行它自己的初始化過程,或者說它把它自己的一些(或者全部)職責委託給了其他建構函式。

和其他建構函式一樣,乙個委託建構函式也有乙個成員初始值列表和乙個函式體。在委託建構函式內,成員初始值列表只有乙個唯一的入口,就是類名本身。

預設建構函式的作用

當物件被預設初始化或值初始化時自動執行預設建構函式。

預設初始化:

當我們在塊作用域中不適用任何初始值定義乙個非靜態變數或陣列時;

當乙個類本身含有類型別的成員且使用合成的預設建構函式時;

當類型別的成員沒有建構函式初始值列表中顯示初始化時。

在實際中,如果定義了乙個其他建構函式,那麼最好也提供乙個預設建構函式。

值初始化:

在陣列初始化的過程中如果我們提供的初始值數量少於陣列的大小時;

當我們不使用初始值定義乙個區域性靜態變數時;

當我們通過書寫形如t( )的表示式顯示地請求值初始化時,其中t是型別名。

類必須包含乙個預設建構函式以便在上述情況下使用,其中的大多數情況非常容易判斷。

在實際中,如果定義了其他建構函式,那麼最好也提供乙個預設建構函式。

隱式的類型別轉換

我們能為類定義隱式轉換規則。如果建構函式只接受乙個實參,則它實際上定義了轉換為此類型別的隱式轉換機制,有時我們把這種建構函式稱作轉換建構函式。

只允許一步類型別轉換

編譯器只會自動地執行一步型別轉換。

類型別轉換不總是有效

有這樣一種情況:建構函式只接受乙個實參,實際上,我們構建了乙個物件,先將它的值加到呼叫他的物件中,隨後將其丟棄。

抑制建構函式定義的隱式轉換

在要求隱式轉換的程式上下文中,我們可以通過將建構函式宣告為explicit加以阻止。

只能在類內宣告建構函式時使用explicit關鍵字,在類外部定義時不應重複。

explicit建構函式只能用於直接初始化

發生隱式轉換的一種情況是當我們執行拷貝形式的初始化時(使用=)。此時,我們只能使用直接初始化而不能使用explicit建構函式。

為轉換顯示的使用建構函式

儘管編譯器不會將explicit的建構函式用於隱式轉換過程,但是我們可以使用這樣的建構函式顯示地強制進行轉換:

item.combine(sales_data(null_book));

標準庫中含有顯式建構函式的類

接受乙個單引數的const char*的string建構函式不是explicit的。

接受乙個容量引數的vector建構函式是explicit的。

聚合類

聚合類使得使用者可以直接訪問其成員,並且具有特殊的初始化語法形式。

當乙個類滿足如下條件時,我們說它是聚合的:

●所有成員都是public的。

●沒有定義任何建構函式。

●沒有類內初始值。

●沒有基類,也沒有virtual函式。

我們可以提供乙個花括號括起來的成員初始值列表,並用它初始化聚合類的資料成員。初始值的順序必須與宣告的順序一致。

與初始化陣列元素的規則一樣,如果初始值列表中的元素個數少於類的成員數量,則靠後的成員被值初始化。初始值列表的元素個數絕對不能超過類的成員數量。

值得注意的是,顯式地初始化類的物件的成員存在三個明顯的缺點:

●要求類的所有成員都是public的。將正確初始化每個物件的每個成員的重任交給了類的使用者(而非類的作者)。因為使用者很容易忘掉某個初始值,或者提供乙個不恰當的初始值,所以這樣的初始化過程冗長乏味且容易出錯。

●新增或刪除乙個成員之後,所有的初始化語句都需要更新。

字面值常量類

constexpr函式的引數和返回值必須是字面值型別。除了算術型別、引用和指標外,某些類也是字面值型別。

資料成員都是字面值型別的聚合類是字面值常量類。

如果乙個類不是聚合類,但它符合下述要求,則它也是乙個字面值常量類:

●資料成員都必須是字面值型別。

●類必須至少含有乙個constexpr建構函式。

●如果乙個資料成員含有類內初始值,則內建型別成員的初始值必須是一條常量表示式;或者如果成員屬於某種類型別,則初始值必須使用成員自己的constexpr建構函式。

●類必須使用析構函式的預設定義,該成員負責銷毀類的物件。

constexpr建構函式

儘管建構函式不能是const的,但是字面值常量類的建構函式可以是constexpr函式。事實上,乙個字面值常量類必須至少提供乙個constexpr建構函式。

constexpr建構函式可以宣告為=default的形式或是刪除函式的形式。否則,他能擁有的唯一可執行的語句就是返回語句。一般來說constexpr建構函式體應該是空的。

constexpr建構函式必須初始化所有資料成員,初始值或者使用constexpr建構函式,或者是一條常量表示式。

constexpr建構函式用於生成constexpr物件以及constexpr函式的引數或返回型別。

7 5 建構函式再探

目錄7.5.2 委託建構函式 7.5.3 隱式的類型別轉換 7.5.4 類的靜態成員 觀察下面兩段建構函式的 初始化bookno,units sold,revenue sale data const string s,unsigned cnt,double price bookno s units ...

C primer 7 5 建構函式再探

這兩個函式從執行的結果上看沒有區別,但是 第乙個函式執行的過程相當於 string foo abc 定義並初始化第二個函式執行的過程相當於 string foo foo abc 先定義 再賦值,且在定義時會執行預設初始化 第乙個過程明顯優於第二個 如果沒有在建構函式的初始值列表中顯式地初始化成員,則...

足跡C primer 19 建構函式再探

sales data sales data const string s,unsigned cnt,double price 這個建構函式和這個效果是一樣的 sales data const std string s,unsigned n,double p bookno s units sold n...