[cpp]
class Sale_item
{
public:
// 隱式使用string 的默認構造函數初始化 isbn
Sale_item():price(0.0){}
Sale_item(const string &book):isbn(book), price(0.0){}
// 建議使用默認實參,將上述2個構造函數合並。如下:
// Sale_item(const string &book = ""):isbn(book), price(0.0){}
private:
string isbn;
double price;
};
合成的默認構造函數
如果,類沒有定義構造函數,編譯器將會自動生成一個默認的構造函數。
但是,如果已經定義過構造函數(哪怕只有1 個), 編譯器就不會再生成默認構造函數。
理由:因為一個類,在某種情況下,需要控制對象的初始化,則,該類很可能在所有情況下都需要控制。
合成的默認構造函數,的初始化規則,與變量的初始化規則相同。
類類型,使用各自的默認構造函數,來初始化
內置、復合類型,如:指針、數組,只對定義在全局作用域中的對象才初始化,
定義局部作用域中,則,內置、復合類型不初始化,處於未定義狀態。
類通常,都應該定義一個默認構造函數
假設:NoDefault ,是一個類,它具有接受一個 string 實參的構造函數,
這種情況下,編譯器,不會生成默認構造函數。
於是,
1、當我定義一個類 A,具有 NoDefault 類型的成員,則,
A 的所有構造器,都必須通過傳遞一個初始 string 來初始化 NoDefault 類型的成員
2、當我定義一個類 A,具有 NoDefault 類型的成員,則,
編譯器將不會生成 A 的默認構造器。只能自己顯示定義
3、NoDefault 類型,不能用作動態分配數組的元素類型。
[cpp]
int *iArr = new int[10];
// 上式可行,下式報錯
NoDefault *arr = new NoDefault[10];
4、NoDefault 類型的靜態分配數組,也必須為每個元素提供顯示的初始化
5、如果有保存 NoDefault 對象的容器,如:vector,
則,容器的構造函數,不僅要提供容器大小,也要提供元素初始化式。
[cpp]
// 這是一個函數聲明,函數返回類型:Sales_item
Sales_item myObj();
//
Sales_item myObj2;
// 創建一個 Sales_item 對象,並用默認構造函數初始化
Sales_item myObj3 = new Sales_item();
隱式類型轉換
[cpp]
class Sales_item
{
public:
Sales_item(const string &book = ""):isbn(book), units_sold(0), revenue(0.0){}
// explicit 只能用於,類內部的構造函數聲明上,在類的定義體外部則不用重復它
explicit Sales_item(istream &is);
Sales_item();
bool same_isbn(Sales_item item)
{
return item.isbn == isbn;
}
private:
string isbn;
int units_sold;
double revenue;
};
// 錯誤: explicit 只能在類內部的構造函數聲明上
explicit Sales_item::Sales_item(istream &is)
{
/* ... */
}
/* ... */
string null_book = "9-999-9999-9";
Sales_item item_a = Sales_item("1-111-1111-1");
// 以下會隱式調用構造函數,生成一個 Sales_item 對象,來進行比較
// 但這種隱式轉換,未必是我們真正想要的。
// 為阻止這種隱式轉換,可以在構造函數前,使用 explicit 關鍵字
item_a.same_isbn(null_book);
// 建議使用下面的方式,避免錯誤
item_a.same_isbn(Sales_item(null_book));
[cpp]
// 沒有定義構造函數、並且,全體數據成員都是 public 的類,
// 可以采用,與數組元素相同的方式,來初始化成員
// 但,還是推薦,使用構造函數
struct Data
{
int ival;
char *ptr;
};
Data val1 = {0, 0};
友元,允許一個類,將自己的,非公有成員的訪問,授權給,指定的類或者函數。
它只能出現在類定義的內部。通常,將所有的友元聲明,成組地放到類定義的開始或者結尾。
[cpp]
class Screen
{
public:
typedef string::size_type index;
private:
int height;
int width;
// 友元不是 Screen的成員,
// 它可以出現在 Screen 類定義體中的,任何地方。
// 並且,不受訪問控制(private、public)的影響
friend class Window_Mgr;
// 將,其他類的成員函數,設置為友元
friend Window_Mgr& Window_Mgr::relocate(Screen::index, Screen::index, Screen&);
};
class Window_Mgr
{
public:
Window_Mgr& relocate(Screen::index r, Screen::index c, Screen &s)
{
s.height += r;
s.width += c;
return *this;
}
private:
};
要將類的成員函數,設為友元,則這個類必須先定義
要將類 或者 非成員函數 設為友元,則,不需要預先聲明。
(P398,例子,貌似有誤)
全局對象,會破壞封裝性,而,類中定義的 靜態成員,則能保持很好的封裝性。
static 數據成員,與類相關聯,而不是與類的對象關聯。
static 成員函數,沒有 this 形參。
[cpp]
class Account
{
public:
void applyint(){ amount += amount * interestRate; }
static double rate() { return interestRate; }
static void rate(double);
private:
string owner;
double amount;
static double interestRate;
static double initRate();
// 例外,const 類型的靜態數據成員,可以在類定義體中初始化
// 但是,即使如此,也必須在外部,進行定義
static const int period = 30;
};
// 外部定義,但此時,無須提供初始化式
const int Account::period;
// 內部已經聲明為 static 了
// 外部定義的時候,不需要再指定 static
// static 不能聲明為 const、也不能聲明為 虛函數
// 聲明為 const 是承諾不修改該函數所屬的對象,
// 然而, static 函數,不屬於任何對象,它只與類關聯
void Account::rate(double newRate)
{
interestRate = newRate;
}
// static 數據成員,必須在類定義體的外部定義(剛好一次)
// 一旦成員名出現,static 成員的定義,就在類作用域中了
// 因此,可以直接使用 私有成員函數 initRate
double Account::interestRate = initRate();
Account ac1;
Account *ac2 = &ac1;
double rate;
rate = ac1.rate();
rate = ac2->rate();
rate = Account::rate();
[cpp]
class Bar
{
public:
private:
// static 數據成員的類型,可以是該成員所屬的類類型。
static Bar mem1;
Bar *mem2;
// 錯誤
Bar mem3;
}; www.2cto.com
class Screen
{
public:
Screen& clear(char = bkground);
private:
// static 數據成員,可以作為默認實參。
static const char bkground = '#';
};