c 的this指標與空指標類成員函式訪問

2021-07-05 17:53:57 字數 2507 閱讀 5952

我們知道,在c++的非靜態成員函式中,有乙個隱含的引數,即this指標,利用它,我們可以訪問相應物件的資料成員,那麼究竟this指標是如何作用的呢?下面先來看乙個例子。有下面的乙個簡單的類:

[cpp]view plain

copy

class cnullpointcall  

;  int cnullpointcall::m_istatic = 0;  

void cnullpointcall::test1()  

void cnullpointcall::test2()  

void cnullpointcall::test3(int itest)  

void cnullpointcall::test4()    

那麼下面的**都正確嗎?都會輸出什麼?

[cpp]view plain

copy

cnullpointcall *pnull = null; // 沒錯,就是給指標賦值為空

pnull->test1(); // call 1

pnull->test2(); // call 2

pnull->test3(13); // call 3

pnull->test4(); // call 4

你肯定會很奇怪我為什麼這麼問。乙個值為null的指標怎麼可以用來呼叫類的成員函式呢?!可是實事卻很讓人吃驚:除了call 4那行**以外,其餘3個類成員函式的呼叫都是成功的,都能正確的輸出結果,而且包含這3行**的程式能非常好的執行。經過細心的比較就可以發現,call 4那行**跟其他3行**的本質區別:類cnullpointcall的成員函式中用到了this指標。

在編繹階段,當遇到通過指標呼叫成員函式時,編繹器會首先檢查該成員函式是否為虛函式,如果不是(是虛函式的情況待會兒再講),編繹器會再此插入一些實現**,它會在函式呼叫之前,首先將物件的首位址放入到ecx暫存器中,然後才是函式呼叫的語句(注意,不同的編繹器在this指標的實現上可能會有所區別,但是c++編譯器必須遵守c++標準,因此對於this指標的實現應該都是差不多的)。在我們這個程式中物件的首位址就是null,由於前三個函式並沒有使用到時this指標,所以自然不會出問題,而對於test4,由於要訪問m_itest資料成員,程式將從ecx暫存器中取出物件的首位址,也就是null,然後再通過null訪問m_itest資料成員,這才是出問題的原因。

了解了這一點後,我們再來看呼叫函式為虛函式的情況。要了解這一情況發生時的機理,我們必需首先了解虛表的概念。c++中的虛函式的作用主要是實現了多型的機制,而這一機制的實現靠的就是虛表,簡稱為v-table。在這個表中,主是要乙個類的虛函式的位址表,這張表解決了繼承、覆蓋的問題,保證其容真實反應實際的函式。對於含有虛函式的類,它的每個物件分配的記憶體空間的最前端就儲存有指向該類的虛表的位址。如下圖所示:

為了更好的理解它,我們來看乙個比較奇怪的例子。

假設我們有這樣的乙個類:

[cpp]view plain

copy

class a      

virtual

void fun1()      

virtual

void fun2()      

virtual

void fun3()      

private:  

int d;  

};  

按照上面的說法,我們可以通過a的例項來得到虛函式表。 下面是實際例程:

[cpp]view plain

copy

typedef

void (*func)();  

int main(int argc, char** argv)   

在這個例項裡面,fs實際上就指向了虛表的首位址,我們可以把它想象成乙個陣列,這樣就可以對虛函式進行呼叫了,而且這一方法還可以繞過它對訪問修飾的限制,即使是私有虛函式,我們也可以照呼叫不誤。

關於虛表就說到這裡,下面還是回到對通過指標呼叫的函式是虛函式的討論中來。這在種情況下,編繹器插入的**完成的功能大概如下:還是首先將物件的首位址放到ecx暫存器中,然後插入函式呼叫的**,只不過這裡不再是乙個簡單的函式首位址完事,它會插入一些**通過前面提到的虛表機制找尋真正要呼叫的函式的入口位址。

在上乙個例子中,如果我們呼叫fs[2]()函式會怎麼樣呢?因為我們是直接通過虛表呼叫的成員函式,所以它沒有事先將物件的首位址放到ecx暫存器中,而該成員函式是會通過exc暫存器中儲存的原先的值去訪問資料成員d的,那麼它輸出的就將是乙個沒有意義的隨機值罷了。

通過以上對this指標以及虛表的討論,回想c++中關於成員函式指標的使用,我們就可以理解它到底和普通的函式指標有何不同了,一切都是this指標的緣故,通過成員指標呼叫函式會事先將物件的首位址放到ecx暫存器中,這也就是它們的根本區別所在。

**c++中的this指標

c++ 虛函式表解析

C 類成員指標

類成員指標 1.成員指標式可以指向類的非靜態成員的指標。類的靜態成員不屬於任何物件,因此無需特殊的指向靜態成員的指標。指向靜態成員的指標的普通指標沒有任何區別。2.當初始化乙個類成員指標時,我們令其指向類的成員,但不指定代成員所屬的物件,直到使用到成員指標時,才提供所屬的物件。3.資料成員指標 例 ...

C 類成員指標

首先讓我們看一下,乙個簡單的成員變數指標 和 成員函式指標的使用例子。struct a int a pi a i void a pfoo a foo a a a.pi 1 等同於 a.i 1 a.pfoo 等價於 a.foo 在vc 下,輸出 a i 和 a foo 的值,你會發現他們的值都為1 在...

C 類成員指標

類成員指標時指可以指向類的非靜態成員的指標,一般情況下,乙個指標指向乙個物件,但是成員指標指示的是類的成員,而非類的物件。指向類的靜態成員的指標和普通指標沒有什麼區別。與普通指標不同的是,類資料成員指標必須在 前新增classname 以表示當前定義的指標可以指向classname的成員。class...