使用類
-
運算符重載
- 重載后的運算符必須至少有一個操作數(shù)是用戶定義的類型
- 使用運算符時不能違反原來運算符的句法規(guī)則, 同樣不能修改運算符的優(yōu)先級
- 不能創(chuàng)建新的運算符, 例如定義operator**()函數(shù)來表示求冪
- 不能重載以下運算符
- sizeof : sizeof運算符
- . : 成員運算符
- .* : 成員指針運算符
- :: : 作用域解析運算符
- ?: : 條件運算符
- typeid : 一個RTTI運算符
- const_cast, dynamic_cast, reinterpret_cast, static_cast : 強(qiáng)制類型轉(zhuǎn)換運算符
- 以下運算符只能通過成員函數(shù)重載
- = : 賦值運算符
- () : 函數(shù)調(diào)用運算符
- [] : 下標(biāo)運算符
-> : 通過指針訪問類成員的運算符
-
以下運算符可通過成員函數(shù)或非成員函數(shù)重載
reloadable_operator.png
-
友元
- 友元有三種:
- 友元函數(shù)
- 友元類
- 友元成員函數(shù)
通過讓函數(shù)成為類的友元,可以賦予該函數(shù)與類成員函數(shù)相同的訪問權(quán)限
- 為何需要友元
在為類重載二元運算符時, 常常需要友元
雙目運算符交換兩邊操作數(shù)結(jié)果應(yīng)該是一樣的, 為了滿足兩種用法, 非成員函數(shù)重載運算符為了能夠使用類的私有成員將函數(shù)聲明為類的友元函數(shù)
創(chuàng)建友元函數(shù)的方法如下代碼:
class Point {
int x;
int y;
public:
Point(int xv = 0, int yv = 0): x(xv), y(yv) {}
Point operator*(int fac) const {
Point res;
res.x = x * fac;
res.y = y * fac;
return res;
}
// 1. 將函數(shù)原型放在類聲明中, 并加上關(guān)鍵字friend
friend Point operator*(int fac, const Point& p);
void show() {
cout << "(" << x << ", " << y << ")\n";
}
};
// 2. 編寫定義函數(shù), 他不是成員函數(shù)不要加Point::限定
// 另外注意不能在定義中使用friend關(guān)鍵字, 除非為內(nèi)聯(lián)函數(shù)的情況(原型也是定義)
Point operator*(int fac, const Point& p) {
Point res;
res.x = p.x * fac;
res.y = p.y * fac;
return res;
}
- 常用的友元: 重載<<運算符
用cout << name 來輸出用戶定義類型
一種實現(xiàn)代碼如下:
// 在類中聲明原型
friend void operator<<(ostream & os, const Point& p);
// 定義
void operator<<(ostream & os, const Point& p) {
os << "(" << p.x << ", " << p.y << ")\n";
}
另一種更好的實現(xiàn), 適應(yīng)cout << x << y這種用法
代碼如下:
ostream & operator<<(ostream & os, const Point& p) {
os << "(" << p.x << ", " << p.y << ")\n";
return os;
}
-
類的自動類型轉(zhuǎn)換和強(qiáng)制類型轉(zhuǎn)換
- C++的類型轉(zhuǎn)換
- 將一個標(biāo)準(zhǔn)類型變量的值賦給另一種標(biāo)準(zhǔn)類型的變量時, 如果這兩種類型兼容, 則C++自動講這個值轉(zhuǎn)換為接收變量的類型
long a = 22; // type int -> type long double b = 33; // int c = 3.14; //
- C++不自動轉(zhuǎn)換不兼容的類型, 例如:
int* p = 10;- 但是可以使用強(qiáng)制類型轉(zhuǎn)換
int* p = (int*)10;
- 將構(gòu)造函數(shù)用作自動類型轉(zhuǎn)換
class ConvInt {
public:
ConvInt(int x) { m_x = x; }
private:
int m_x;
}
ConvInt ci = 10; // 合法
- explicit關(guān)鍵字用于關(guān)閉這種特性, 但仍可以顯示轉(zhuǎn)換
class ConvInt {
public:
explicit ConvInt(int x) { m_x = x; }
private:
int m_x;
}
ConvInt ci = 10; // 不合法
ConvInt cj = ConvInt(10); // 合法
ConvInt ck = (ConvInt)10; // 合法
- 注意: 只接收一個參數(shù)的構(gòu)造函數(shù)定義了從參數(shù)類型到類類型的轉(zhuǎn)換
- 何時使用ConvInt(int)函數(shù)?
如果在聲明中使用了關(guān)鍵字explicit, 則ConvInt(int)將只用于顯示的強(qiáng)制轉(zhuǎn)換, 否則還可以用于以下隱式轉(zhuǎn)換:
- 將ConvInt對象初始化為int值時
- 將int值賦給ConvInt對象時
- 將int值傳遞給接受ConvInt參數(shù)的函數(shù)時
- 返回值被聲明為ConvInt的函數(shù)試圖返回int值時
- 在上述任一種情況下,使用可轉(zhuǎn)換為int類型的內(nèi)置類型時
對以上最后一條而言轉(zhuǎn)換不能出現(xiàn)二義性
- 轉(zhuǎn)換函數(shù)
轉(zhuǎn)換函數(shù)用于將類類型轉(zhuǎn)換為某種類型
例如有以下語句ConvInt ci(10); double dt1 = double(ci); double dt2 = (double)ci; double dt3 = ci;轉(zhuǎn)換函數(shù)應(yīng)滿足以下幾點:
- 轉(zhuǎn)換函數(shù)必須是類方法
- 轉(zhuǎn)換函數(shù)不能指定返回類型
- 轉(zhuǎn)換函數(shù)不能有參數(shù)
例如, 轉(zhuǎn)換為double類型的原型聲明如下:
operator double();
- 程序中不能出現(xiàn)二義性轉(zhuǎn)換, 例如:
class ConvInt {
public:
ConvInt(int x) { m_x = x; }
operator int() {
return m_x;
}
operator double() {
return double(m_x);
}
private:
int m_x;
}
ConvInt ci(1);
double dt = ci; // 合法, 根據(jù)上下文知道使用operator double()轉(zhuǎn)換
cout << ci; // 不合法, 編譯器會認(rèn)為有二義性而拒絕
cout << int(ci); // 合法
- 隱式自動轉(zhuǎn)換請謹(jǐn)慎使用, 建議永遠(yuǎn)做顯式轉(zhuǎn)換
