本文預(yù)覽:
- 轉(zhuǎn)換函數(shù) 與 non-explict-one-argument Ctor
- pointer-like class
- function-like class
- Reference經(jīng)驗(yàn)談
前言
本篇會(huì)提到一些瑣碎的東西,雖然有一些在我們編寫代碼的過(guò)程中不經(jīng)常用到,但是都是一些幫助你理解C++底層次的東西。網(wǎng)上有人開(kāi)玩笑說(shuō),一個(gè)java程序員學(xué)了三年,師傅對(duì)他說(shuō),你已經(jīng)精通java了,可以下山了;一個(gè)C++程序員,學(xué)了十年,師傅對(duì)他說(shuō),你可以下山了,但是不要說(shuō)你精通C++。這當(dāng)然只是個(gè)笑話,但是從側(cè)面反映出一個(gè)深刻的道理,那就是C++坑大水深,入坑需謹(jǐn)慎~。既然你已經(jīng)入坑了,不想就此自費(fèi)武功,那就好好修煉內(nèi)功吧。
轉(zhuǎn)換函數(shù) 與 non-explict-one-argument Ctor
轉(zhuǎn)換函數(shù)是什么鬼?類型轉(zhuǎn)換嘛,顧名思義。轉(zhuǎn)換函數(shù)記住一句話就好了,有轉(zhuǎn)出去和轉(zhuǎn)進(jìn)來(lái)之分。
舉個(gè)例子:設(shè)計(jì)一個(gè)分?jǐn)?shù)類 x/y
class Fraction {//這個(gè)分?jǐn)?shù)類還是非常簡(jiǎn)單的嘛
public:
Fraction(int x, int y = 1):_x(x),_y(y){}
inline int x() const {return _x;}
inline int y() const {return _y;}
operator double() const
{
return (double)(_x ) / (double)(_y);
}
Fraction operator+(const Fraction& f)
{
return Fraction(...);
}
private:
int _x; //分子
int _y; //分母
};
分?jǐn)?shù)類設(shè)計(jì)好了,使用的時(shí)候出現(xiàn)問(wèn)題了:
Fraction f(3,5);
double d = 4 + f;
一個(gè)整數(shù)加一個(gè)分?jǐn)?shù),能編譯通過(guò)嗎?我們是不是還需要重載一個(gè)+操作符來(lái)來(lái)實(shí)現(xiàn)運(yùn)算呢?現(xiàn)在好像是不用了,編譯器能通過(guò)編譯,計(jì)算結(jié)果也是正確的。你也許已經(jīng)注意到了:
operator double() const
{
return (double)(_x ) / (double)(_y);
}
這就是轉(zhuǎn)換函數(shù)的語(yǔ)法,沒(méi)有返回值類型,函數(shù)名稱就已經(jīng)說(shuō)明了你需要轉(zhuǎn)換出去的類型。C++編譯器會(huì)這么在遇到 4+f的時(shí)候首先會(huì)去尋找operator+(int),都沒(méi)有int可以穩(wěn)定轉(zhuǎn)成double, operator+(double)肯定是有的,double+double類型能通過(guò)嗎?找找看Fraction能轉(zhuǎn)成double類型嗎?operator double(),定義了轉(zhuǎn)換到double類型的函數(shù),可以轉(zhuǎn)換。
現(xiàn)在我們把轉(zhuǎn)換函數(shù)去掉,F(xiàn)raction不能轉(zhuǎn)成double了:
Fraction f(3,5);
double d = f + 4;
我們也沒(méi)有operator+(const double) ,但是編譯能過(guò)嗎?我們重載了一個(gè)operator+(const Fraction&),這個(gè)必須是要有的,沒(méi)有重載+肯定是編譯不過(guò)的,也就是說(shuō),我們這次的+,肯定是用到了operator+(const Fraction),那么好了,如果能編譯通過(guò),肯定是int轉(zhuǎn)成了Fraction類型了。但是,我們不可能去修改C++語(yǔ)言內(nèi)核,在int里也加一個(gè)轉(zhuǎn)換函數(shù)吧。為題出在哪里了?它怎么自動(dòng)轉(zhuǎn)的,這就用到了non-explict-one-argument Ctor, 自動(dòng)調(diào)用了Fraction的構(gòu)造函數(shù),把int轉(zhuǎn)換成了Fraction。
注意:
Fraction(int x, int y = 1):_x(x),_y(y){}
// explict Fraction(int x, int y = 1):_x(x),_y(y){}
這種構(gòu)造函數(shù)叫做non-explict-one-argument Ctor,前面沒(méi)有explict修飾,并且只有一個(gè)實(shí)參,第二個(gè)參數(shù)是有默認(rèn)值的,如果沒(méi)有默認(rèn)值就不能叫one-argument。如果沒(méi)有加explict編譯器是可以自行調(diào)用,把其他類型轉(zhuǎn)進(jìn)來(lái)的。加了explict,編譯就不通過(guò)了。
pointer-like class
pointer-like class:把class設(shè)計(jì)出來(lái)當(dāng)做指針用。在智能指針和迭代器都是這么設(shè)計(jì)的。
- 智能指針的設(shè)計(jì)
智能指針被C++設(shè)計(jì)用來(lái)管內(nèi)存,寫法相當(dāng)固定,必須要重載的和->,解引用這個(gè)應(yīng)該都是沒(méi)有什么困惑,但是問(wèn)題在->這個(gè)問(wèn)題就出來(lái)了,sp->method()調(diào)用返回的是T啊,在第一次已經(jīng)使用了->,返回的T*還怎么調(diào)用method(),C++語(yǔ)法定義了->有繼續(xù)作用的特性。這個(gè)問(wèn)題就解決了。我們第一次雖然使用了->,但是由于C++語(yǔ)法規(guī)定,->能繼續(xù)作用,因此,智能指針這么設(shè)計(jì)是沒(méi)有問(wèn)題的。
- 迭代器的設(shè)計(jì)
迭代器在STL里大部分都被設(shè)計(jì)成了class,迭代器的使用方法也很像是指針,我們以list的迭代器來(lái)看,是如何重載指針的解引用和調(diào)用操作符的。
在list中*操作符將獲取元素對(duì)象,也就是list_no
![Uploading 屏幕快照 2017-03-08 16.00.50_078916.png . . .]
de<T>的data部分;->操作符獲得data的指針。這樣,我們就能使用迭代器,直接獲取list元素對(duì)象和調(diào)用相應(yīng)的方法了。
function-like class 所謂仿函數(shù)
function-like class: 將類設(shè)計(jì)出來(lái),當(dāng)做函數(shù)使用,又叫仿函數(shù)。其實(shí)質(zhì)就是在里面重載了()操作符
STL里面的算法less實(shí)現(xiàn):
template <class T>
struct less
{
bool operator()(const T& x, const T& y) const {return x < y; }
}
這是算法嗎?分明就是一個(gè)class,這是一個(gè)class嗎?這不是仿函數(shù)嗎?自己好像很少用到仿函數(shù)吧,C++11里面出現(xiàn)了lamda表達(dá)式之后對(duì)仿函數(shù)簡(jiǎn)直就是秒殺有沒(méi)有。但是它確實(shí)在STL里面有大量的應(yīng)用。
bool ret = less<int>()(2,1); //第一個(gè)()表示是一個(gè)臨時(shí)對(duì)象,第二個(gè)()才真正調(diào)用了operator()
cout<<ret<<endl;
float d = plus<float>()(1.2,2.1);
cout<<d<<endl;
以上是使用示例。
Reference經(jīng)驗(yàn)談
如果從內(nèi)存角度看一個(gè)變量,那么變量大概可以分為三類:
- value : 分配一塊內(nèi)存空間放值
- pointer : 分配一塊內(nèi)存空間放地址
- reference : 分配一塊地址空間,放一個(gè)對(duì)象,這個(gè)對(duì)象代表了他所引用的對(duì)象
int x = 0;
int& r = x;
cout<<x<<endl;
cout<<&x<<endl;
cout<<sizeof(x)<<endl;
cout<<r<<endl;
cout<<&r<<endl;
cout<<sizeof(r)<<endl;
你所看到的r和x所有的都是一樣的,于是我們稱reference是object的別名。但是它的內(nèi)部實(shí)現(xiàn)是指針,但是它屏蔽了指針的概念和用法,在用法上和它所引用的對(duì)象是一樣的。
關(guān)于引用需要知道:
- 一個(gè)引用變量在創(chuàng)建的時(shí)候要有初始值;
- 通常不用做變量聲明,而作為參數(shù)傳遞;
- java里面的所有變量都是reference;
- 修改引用,也會(huì)修改它所代表的對(duì)象;
- 實(shí)現(xiàn)是指針,邏輯上我們理解為代表或者別名。