我們先從一個簡單的類開始
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));