午夜视频在线网站,日韩视频精品在线,中文字幕精品一区二区三区在线,在线播放精品,1024你懂我懂的旧版人,欧美日韩一级黄色片,一区二区三区在线观看视频

分享

淺析C++中的this指針 - 數(shù)組指針 - 龍行天下

 jijo 2009-06-23
淺析C++中的this指針
 
    有下面的一個(gè)簡(jiǎn)單的類:
class CNullPointCall
{
public:
    
static void Test1();
    
void Test2();
    
void Test3(int iTest);
    
void Test4();

private:
    
static int m_iStatic;
    
int m_iTest;
};

int CNullPointCall::m_iStatic = 0;

void CNullPointCall::Test1()
{
    cout 
<< m_iStatic << endl;
}

void CNullPointCall::Test2()
{
    cout 
<< "Very Cool!" << endl; 
}

void CNullPointCall::Test3(int iTest)
{
    cout 
<< iTest << endl; 
}

void CNullPointCall::Test4()
{
    cout 
<< m_iTest << endl; 
}
    那么下面的代碼都正確嗎?都會(huì)輸出什么?
CNullPointCall *pNull = NULL; // 沒(méi)錯(cuò),就是給指針賦值為空
pNull->Test1(); // call 1
pNull->Test2(); // call 2
pNull->Test3(13); // call 3
pNull->Test4(); // call 4
    你肯定會(huì)很奇怪我為什么這么問(wèn)。一個(gè)值為NULL的指針怎么可以用來(lái)調(diào)用類的成員函數(shù)呢?!可是實(shí)事卻很讓人吃驚:除了call 4那行代碼以外,其余3個(gè)類成員函數(shù)的調(diào)用都是成功的,都能正確的輸出結(jié)果,而且包含這3行代碼的程序能非常好的運(yùn)行。
    經(jīng)過(guò)細(xì)心的比較就可以發(fā)現(xiàn),call 4那行代碼跟其他3行代碼的本質(zhì)區(qū)別:類CNullPointCall的成員函數(shù)中用到了this指針。
    對(duì)于類成員函數(shù)而言,并不是一個(gè)對(duì)象對(duì)應(yīng)一個(gè)單獨(dú)的成員函數(shù)體,而是此類的所有對(duì)象共用這個(gè)成員函數(shù)體。 當(dāng)程序被編譯之后,此成員函數(shù)地址即已確定。而成員函數(shù)之所以能把屬于此類的各個(gè)對(duì)象的數(shù)據(jù)區(qū)別開(kāi), 就是靠這個(gè)this指針。函數(shù)體內(nèi)所有對(duì)類數(shù)據(jù)成員的訪問(wèn), 都會(huì)被轉(zhuǎn)化為this->數(shù)據(jù)成員的方式。
    而一個(gè)對(duì)象的this指針并不是對(duì)象本身的一部分,不會(huì)影響sizeof(“對(duì)象”)的結(jié)果。this作用域是在類內(nèi)部,當(dāng)在類的非靜態(tài)成員函數(shù)中訪問(wèn)類的非靜態(tài)成員的時(shí)候,編譯器會(huì)自動(dòng)將對(duì)象本身的地址作為一個(gè)隱含參數(shù)傳遞給函數(shù)。也就是說(shuō),即使你沒(méi)有寫(xiě)上this指針,編譯器在編譯的時(shí)候也是加上this的,它作為非靜態(tài)成員函數(shù)的隱含形參,對(duì)各成員的訪問(wèn)均通過(guò)this進(jìn)行。
    對(duì)于上面的例子來(lái)說(shuō),this的值也就是pNull的值。也就是說(shuō)this的值為NULL。而Test1()是靜態(tài)函數(shù),編譯器不會(huì)給它傳遞this指針,所以call 1那行代碼可以正確調(diào)用(這里相當(dāng)于CNullPointCall::Test1());對(duì)于Test2()和Test3()兩個(gè)成員函數(shù),雖然編譯器會(huì)給這兩個(gè)函數(shù)傳遞this指針,但是它們并沒(méi)有通過(guò)this指針來(lái)訪問(wèn)類的成員變量,因此call 2和call 3兩行代碼可以正確調(diào)用;而對(duì)于成員函數(shù)Test4()要訪問(wèn)類的成員變量,因此要使用this指針,這個(gè)時(shí)候發(fā)現(xiàn)this指針的值為NULL,就會(huì)造成程序的崩潰。   
    其實(shí),我們可以想象編譯器把Test4()轉(zhuǎn)換成如下的形式:
void CNullPointCall::Test4(CNullPointCall *this)
{
    cout 
<< this->m_iTest << endl; 
}
    而把call 4那行代碼轉(zhuǎn)換成了下面的形式:
CNullPointCall::Test4(pNull);
    所以會(huì)在通過(guò)this指針訪問(wèn)m_iTest的時(shí)候造成程序的崩潰。
    下面通過(guò)查看上面代碼用VC 2005編譯后的匯編代碼來(lái)詳細(xì)解釋一下神奇的this指針。
    上面的C++代碼編譯生成的匯編代碼是下面的形式:
    CNullPointCall *pNull = NULL;
0041171E  mov         dword ptr [pNull],
0 
    pNull
->Test1();
00411725  call        CNullPointCall::Test1 (411069h) 
    pNull
->Test2();
0041172A  mov         ecx,dword ptr [pNull] 
0041172D  call        CNullPointCall::Test2 (4111E0h) 
    pNull
->Test3(13);
00411732  push        0Dh  
00411734  mov         ecx,dword ptr [pNull] 
00411737  call        CNullPointCall::Test3 (41105Ah) 
    pNull
->Test4();
0041173C  mov         ecx,dword ptr [pNull] 
0041173F  call        CNullPointCall::Test4 (411032h) 
    通過(guò)比較靜態(tài)函數(shù)Test1()和其他3個(gè)非靜態(tài)函數(shù)調(diào)用所生成的的匯編代碼可以看出:非靜態(tài)函數(shù)調(diào)用之前都會(huì)把指向?qū)ο蟮闹羔榩Null(也就是this指針)放到ecx寄存器中(mov ecx,dword ptr [pNull])。這就是this指針的特殊之處。看call 3那行C++代碼的匯編代碼就可以看到this指針跟一般的函數(shù)參數(shù)的區(qū)別:一般的函數(shù)參數(shù)是直接壓入棧中(push 0Dh),而this指針卻被放到了ecx寄存器中。在類的非成員函數(shù)中如果要用到類的成員變量,就可以通過(guò)訪問(wèn)ecx寄存器來(lái)得到指向?qū)ο蟮膖his指針,然后再通過(guò)this指針加上成員變量的偏移量來(lái)找到相應(yīng)的成員變量。
    下面再通過(guò)另外一個(gè)例子來(lái)說(shuō)明this指針是怎樣被傳遞到成員函數(shù)中和如何使用this來(lái)訪問(wèn)成員變量的。
    依然是一個(gè)很簡(jiǎn)單的類:
class CTest
{
public:
    
void SetValue();

private:
    
int m_iValue1;
    
int m_iValue2;
};

void CTest::SetValue()
{
    m_iValue1 
= 13;
    m_iValue2 
= 13;
}
    用如下的代碼調(diào)用成員函數(shù):
CTest test;
test.SetValue();
    上面的C++代碼的匯編代碼為:
    CTest test;
    test.SetValue();
004117DC  lea         ecx,[test] 
004117DF  call        CTest::SetValue (4111CCh) 
    同樣的,首先把指向?qū)ο蟮闹羔樂(lè)诺絜cx寄存器中;然后調(diào)用類CTest的成員函數(shù)SetValue()。地址4111CCh那里存放的其實(shí)就是一個(gè)轉(zhuǎn)跳指令,轉(zhuǎn)跳到成員函數(shù)SetValue()內(nèi)部。
004111CC  jmp         CTest::SetValue (411750h)
    而411750h才是類CTest的成員函數(shù)SetValue()的地址。
void CTest::SetValue()
{
00411750  push        ebp  
00411751  mov         ebp,esp 
00411753  sub         esp,0CCh 
00411759  push        ebx  
0041175A  push        esi  
0041175B  push        edi  
0041175C  push        ecx
// 1   
0041175D  lea         edi,[ebp-0CCh] 
00411763  mov         ecx,33h 
00411768  mov         eax,0CCCCCCCCh 
0041176D  rep stos    dword ptr es:[edi] 
0041176F  pop         ecx
// 2 
00411770  mov         dword ptr [ebp-8],ecx // 3
    m_iValue1 = 13;
00411773  mov         eax,dword ptr [this] // 4
00411776  mov         dword ptr [eax],0Dh // 5
    m_iValue2 = 13;
0041177C  mov         eax,dword ptr [
this] // 6
0041177F  mov         dword ptr [eax+4],0Dh // 7
}
00411786  pop         edi  
00411787  pop         esi  
00411788  pop         ebx  
00411789  mov         esp,ebp 
0041178B  pop         ebp  
0041178C  ret 
    下面對(duì)上面的匯編代碼中的重點(diǎn)行進(jìn)行分析:
    1、將ecx寄存器中的值壓棧,也就是把this指針壓棧。
    2、ecx寄存器出棧,也就是this指針出棧。
    3、將ecx的值放到指定的地方,也就是this指針?lè)诺絒ebp-8]內(nèi)。
    4、取this指針的值放入eax寄存器內(nèi)。此時(shí),this指針指向test對(duì)象,test對(duì)象只有兩個(gè)int型的成員變量,在test對(duì)象內(nèi)存中連續(xù)存放,也就是說(shuō)this指針目前指向m_iValue1。
    5、給寄存器eax指向的地址賦值0Dh(十六進(jìn)制的13)。其實(shí)就是給成員變量m_iValue1賦值13。
    6、同4。
    7、給寄存器eax指向的地址加4的地址賦值。在4中已經(jīng)說(shuō)明,eax寄存器內(nèi)存放的是this指針,而this指針指向連續(xù)存放的int型的成員變量m_iValue1。this指針加4(sizeof(int))也就是成員變量m_iValue2的地址。因此這一行就是給成員變量m_iValue2賦值。
    通過(guò)上面的分析,我們可以從底層了解了C++中this指針的實(shí)現(xiàn)方法。雖然不同的編譯器會(huì)使用不同的處理方法,但是C++編譯器必須遵守C++標(biāo)準(zhǔn),因此對(duì)于this指針的實(shí)現(xiàn)應(yīng)該都是差不多的。
 
轉(zhuǎn)自:http://blog.csdn.net/starlee/archive/2008/01/24/2062586.aspx

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多