1 類(lèi)類(lèi)型轉(zhuǎn)換
在C++中扼仲,類(lèi)只要滿(mǎn)足特定的條件就可以從類(lèi)對(duì)象轉(zhuǎn)換到基本類(lèi)型或其他類(lèi)類(lèi)型對(duì)象,也可以從基本類(lèi)型或其他類(lèi)類(lèi)型對(duì)象轉(zhuǎn)換到該類(lèi)對(duì)象抄淑。1.1和1.2節(jié)講述只兩種轉(zhuǎn)換的操作方法以及注意事項(xiàng)屠凶。
1.1 class到其他對(duì)象
一個(gè)class對(duì)象要轉(zhuǎn)換到其他類(lèi)型的對(duì)象,需要重載類(lèi)型轉(zhuǎn)換操作符(Conversion Operator)肆资。類(lèi)型轉(zhuǎn)換操作符是一種特殊的成員函數(shù)矗愧,它負(fù)責(zé)將一個(gè)類(lèi)類(lèi)型的值轉(zhuǎn)換成其他類(lèi)型。類(lèi)型轉(zhuǎn)換操作符的一般形式:
operator type() const;
**
注意:
1.類(lèi)型轉(zhuǎn)換操作符沒(méi)有返回值郑原;
2.type可以是除了void之外唉韭,任意能夠作為函數(shù)返回值的類(lèi)型夜涕;
3.一般類(lèi)型轉(zhuǎn)換操作符都不會(huì)修改類(lèi)數(shù)據(jù)成員的值,因此一般聲明為const属愤;
4.類(lèi)型轉(zhuǎn)換操作符是不可以帶有參數(shù)的女器;
5.類(lèi)型轉(zhuǎn)換操作符必須是類(lèi)的成員函數(shù)。
**
在實(shí)現(xiàn)上住诸,一般很少有類(lèi)提供類(lèi)型轉(zhuǎn)換操作符驾胆,但是有一個(gè)例外,類(lèi)定義向bool類(lèi)型的轉(zhuǎn)換還是比較常見(jiàn)的贱呐。比如我們經(jīng)常使用輸入輸出流俏拱,文件流和字符流都定義了從類(lèi)對(duì)象到bool對(duì)象的轉(zhuǎn)換。有了這種轉(zhuǎn)換我們就可以很方便的編寫(xiě)判斷文件打開(kāi)是否成功吼句、文件讀取/寫(xiě)入是否成功的代碼锅必,像 if(cin)
或者while(cin >> val)
。如果沒(méi)有這種轉(zhuǎn)換惕艳,對(duì)while的判斷我們可能就要這樣寫(xiě):
while(1){
cin >> val;
if (cin.good()){//do someting.}
}
相較之下搞隐,方便程度力見(jiàn)。在使用C++的語(yǔ)法元素上远搪,標(biāo)準(zhǔn)庫(kù)是最有說(shuō)服力的劣纲。因此,下面我們看下標(biāo)準(zhǔn)庫(kù)的basic_istream::sentry是如何實(shí)現(xiàn)類(lèi)型轉(zhuǎn)換的谁鳍。
template<typename _CharT, typename _Traits>
class basic_istream<_CharT, _Traits>::sentry
{
// Data Members.
bool _M_ok;
public:
explicit
sentry(basic_istream<_CharT, _Traits>& __is, bool __noskipws = false);
#if __cplusplus >= 201103L
explicit
#endif
operator bool() const
{ return _M_ok; }
};
從sentry的實(shí)現(xiàn)中癞季,我們可以看到類(lèi)型轉(zhuǎn)換操作符聲明上雖然沒(méi)有返回值,但是需要返回一個(gè)type類(lèi)型的對(duì)象(這里就是bool)倘潜。
類(lèi)型轉(zhuǎn)換操作符一般都是隱式進(jìn)行的绷柒,因此可能出現(xiàn)會(huì)產(chǎn)生意料之外的結(jié)果,為了限制編譯器在非bool上下文中進(jìn)行隱式轉(zhuǎn)換涮因,C++11引入了顯式的類(lèi)型轉(zhuǎn)換符废睦,形式如下:
explicit operator type() const
通過(guò)在聲明中添加explicit關(guān)鍵字來(lái)要求編譯器只能在bool上下文中使用類(lèi)型轉(zhuǎn)換。
1.2 其他對(duì)象到class
通過(guò)定義只帶一個(gè)參數(shù)的構(gòu)造函數(shù)可以實(shí)現(xiàn)其他對(duì)象到類(lèi)對(duì)象的隱式類(lèi)型轉(zhuǎn)換养泡。我們通過(guò)一個(gè)示例來(lái)看下如何編寫(xiě)從其他類(lèi)型到class對(duì)象的隱式轉(zhuǎn)換嗜湃。
代碼
#include <iostream>
using namespace std;
class A
{
double m_data;
public:
A(double x):m_data(x){cout << "A::ctor(x)" << endl;}
void print()const{cout << m_data << endl;}
};
int main()
{
A a(1);
a.print(); //輸出a=1
a = 3;
a.print(); //輸出a=3
}
程序輸出結(jié)果:
A::ctor(x)
1
A::ctor(x)
3
從程序的輸出結(jié)果可以看出在執(zhí)行a=3
時(shí),編譯器會(huì)先調(diào)用構(gòu)造函數(shù)將數(shù)值3轉(zhuǎn)換成類(lèi)A的對(duì)象澜掩,然后再執(zhí)行賦值操作购披。因此,我們可以用類(lèi)似的方式來(lái)實(shí)現(xiàn)其他對(duì)象向類(lèi)對(duì)象的隱式轉(zhuǎn)換肩榕。
雖然刚陡,編譯器的這種隱式類(lèi)型轉(zhuǎn)換是很方便的,但是,我們有時(shí)候并不希望編譯器進(jìn)行隱式類(lèi)型轉(zhuǎn)換橘荠,這時(shí)候可以在構(gòu)造函數(shù)的聲明前添加explicit關(guān)鍵字來(lái)阻止編譯器的隱式轉(zhuǎn)換。
2 like-classes
C++有兩種很特別的類(lèi)郎逃,pointer like class和function like class哥童。pointer like class的行為像指針,function like class的行為像函數(shù)褒翰。
2.1 pointer like class
pointer like class通過(guò)重載操作符*,->,++,--等其中的一部分或全部來(lái)使類(lèi)具有像指針一樣的行為贮懈。pointer like class主要的用途有兩個(gè):智能指針和迭代器。本文不打算從pointer like class用途的角度來(lái)描述,本文主要從操作符重載的角度來(lái)描述怎樣實(shí)現(xiàn)一個(gè)pointer like class.
一般pointer like class都要實(shí)現(xiàn)兩個(gè)操作符优训,解引用操作符(*)和箭頭操作符(->)朵你。實(shí)現(xiàn)的示例如下:
template<typename T>
class SmartPtr{
public:
SmartPtr(T *p):px(p){}
T& operator*(){return *px;}
T* operator->(){return px;}
private:
T *px;
}
當(dāng)我們定義好類(lèi)SmartPtr以后,我們就可以像指針一樣使用它揣非。如:
struct s{int no;};
SmartPtr<s> sp = new s;
然后對(duì)sp我們可以進(jìn)行解引用*sp
和訪(fǎng)問(wèn)對(duì)象成員sp->no抡医。
**
注意:
1.箭頭操作符必須是類(lèi)成員函數(shù)。解引用操作符通常是類(lèi)成員函數(shù)早敬。
2.重載的箭頭操作符必須返回類(lèi)的指針或者重載了箭頭操作符的摸個(gè)類(lèi)的對(duì)象忌傻。
**
2.2 function like class
如果類(lèi)重載了函數(shù)調(diào)用操作符,則我們就可以像函數(shù)一樣使用該類(lèi)的對(duì)象搞监,因此我們稱(chēng)這種類(lèi)為function like class.由于類(lèi)可以存儲(chǔ)狀態(tài)因此會(huì)比一般的函數(shù)更加靈活水孩。
語(yǔ)法:
return-type operator()(param_type1 param1, param_type2 param2,...);
注意:函數(shù)調(diào)用操作符必須是成員函數(shù)。
我們來(lái)看一個(gè)示例:
struct absInt{
int operator()(int x){
return x > 0 ? x : -x;
}
}
3 引用
3.1 語(yǔ)法
引用定義的一般形式為type& var = defined_var;
或者consts type& var = defined_var;
引用是變量的別名琐驴,因此引用在定義的時(shí)候就要進(jìn)行初始化俘种。當(dāng)使用引用時(shí)就和使用變量是一致。如下:
int x = 3;
int &r = x; //定義引用
r = 5; //對(duì)引用復(fù)制就是對(duì)變量x復(fù)制绝淡,此時(shí)x的值就是5.
3.2 常見(jiàn)用途及注意事項(xiàng)
1.很少用于變量聲明宙刘,一般用于參數(shù)傳遞和返回類(lèi)型的描述。
2.引用類(lèi)型的&符號(hào)并不能作為函數(shù)簽名
3.引用定義時(shí)就要進(jìn)行初始化牢酵。