C++類的特殊成員函數(shù)(1):構(gòu)造函數(shù)


我們先從一個簡單的類開始

class Sales_item {
public:
    Sales_item(const std::string &book)
        : isbn(book), 
        units_sold(0), 
        revenue(0.0) {}
    virtual ~Sales_item() {};
private:
    std::string isbn;
    unsigned units_sold;
    double revenue;
};

1 構(gòu)造函數(shù)

Sales_item(const std::string &book)
    : isbn(book), 
    units_sold(0), 
    revenue(0.0) {}

構(gòu)造函數(shù)是一個特殊的,與類同名的成員函數(shù),并且不能指定返回類型,如上圖所示。用于為每一個數(shù)據(jù)成員初始化。當(dāng)創(chuàng)建一個對象的實例時,編譯器會自動調(diào)用構(gòu)造函數(shù)來初始化對象。

這里使用了初始化列表的形式來初始化對象的成員變量。初始化列表以":"開始,項與項之間用","分隔。

它可以沒有形參,也可以定義多個形參。

除了初始化列表的形式,它還可以在函數(shù)體內(nèi)對成員變量進(jìn)行初始化,例如:

Sales_item::Sales_item(const string &book)
{
    isbn = book;
    units_sold = 0;
    revenue = 0.0;
}

我們生成一個對象的實例時,可以采取下面兩種方式:

Sales_item item("0-201-54848-8");
Sales_item *p = new Sales_item("0-201-54848-8");

2 默認(rèn)構(gòu)造函數(shù)

當(dāng)一個類沒有定義構(gòu)造函數(shù)時,像這樣:

class Sales_item {
};

這時,編譯器會自動生成一個默認(rèn)構(gòu)造函數(shù)。

反過來,只要這個類定義了一個構(gòu)造函數(shù),那么編譯器就不會再生成默認(rèn)構(gòu)造函數(shù)。

建議大家顯式的定義一個默認(rèn)構(gòu)造函數(shù)。

使用默認(rèn)構(gòu)造函數(shù)生成一個對象的實例時應(yīng)注意,下面的寫法是錯誤的:

Sales_item item();

當(dāng)沒有形參時,這種寫法不會引起編譯錯誤,但是卻未被編譯器理解為一個函數(shù),而不是一個類的對象。正確的寫法應(yīng)該是下面兩種形式:

Sales_item item;
Sales_item item = Sales_item();

3 隱式類類型轉(zhuǎn)換

「C++語言基礎(chǔ)(1):類型轉(zhuǎn)換」一文中介紹了內(nèi)置類型之間的幾個自動轉(zhuǎn)換。

也可以定義如何將其他類型的對象隱式轉(zhuǎn)換為我們的類類型,或?qū)⑽覀兊念愵愋蛯ο箅[式轉(zhuǎn)換為其他類型。

為了定義到類類型的隱式轉(zhuǎn)換,需要定義合適的構(gòu)造函數(shù)。

3.1 單個形參構(gòu)造函數(shù)的隱式類型轉(zhuǎn)換

可以用單個實參來調(diào)用的構(gòu)造函數(shù)定義了從形參類型到該類型的一個隱式轉(zhuǎn)換。

class Sales_item {
public:
    Sales_item(const std::string &book = "")
    :isbn(book)
    , units_sold(0) 
    , revenue(0.0) 
    {}
    
    Sales_item(std::istream &is);
}

我們看上面的帶有兩個構(gòu)造函數(shù)的Sales_item類。這里的每一個構(gòu)造函數(shù)都定義了一個隱式轉(zhuǎn)換。下述調(diào)用,都是合法的:

string null_book = "9-999-99999-9";
item.same_isbn(null_book);

item.same_isbn(std::cin);

編譯器使用接受一個string或istream類型的Sales_item構(gòu)造函數(shù)從null_book或cin生成一個新的Sales_item對象,并將該對象傳遞給same_isbn。但顯然,這時的Sales_item對象是臨時的,一旦same_item調(diào)用結(jié)束后,會被釋放。這樣的行為,多數(shù)情況下是錯誤的。

3.2 應(yīng)抑制由構(gòu)造函數(shù)定義的隱式轉(zhuǎn)換

通常,除非有明顯的理由想要定義隱式轉(zhuǎn)換,否則,單形參構(gòu)造函數(shù)應(yīng)該為explicit。將構(gòu)造函數(shù)設(shè)置為explicit可以避免錯誤,并且當(dāng)轉(zhuǎn)換有用時,用戶可以顯示的構(gòu)造對象。

3.2.1 explicit

當(dāng)構(gòu)造函數(shù)被聲明為explicit時,編譯器將不使用它作為轉(zhuǎn)換操作符。

class Sales_item {
public:
    explicit Sales_item(const std::string &book = "")
    :isbn(book)
    , units_sold(0) 
    , revenue(0.0) 
    {}
    
    explicit Sales_item(std::istream &is);
}

Sales_item::Sales_item(std::istream &is)
{
    is >> *this;
}

如上所示,可以通過將構(gòu)造函數(shù)聲明為explicit,來防止在需要隱式轉(zhuǎn)換的上下文中使用構(gòu)造函數(shù);該關(guān)鍵字只能用于類內(nèi)部的構(gòu)造函數(shù)聲明上,在類的定義體外部所做的定義不再重復(fù)它。

3.2.2 為轉(zhuǎn)換而顯式地使用構(gòu)造函數(shù)

用explicit聲明后的構(gòu)造函數(shù),如果需要做類型轉(zhuǎn)換時,可以按照下面這樣顯式的調(diào)用:

string null_book = "9-999-99999-9";
item.same_isbn(Sales_item(null_book));

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容