亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C++ > 正文

C++ COM編程之接口背后的虛函數表

2020-05-23 14:21:08
字體:
來源:轉載
供稿:網友
這篇文章主要介紹了C++ COM編程之接口背后的虛函數表,COM的背后,就是接口,而接口的背后,就是虛函數表,需要的朋友可以參考下
 
 

前言

學習C++的人,肯定都知道多態機制;多態就是用父類型別的指針指向其子類的實例,然后通過父類的指針調用實際子類的成員函數。對于多態機制是如何實現的,你有沒有想過呢?而COM中的接口就將這一機制運用到了極致,所以,不知道多態機制的人,是永運無法明白COM的。所以,在總結COM時,是非常有必要專門總結一下C++的多態機制是如何實現的。

多態

什么是多態?上面也說了,多態就是用父類型別的指針指向其子類的實例,然后通過父類的指針調用實際子類的成員函數?,F在通過代碼,讓大家切身的體會一下多態:

復制代碼代碼如下:

#include <iostream>
using namespace std;
 
class A
{
public:
    void Print()
    {
        cout<<"I am A."<<endl;
    }
};
 
class B : public A
{
public:
    void Print()
    {
        cout<<"I am B."<<endl;
    }
};
 
int main()
{
    A *pAObj = new B();
    pAObj->Print();
}

 

上面代碼的運行結果是:I am A.這不是多態的行為。

好了,經過對上面代碼的改造,就在A類的Print函數前面加入關鍵字virtual,具體代碼如下:

復制代碼代碼如下:

#include <iostream>
using namespace std;
 
class A
{
public:
    virtual void Print()
    {
        cout<<"I am A."<<endl;
    }
};
 
class B : public A
{
public:
    void Print()
    {
        cout<<"I am B."<<endl;
    }
};
 
int main()
{
    A *pAObj = new B();
    pAObj->Print();
}

 

此時,代碼的運行結果為:I am B.這個時候就表現出來了多態行為。好了,多了我也不說了,就通過這個簡單的例子,你就能體會到多態的概念了。從下面才開始今天的主題。

虛函數表

多態機制的關鍵就是在于虛函數表,也就是vtbl。當我們定義一個類,類中包含虛函數時,其實也就定義了一張虛函數表,沒有虛函數的類是不包含虛函數表的,只有該類被實例化時,才會將這個表分配到這個實例的內存中;在這張虛函數表中,存放了每個虛函數的地址;它就像一個地圖一樣,指明了實際所應該調用的函數。比如我定義一個類,如下:

 

復制代碼代碼如下:

class CIF
{
public:
     CIF(){}
     CIF(int i, int f) : m_iVar(i), m_fVar(f){}
     virtual void IF1() { cout<<"I'm IF1"<<endl; }
     virtual void IF2() { cout<<"I'm IF2"<<endl; }
     virtual void IF3() { cout<<"I'm IF3"<<endl; }
     void MemFunc(){ cout<<"I'm IF4"<<endl; }
private:
     int m_iVar;
     float m_fVar;
};

 

這樣的一個類,當你去定義這個類的實例時,編譯器會給這個類分配一個成員變量,該變量指向這個虛函數表,這個虛函數表中的每一項都會記錄對應的虛函數的地址;如下圖:

C++ COM編程之接口背后的虛函數表

這個類的變量還沒有被初始化時,就像上圖那樣,變量的值都是隨機值,而指向虛擬函數表的指針__vfptr中對應的虛函數地址也是錯誤的地址;只有等我們真正的完成了這個變量的聲明和初始化時,這些值才能被正確的初始化,如下圖:

C++ COM編程之接口背后的虛函數表

從上圖中就可以看到,初始化完成以后,指向虛函數表的__vfptr指針中的元素都被賦予了正確的虛函數值,分別指向了在類中定義的三個虛函數。也看到了,__vfptr指針定義的位置也比m_iVar和m_fVar變量的位置靠前;在C++編譯器中,它保證虛函數表的指針存在于對象實例中最前面的位置,這主要是為了在多層繼承或是多重繼承的情況下,能以高性能取到這張虛函數表,然后進行遍歷,查找對應的虛函數指針,進行對應的調用。

我們都知道,虛函數是用來支持C++中的多態的,而單獨的一個類,有了虛函數,而沒有任何繼承關系,也就是說沒有子類去覆蓋父類的虛函數,這樣是毫無意義的。所以下面就要從各個方面進行詳細的說明虛函數表。

沒有實現多態的單繼承

比如有如下的繼承關系:

C++ COM編程之接口背后的虛函數表

在這個繼承關系中,CIF2作為CIF1的子類,但是CIF2沒有重寫CIF1類的任何虛函數;定義CIF2 if2Obj;實例,在派生類的實例中,它的虛函數表應該是像下面這樣的:

復制代碼代碼如下:

[0]     0x011513c5 {InterfaceDemo2.exe!CIF1::IF1(void)}     void * 
[1]     0x011512cb {InterfaceDemo2.exe!CIF1::IF2(void)}     void * 
[2]     0x01151343 {InterfaceDemo2.exe!CIF1::IF3(void)}     void * 
[3]     0x01151249 {InterfaceDemo2.exe!CIF2::IF4(void)}     void * 
[4]     0x01151433 {InterfaceDemo2.exe!CIF2::IF5(void)}     void * 
[5]     0x01151267 {InterfaceDemo2.exe!CIF2::IF6(void)}     void * 
[6]     0x00000000     void *

 

可以發現,虛函數按照其聲明順序存放在表中,父類的虛函數在子類的虛函數前面。

實現多態的單繼承

現在我在CIF2類中,重寫CIF1類的IF1函數,它們的關系如下:

C++ COM編程之接口背后的虛函數表

在上圖中,CIF2繼承了CIF1,并且在CIF2類中重寫了CIF1的虛函數IF1,那我們現在看看虛函數表是什么樣子的?

 

復制代碼代碼如下:

[0]     0x00b61311 {InterfaceDemo2.exe!CIF2::IF1(void)}     void * 
[1]     0x00b612c6 {InterfaceDemo2.exe!CIF1::IF2(void)}     void * 
[2]     0x00b61343 {InterfaceDemo2.exe!CIF1::IF3(void)}     void * 
[3]     0x00b61249 {InterfaceDemo2.exe!CIF2::IF4(void)}     void * 
[4]     0x00b61433 {InterfaceDemo2.exe!CIF2::IF5(void)}     void *
[5]     0x00000000     void *

 

你發現了什么?虛函數表中的第一項是CIF2::IF1,而不是CIF1::IF1,這說明了當在子類中重寫父類的虛函數時,新的函數的地址覆蓋了父類的虛函數地址,這樣就能在多態時能正確的找到需要被調用的函數;而沒有被覆蓋的函數還是那樣的順序在虛函數表中存儲著。

沒有實現多態的多繼承

對于簡單的,沒有實現多態的多繼承,比如,有下面的一個多繼承關系:

C++ COM編程之接口背后的虛函數表

在子類中沒有重寫任何父類的虛函數,那么它的虛函數表應該是什么樣子呢?

虛函數表CIF1,如下:

復制代碼代碼如下:

[0]     0x001e13d9 {InterfaceDemo2.exe!CIF1::IF1(void)}     void * 
[1]     0x001e12df {InterfaceDemo2.exe!CIF1::IF2(void)}     void * 
[2]     0x001e1357 {InterfaceDemo2.exe!CIF1::IF3(void)}     void * 
[3]     0x001e10c8 {InterfaceDemo2.exe!CIF3::IF4(void)}     void * 
[4]     0x001e1041 {InterfaceDemo2.exe!CIF3::IF5(void)}     void * 
[5]     0x001e1249 {InterfaceDemo2.exe!CIF3::IF6(void)}     void * 
[6]     0x00000000     void *

 

虛函數表CIF2,如下:

 

復制代碼代碼如下:

[0]     0x001e1258 {InterfaceDemo2.exe!CIF2::IF7(void)}     void * 
[1]     0x001e1447 {InterfaceDemo2.exe!CIF2::IF8(void)}     void * 
[2]     0x001e127b {InterfaceDemo2.exe!CIF2::IF9(void)}     void * 
[3]     0x00000000     void *

 

從上面的虛函數表,我們可以分析出來,每個父類都有自己的虛函數表,子類的虛函數被放到了第一個父類的表中。第一個父類是按照聲明順序來判斷的。

實現多態的多繼承

上面說的是沒有發生重寫的情況,現在來說說發生重寫的情況;比如,現在有以下情況:

C++ COM編程之接口背后的虛函數表

在子類中重寫了父類的虛函數,那它的虛函數表又是什么樣子呢?

虛函數表CIF1,如下:

 

復制代碼代碼如下:

[0]     0x012013cf {InterfaceDemo2.exe!CIF3::IF1(void)}     void * 
[1]     0x012012d5 {InterfaceDemo2.exe!CIF1::IF2(void)}     void * 
[2]     0x0120134d {InterfaceDemo2.exe!CIF1::IF3(void)}     void * 
[3]     0x01201456 {InterfaceDemo2.exe!CIF3::IF4(void)}     void * 
[4]     0x012014d8 {InterfaceDemo2.exe!CIF3::IF5(void)}     void * 
[5]     0x00000000     void *

 

虛函數表CIF2,如下:

 

復制代碼代碼如下:

[0]     0x012014e2 {InterfaceDemo2.exe![thunk]:CIF3::IF1`adjustor{4}' (void)}     void * 
[1]     0x012014ce {InterfaceDemo2.exe!CIF2::IF2(void)}     void * 
[2]     0x012014d3 {InterfaceDemo2.exe!CIF2::IF3(void)}     void * 
[3]     0x00000000     void *

 

從上面的虛函數表中,我們可以看到虛函數表中的CIF1::IF1(void)全都被替換成了CIF3::IF1(void),那么我們就可以以任意的父類指針來調用IF1(void),實際上調用的是CIF3::IF1(void),這就實現了所謂的多態。

總結

總結了這么多關于虛函數表的內容,感覺很扯,和接口沒有多大的關系;但是,這一切都是COM的基礎,COM的背后,就是接口,而接口的背后,就是我這里總結的,說白了,完全了解了這里,對于理解COM的接口是有非常大的用處的。希望我的總結對大家有用。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
一区二区亚洲精品国产| 欧美日本啪啪无遮挡网站| 欧美大尺度电影在线观看| 欧美亚洲视频一区二区| 日韩欧美精品在线观看| 在线电影中文日韩| 日韩精品极品毛片系列视频| 久久成人国产精品| 久久天天躁狠狠躁老女人| 亚洲欧洲日本专区| 亚洲欧美国内爽妇网| 在线成人免费网站| 日韩激情av在线免费观看| 国产成人午夜视频网址| 日韩人在线观看| 国产精品网站入口| 国产亚洲美女精品久久久| 4438全国亚洲精品在线观看视频| 欧美精品少妇videofree| 国产区精品在线观看| 国产日韩在线一区| 亚洲自拍偷拍第一页| 日本精品一区二区三区在线播放视频| 久久香蕉国产线看观看网| 国产精品久久久久7777婷婷| 亚洲精品视频播放| 最近更新的2019中文字幕| 久久韩剧网电视剧| 91精品久久久久久久久久久久久久| 色偷偷亚洲男人天堂| 秋霞成人午夜鲁丝一区二区三区| 亚洲最新av在线网站| 午夜精品久久久久久久99热浪潮| 国产性猛交xxxx免费看久久| 欧美性xxxx极品hd满灌| 91精品久久久久久久久不口人| 国产国语刺激对白av不卡| 91av视频在线播放| 国产在线视频2019最新视频| 2021久久精品国产99国产精品| 欧美天天综合色影久久精品| 国产在线精品播放| 日本精品免费观看| 国产精品羞羞答答| 国产精品夫妻激情| 亚洲香蕉在线观看| 国产精品第一第二| 成人黄色在线播放| 欧美一区第一页| 久久国产精品久久久久久| 日韩在线一区二区三区免费视频| 日韩精品在线影院| 国内精品久久久久久久久| 成人精品网站在线观看| 91精品在线播放| 国产精品丝袜久久久久久高清| 欧美疯狂性受xxxxx另类| 日韩免费在线视频| 欧美成人中文字幕| 日韩欧美亚洲国产一区| 亚洲欧美中文日韩v在线观看| 日本高清不卡在线| 国产一区二区丝袜| 国产精品自拍偷拍视频| 精品久久在线播放| 国产精品黄色影片导航在线观看| 日韩美女av在线| 日韩午夜在线视频| 亚洲国产精品字幕| 亚洲男人的天堂网站| 日韩国产精品视频| 5566日本婷婷色中文字幕97| 欧美一级视频在线观看| 亚洲人在线视频| 91大神在线播放精品| 欧美日韩爱爱视频| 亚洲春色另类小说| 久久人人爽人人爽爽久久| 欧美日韩国产综合视频在线观看中文| 亚洲欧美日韩成人| 欧美精品www| 亚洲级视频在线观看免费1级| 国产一区深夜福利| 欧美亚洲激情在线| 欧美日韩福利在线观看| 日韩va亚洲va欧洲va国产| 日韩国产一区三区| 欧美一级大片在线观看| 欧美老女人在线视频| 亚洲欧美另类国产| 久久久999国产| www.久久久久久.com| 国产成人在线一区二区| 日韩中文综合网| 欧美夫妻性生活xx| 国产精品视频白浆免费视频| 欧美精品情趣视频| 精品国内自产拍在线观看| 欧美大学生性色视频| 亚洲国产精品久久精品怡红院| 欧美老女人bb| 国内精品久久久久久影视8| 日本久久中文字幕| 亚洲国产成人久久综合一区| 国产日韩欧美电影在线观看| 日韩精品视频在线观看网址| 国产精品都在这里| 亚洲国产精品成人精品| 欧美精品一本久久男人的天堂| 97香蕉久久超级碰碰高清版| 国产不卡视频在线| 日韩电影在线观看永久视频免费网站| 日韩成人中文字幕在线观看| 久久久久久久激情视频| 国产成人精品免高潮在线观看| 国产精品香蕉在线观看| 一级做a爰片久久毛片美女图片| 日韩欧美精品中文字幕| 98精品在线视频| 日韩免费在线观看视频| 亚洲男人天堂手机在线| 欧美黄色片在线观看| 亚洲网站在线观看| 国产欧美日韩精品专区| 日日摸夜夜添一区| 亚洲最大福利网站| 日韩欧美在线视频日韩欧美在线视频| 一本色道久久综合狠狠躁篇怎么玩| 亚洲欧美日韩国产中文| 国产精品久久久久久亚洲调教| 久久精品这里热有精品| 亚洲一区二区三区视频| 欧美成年人视频网站| 欧美激情伊人电影| 91久久综合亚洲鲁鲁五月天| 中文字幕亚洲综合久久| 成人免费直播live| 欧美日韩国产一区在线| 在线看国产精品| 亚洲成人网av| 亚洲第一区在线观看| 综合激情国产一区| 热门国产精品亚洲第一区在线| 一本色道久久综合狠狠躁篇的优点| 日本高清不卡的在线| 国产aaa精品| 亚洲自拍偷拍在线| 国产亚洲精品91在线| 一区二区三区视频免费| 国产伦精品免费视频| 日韩精品免费综合视频在线播放| 久久国产精品99国产精| 国模精品系列视频| 久久色免费在线视频| 亚洲欧洲偷拍精品| 亚洲精品美女久久久| 欧美激情啊啊啊| 亚洲精品国产精品自产a区红杏吧| 97香蕉超级碰碰久久免费软件| 欧美一区二区三区免费观看| 欧美日韩久久久久| 欧美激情精品久久久久久大尺度| 精品一区精品二区| 亚洲一级免费视频|