C++基礎(chǔ)之this指針與另一種“多態(tài)”
一、引入
定義一個(gè)類的對(duì)象,首先系統(tǒng)已經(jīng)給這個(gè)對(duì)象分配了空間,然后會(huì)調(diào)用構(gòu)造函數(shù)。
一個(gè)類有多個(gè)對(duì)象,當(dāng)程序中調(diào)用對(duì)象的某個(gè)函數(shù)時(shí),有可能要訪問(wèn)到這個(gè)對(duì)象的成員變量。
而對(duì)于同一個(gè)類的每一個(gè)對(duì)象,都是共享同一份類函數(shù)。對(duì)象有單獨(dú)的變量,但是沒(méi)有單獨(dú)的函數(shù),所以當(dāng)調(diào)用函數(shù)時(shí),系統(tǒng)必須讓函數(shù)知道這是哪個(gè)對(duì)象的操作,從而確定成員變量是哪個(gè)對(duì)象的。
這種用于對(duì)成員變量歸屬對(duì)像進(jìn)行區(qū)分的東西,就叫做this指針。事實(shí)上它就是對(duì)象的地址,這一點(diǎn)從反匯編出來(lái)的代碼可以看到。
二、分析
1、測(cè)試代碼:
/////////////////////////////////////////////////////////////////////////////////////
#include<iostream>
using namespace std;
/////////////////////////////////////////////////////
class A
{
public:
A(char *szname)
{
cout<<"construct"<<endl;
name
= new char[20];
strcpy(name,
szname);
}
~A()
{
cout<<"destruct"<<endl;
delete name;
}
void show();
private:
char *name;
};
/////////////////////////////////////////////////////
void A::show()
{
cout<<"name
= "<<name<<endl;
}
/////////////////////////////////////////////////////
int main()
{
A
a("zhangsan");
a.show();
system("pause");
return 0;
}
程序在VC++6.0 32位操作系統(tǒng)上編譯、運(yùn)行。
對(duì)編譯后的EXE文件,進(jìn)行反匯編。反匯編工具為OllyDbg。
2、反匯編分析
關(guān)鍵點(diǎn)截圖如下:
(1)從圖1可以發(fā)現(xiàn)this指針通過(guò)ECX寄存器,傳遞給了成員函數(shù)。this指針就是對(duì)象的地址。
圖 1 Main函數(shù)
(2)從圖 2可以發(fā)現(xiàn)訪問(wèn)對(duì)象的成員變量用的就是之前通過(guò)ECX傳入的this指針。
圖 2 show()函數(shù)
三、深入理解
通過(guò)截圖及相關(guān)的資料,可以很清晰的知道在調(diào)用構(gòu)造函數(shù)、show()函數(shù)之前的那個(gè)ECX就是this指針,也就是說(shuō)這是一個(gè)驗(yàn)證性的實(shí)驗(yàn),答案已經(jīng)很清楚了,所要做的就是去動(dòng)手體驗(yàn)一下。但是,假如我不懂C++、我不懂什么this指針,我一樣可以發(fā)現(xiàn)這個(gè)叫做“this指針”的東西。通過(guò)OD的動(dòng)態(tài)調(diào)試,當(dāng)顯示出了name時(shí),逐步回溯可以發(fā)現(xiàn)name的源頭是ECX。OD重新載入,查看在進(jìn)入show()函數(shù)之前ECX是哪里來(lái)的,最終可以一步步的發(fā)現(xiàn),ECX就是一個(gè)地址,這個(gè)地址里邊的第一個(gè)值也是一個(gè)地址,指向一串字符串。再往上分析,進(jìn)入show()上邊的構(gòu)造函數(shù),可以發(fā)現(xiàn)里邊有new操作,strcpy操作,這里就發(fā)現(xiàn)了字符串空間、內(nèi)容的來(lái)源。至此,基本就分析完了。
通過(guò)這個(gè)過(guò)程可以發(fā)現(xiàn)很多C++的知識(shí)。如:對(duì)象的空間是在調(diào)用構(gòu)造函數(shù)之前就分配好了的;對(duì)象里邊沒(méi)有函數(shù);this指針通過(guò)寄存器ECX傳遞;通過(guò)聲明定義的對(duì)象它的空間分配在棧中;等等這些跟系統(tǒng)或者C++有關(guān)聯(lián)的知識(shí)。
但是,對(duì)于一個(gè)不懂C++的人看來(lái),上面一段的體會(huì)都是沒(méi)有的。從匯編指令看不出C++的思想,this指針不過(guò)是一個(gè)地址;對(duì)象不過(guò)是一些空間;構(gòu)造函數(shù)、析構(gòu)函數(shù)以及其它的函數(shù),也不過(guò)是一堆指令的集合。
C++的同一個(gè)類定義出來(lái)的多個(gè)對(duì)象,從匯編指令看來(lái)是這樣的:有很多塊地址空間,它們有相同的大小。當(dāng)不同的對(duì)象調(diào)用成員函數(shù)時(shí),在匯編指令看來(lái)是:它們都call同一個(gè)地址,這個(gè)call指令其實(shí)里邊是一個(gè)jmp指令,用于跳向某個(gè)位置,在call指令之前一般都會(huì)把一個(gè)地址放到ECX中,當(dāng)然有時(shí)候會(huì)用堆?;蛘咂渌拇嫫鳌?br>
C++的繼承、多態(tài)、封裝,對(duì)匯編程序員來(lái)說(shuō)是看不出有什么神奇的,對(duì)于C++程序員來(lái)說(shuō)那可就不同了,可以省去很多的工作,把很多事情都交給了編譯器,讓編譯器自動(dòng)給你搞定。
C++程序員所討論的對(duì)象及其眾多的特點(diǎn)、優(yōu)點(diǎn),最終還是變成了“低級(jí)”的指令,而且可能是效率低下的指令,即便如此,它的優(yōu)點(diǎn)仍遠(yuǎn)大于缺點(diǎn),它讓編程變得容易、高效。
四、延伸
忽然想到了C++的多態(tài),一句話“將子類類型的指針賦值給父類類型的指針”,多態(tài)是通過(guò)虛函數(shù)實(shí)現(xiàn)。對(duì)虛函數(shù)及其相關(guān)內(nèi)容的原理、詳細(xì)理解就不細(xì)說(shuō)了。
說(shuō)下我的簡(jiǎn)單理解,有一個(gè)基類A和子類B、C,有一個(gè)函數(shù)以基類A的指針為參數(shù),然后在函數(shù)里頭通過(guò)指針調(diào)用基類的成員函數(shù)。假如這個(gè)被調(diào)用的基類成員函數(shù)不是虛函數(shù),那么是不可能實(shí)現(xiàn)多態(tài)的,因?yàn)榉g成匯編指令的時(shí)候,調(diào)用成員函數(shù)的這個(gè)地方是一個(gè)call指令,然后這個(gè)call指令跳到某個(gè)地方去執(zhí)行,這是一個(gè)固定了的地址。通過(guò)定義為虛函數(shù),調(diào)用成員函數(shù)的這個(gè)地方是通過(guò)虛函數(shù)表指針來(lái)確定調(diào)用哪個(gè)函數(shù)的,而虛函數(shù)表指針就放在對(duì)象的地址空間中,如果對(duì)象變了,那么虛函數(shù)表指針也變了,調(diào)用的函數(shù)也就不同了。對(duì)于那個(gè)以基類A的指針為參數(shù)的函數(shù),指針即是對(duì)象的地址,如果傳遞的地址是子類B或者C的對(duì)象的地址,那么虛函數(shù)表指針也就不同了,調(diào)用的成員函數(shù)也就不同了。
這就是多態(tài),這種多態(tài)使得調(diào)用同一個(gè)函數(shù),因?yàn)閭鬟f參數(shù)的不同而顯示出差異,參數(shù)可以是基類對(duì)象或者眾多不同的子類對(duì)象。它們的差異是類與類之間的。
有虛函數(shù)的對(duì)象的內(nèi)存布局,比沒(méi)有虛函數(shù)的對(duì)象多了一個(gè)指向虛函數(shù)表的指針。因?yàn)樘摵瘮?shù)的調(diào)用是通過(guò)虛函數(shù)表指針來(lái)實(shí)現(xiàn)的,所以有了多態(tài)。
再考慮一下C++的this指針,一個(gè)類中的成員函數(shù),依據(jù)this指針來(lái)區(qū)分不同的對(duì)象,也就是說(shuō)根據(jù)this指針實(shí)現(xiàn)了訪問(wèn)不同的對(duì)象的成員變量。
這是否也是多態(tài)的一種表現(xiàn)?這里所說(shuō)的多態(tài)已經(jīng)不是那個(gè)“父類指針指向子類對(duì)象”的教條了,而是體現(xiàn)在同一個(gè)類的不同對(duì)象之間,調(diào)用同一個(gè)成員函數(shù),依據(jù)參數(shù)“this指針”來(lái)實(shí)現(xiàn)訪問(wèn)不同的對(duì)象的成員變量。成員函數(shù)訪問(wèn)成員變量,在編譯期無(wú)法確定它訪問(wèn)的成員變量在哪一個(gè)地址的,只有到了運(yùn)行期依據(jù)this指針才能確定訪問(wèn)的地址。這一點(diǎn)很類似于類的多態(tài):以基類指針為參數(shù)的函數(shù)里調(diào)用了某個(gè)基類的虛成員函數(shù),在編譯期無(wú)法確定程序運(yùn)行時(shí)調(diào)用的會(huì)是哪個(gè)類的對(duì)象,只有到了運(yùn)行期才確定會(huì)調(diào)用哪個(gè)類的對(duì)象。
this指針識(shí)別了同一個(gè)類的不同的對(duì)象,換句話說(shuō),this指針使得成員函數(shù)可以訪問(wèn)同一個(gè)類的不同對(duì)象。再深入一點(diǎn),this指針使得成員函數(shù)會(huì)因?yàn)閠his指針的不同而訪問(wèn)到了不同的成員變量。這也是多態(tài)吧,只是它是必然存在的多態(tài),這種多態(tài)跟基類與派生類之間的多態(tài)是不同級(jí)別的多態(tài),它不像一般的多態(tài)可以通過(guò)對(duì)使用虛函數(shù)的選擇來(lái)取舍,它是一個(gè)類對(duì)應(yīng)多個(gè)對(duì)象、多個(gè)對(duì)象共享一份成員函數(shù)代碼帶來(lái)的必然結(jié)果。
欄 目:C語(yǔ)言
下一篇:c++中冒號(hào)(:)和雙冒號(hào)(::)的使用說(shuō)明
本文標(biāo)題:C++基礎(chǔ)之this指針與另一種“多態(tài)”
本文地址:http://mengdiqiu.com.cn/a1/Cyuyan/4259.html
您可能感興趣的文章
- 04-02c語(yǔ)言沒(méi)有round函數(shù) round c語(yǔ)言
- 01-10深入理解C++中常見(jiàn)的關(guān)鍵字含義
- 01-10使用C++實(shí)現(xiàn)全排列算法的方法詳解
- 01-10APUE筆記之:進(jìn)程環(huán)境詳解
- 01-10c++中inline的用法分析
- 01-10用C++實(shí)現(xiàn)DBSCAN聚類算法
- 01-10全排列算法的非遞歸實(shí)現(xiàn)與遞歸實(shí)現(xiàn)的方法(C++)
- 01-10C++大數(shù)模板(推薦)
- 01-10淺談C/C++中的static與extern關(guān)鍵字的使用詳解
- 01-10深入C/C++浮點(diǎn)數(shù)在內(nèi)存中的存儲(chǔ)方式詳解


閱讀排行
- 1C語(yǔ)言 while語(yǔ)句的用法詳解
- 2java 實(shí)現(xiàn)簡(jiǎn)單圣誕樹(shù)的示例代碼(圣誕
- 3利用C語(yǔ)言實(shí)現(xiàn)“百馬百擔(dān)”問(wèn)題方法
- 4C語(yǔ)言中計(jì)算正弦的相關(guān)函數(shù)總結(jié)
- 5c語(yǔ)言計(jì)算三角形面積代碼
- 6什么是 WSH(腳本宿主)的詳細(xì)解釋
- 7C++ 中隨機(jī)函數(shù)random函數(shù)的使用方法
- 8正則表達(dá)式匹配各種特殊字符
- 9C語(yǔ)言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
- 10C語(yǔ)言查找數(shù)組里數(shù)字重復(fù)次數(shù)的方法
本欄相關(guān)
- 04-02c語(yǔ)言函數(shù)調(diào)用后清空內(nèi)存 c語(yǔ)言調(diào)用
- 04-02func函數(shù)+在C語(yǔ)言 func函數(shù)在c語(yǔ)言中
- 04-02c語(yǔ)言的正則匹配函數(shù) c語(yǔ)言正則表達(dá)
- 04-02c語(yǔ)言用函數(shù)寫分段 用c語(yǔ)言表示分段
- 04-02c語(yǔ)言中對(duì)數(shù)函數(shù)的表達(dá)式 c語(yǔ)言中對(duì)
- 04-02c語(yǔ)言編寫函數(shù)冒泡排序 c語(yǔ)言冒泡排
- 04-02c語(yǔ)言沒(méi)有round函數(shù) round c語(yǔ)言
- 04-02c語(yǔ)言分段函數(shù)怎么求 用c語(yǔ)言求分段
- 04-02C語(yǔ)言中怎么打出三角函數(shù) c語(yǔ)言中怎
- 04-02c語(yǔ)言調(diào)用函數(shù)求fibo C語(yǔ)言調(diào)用函數(shù)求
隨機(jī)閱讀
- 08-05dedecms(織夢(mèng))副欄目數(shù)量限制代碼修改
- 01-10delphi制作wav文件的方法
- 04-02jquery與jsp,用jquery
- 01-10使用C語(yǔ)言求解撲克牌的順子及n個(gè)骰子
- 01-11Mac OSX 打開(kāi)原生自帶讀寫NTFS功能(圖文
- 08-05織夢(mèng)dedecms什么時(shí)候用欄目交叉功能?
- 01-10SublimeText編譯C開(kāi)發(fā)環(huán)境設(shè)置
- 01-10C#中split用法實(shí)例總結(jié)
- 01-11ajax實(shí)現(xiàn)頁(yè)面的局部加載
- 08-05DEDE織夢(mèng)data目錄下的sessions文件夾有什