青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

runsisi

  C++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
  45 隨筆 :: 15 文章 :: 26 評論 :: 0 Trackbacks

n久沒有寫過了,轉載一篇,呵呵。不喜歡轉載,但這篇文章確實還不錯,只是不知道為什么找不到原文出處。
以下為轉載全文。修改了一些細節。對cppblog崩潰了,這是啥所見即所得排版啊,唉,暈倒。

這幾天寫的程序應用到多繼承。

以前對多繼承的概念非常清晰,可是很久沒用就有點模糊了。重新研究一下,刷新下記憶。

假設我們有下面的代碼:

#include <stdio.h>

class A
{
private:
   char data;
public:
   A(){data = 'A';}
   virtual void Show(){printf("A\n");};
   virtual void DispA(){printf("a\n");};
};

class B
{
private:
   int data;
public:
   B(){data = 'B';}
   virtual void Show(){printf("B\n");};
   virtual void DispB(){printf("b\n");};
};

class C
{
private:
   char data;
public:
   C(){data = 'C';}
   virtual void Show(){printf("C\n");};
   virtual void DispC(){printf("c\n");};
};

class D : public A, public B, public C
{
public:
   char data;
public:
   D(){data = 'D';}
   virtual void Show(){printf("D\n");};
   virtual void DispD(){printf("d\n");};
};

class E : public D
{
private:
   char data;
public:
   E(){data = 'E';}
   virtual void Show(){printf("E\n");};
   virtual void DispE(){printf("e\n");};
};

int main()
{
   D *d = new D;
   A *a = (A*)d;
   B *b = (B*)d;
   C *c = (C*)d;;

   d->Show();
   a->Show();
   b->Show();

   a->DispA();
   b->DispB();
   d->DispD();

   D *d1 = (D*)a;
   d1->Show();
   d1->DispD();
   D *d2 = (D*)b;
   d2->Show();
   d2->DispD();

   char x = d->data;
   return 0;
}

每個類都有兩個虛擬函數Show()DispX()。類A,B,C是基本類,而D是多繼承,最后E又繼承了D。那么對于類E,它的內存映像是怎樣的呢?為了解答這個問題,我們回顧一下基本類的內存映像:

+ --------------+ <- this
+    VTAB       +
+ --------------+
+               +
+    Data       +
+               +
+ --------------+

如果一個類有虛擬函數,那么它就有虛函數表(VTAB)。類的第一個單元是一個指針,指向這個虛函數表。如果類沒有虛函數,并且它的祖先(所有父類)均沒有虛函數,那么它的內存映像和C的結構一樣。所謂虛函數表就是一個數組,每個單元指向一個虛函數地址。
如果類Y是類X的一個繼承,那么類Y的內存映像如下:

+ --------------+ <- this
+   Y
VTAB   +
+ --------------+
+               +
+   X
Data   +
+               +
+ --------------+
+               +
+   Y
Data   +
+               +
+ --------------+
Y
的虛函數表基本和X的相似。如果Y有新的虛函數,那么就在VTAB的末尾加上一個。如果Y重新定義了原有的虛函數,那么原的指針指向新的函數入口。這樣無論是內存印象和虛函數表,Y都和X兼容。這樣當執行 X* x = (Y*)y;之后,x可以很好的被運用,并且可以享受新的虛擬函數。

現在看多重繼承:
class D : public A, public B, public C
{
   ....
}
它的內存映像如下
:  
+ --+ -----------------+ 00H <- this
+   +    D
VTAB     +
+ A + -----------------+ 04H
+   +    A
的 數據
     +
+ --+ -----------------+ 08H
+   +    B
VTAB'    +
+ B + -----------------+ 0CH
+   +    B
的 數據
     +
+ --+ -----------------+ 10H
+   +    C
VTAB'    +
+ C + -----------------+ 14H
+   +    C
的 數據
     +
+ --+ -----------------+ 18H
+ D +    D
的 數據
     +
+ --+ -----------------+
(因為對齊于雙字,A~D的數據雖然只是一個char,但需要對齊到DWORD,所以占4字節)

對于A,它和單繼承沒有什么兩樣。BC被簡單地放在A的后面。如果它們虛函數在D中被重新定義過(比如Show函數),那么它們需要使用新的VTAB,使被重定義的虛函數指到正確的位置上(這對于COM或類似的技術是至關重要的)。最后,D的數據被放置到最后面。
對于E的內存映像問題就可以不說自明了。

下面我們看一下C++是如何處理
   D *d;
   ......
   B *b = (B*)d;
這樣的要求的。設置斷點,進入反匯編,你可以看到如下的匯編代碼:

B *b = (B*)d;
00401062  cmp         dword ptr [d],0
00401066  je          main+73h (401073h)
00401068  mov         eax,dword ptr [d]
0040106B  add         eax,8
0040106E  mov         dword ptr [ebp-38h],eax
00401071  jmp         main+7Ah (40107Ah)
00401073  mov         dword ptr [ebp-38h],0
0040107A  mov         ecx,dword ptr [ebp-38h]
0040107D  mov         dword ptr [b],ecx
從上述匯編代碼可以看出:如果源(這里是d)是NULL,那么目標(這里是b)也將被置為NULL,否則目標將指向源的地址并向下偏移8個字節,正好就是上圖所示BVTAB位置。至于為什么要用ebp-38h作緩存,這是編譯器的算法問題了。等以后有時間再研究。

接下來看一個比較古怪的問題,這個也是我寫這篇文章的初衷:
根據上面的多繼承定義,如果給出一個類B的實例b,我們是否可以求出D的實例?

為什么要問這個問題。因為存在下面的可能性:
class B
{
   ...
   virtual int GetTypeID()=0;
   ...
};

class D : public A, public B, public C
{
   ...
   virtual int GetTypeID(){return 0;};
   ...
};

class Z : public X, public Y, public B
{
   ...
   virtual int GetTypeID(){return 1;};
   ...
};

void MyFunc(B* b)
{
   int t = b->GetTypeID();
   switch(t)
   {
   case 0:
       DoSomething((D*)b); //
可能嗎?

       break;
   case 1:
       DoSomething((Z*)b); //
可能嗎?

       break;
   default:
       break;
   }
}

猛一看很值得懷疑。但仔細想想,這是可能的,事實也證明了這一點。因為編譯器了解這DB這兩個類相互之間的關系(也就是偏移量),因此它會做相應的轉換。同樣,設置斷點,查看匯編:
D *d2 = (D*)b;
00419992  cmp         dword ptr [b],0
00419996  je          main+196h (4199A6h)
00419998  mov         eax,dword ptr [b]
0041999B  sub         eax,8
0041999E  mov         dword ptr [ebp-13Ch],eax
004199A4  jmp         main+1A0h (4199B0h)
004199A6  mov         dword ptr [ebp-13Ch],0
004199B0  mov         ecx,dword ptr [ebp-13Ch]
004199B6  mov         dword ptr [d2],ecx
如果源(這里是b)為NULL,那么目標(這里是d2)也為NULL。否則目標取源的地址并向上偏移8個字節,這樣正好指向D的實例位置。同樣,為啥需要ebp-13Ch做緩存,待查。

前一段時間因為擔心.NET中將interface轉成相應的類會有問題。今天對C++多重繼承的復習徹底消除了疑云。

 

 

posted on 2010-09-08 14:14 runsisi 閱讀(214) 評論(0)  編輯 收藏 引用

只有注冊用戶登錄后才能發表評論。
網站導航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            一本色道久久综合| 亚洲免费在线精品一区| 久久综合激情| 在线观看视频一区| 欧美不卡三区| 欧美精品日本| 性欧美xxxx大乳国产app| 亚洲欧美偷拍卡通变态| 国产一区二区三区的电影 | 欧美日韩精品免费看| 日韩午夜电影av| 99精品视频免费| 国产伦精品免费视频| 久久久久久电影| 欧美成人在线网站| 亚洲一区影院| 久久久久9999亚洲精品| 亚洲黄一区二区三区| 日韩亚洲欧美成人一区| 国产欧美一区二区三区在线老狼 | 欧美国产一区视频在线观看| 欧美精品在线免费播放| 亚洲午夜精品17c| 久久国产综合精品| 一区二区三区波多野结衣在线观看| 日韩一区二区精品在线观看| 国产日韩欧美综合精品| 欧美激情无毛| 国产一区二区三区网站| 最新中文字幕一区二区三区| 国产精品激情偷乱一区二区∴| 久久久亚洲精品一区二区三区 | 久久亚洲精品视频| 亚洲一区二区av电影| 久久精品人人| 亚洲淫性视频| 欧美jizz19性欧美| 久久久国产精品一区二区三区| 欧美另类变人与禽xxxxx| 久久成人18免费网站| 欧美精品v日韩精品v国产精品| 久久嫩草精品久久久精品一 | 午夜精品久久久久久久男人的天堂 | 国产精品国内视频| 女人色偷偷aa久久天堂| 国产精品一级久久久| 亚洲韩日在线| 在线播放日韩专区| 午夜精品久久久久久久蜜桃app | 亚洲黄色一区二区三区| 国产在线乱码一区二区三区| 中文精品99久久国产香蕉| 亚洲另类自拍| 暖暖成人免费视频| 久久乐国产精品| 国产日韩精品视频一区| 亚洲香蕉视频| 亚洲欧美在线观看| 欧美性猛交99久久久久99按摩| 欧美激情一二区| 在线日韩一区二区| 久久精品女人的天堂av| 久久精品一二三| 国产欧美日韩综合一区在线观看 | 欧美一区二区三区播放老司机| 欧美日产一区二区三区在线观看| 免费成人在线观看视频| 国内精品国语自产拍在线观看| 亚洲曰本av电影| 午夜精品久久久久久久99热浪潮| 欧美视频在线不卡| 一本色道久久综合亚洲精品不卡| 99视频精品| 欧美日韩国产综合一区二区| 一本大道久久a久久综合婷婷| 中文久久精品| 国产精品一级二级三级| 欧美影院在线| 欧美国产精品一区| 亚洲卡通欧美制服中文| 欧美日韩系列| 午夜亚洲福利在线老司机| 久久久久久9| 在线成人激情黄色| 欧美1区2区3区| 99re视频这里只有精品| 小处雏高清一区二区三区 | 欧美高清视频一区二区三区在线观看 | 亚洲三级影院| 欧美色道久久88综合亚洲精品| 一区二区三区不卡视频在线观看| 亚洲男同1069视频| 国语精品中文字幕| 久久在线播放| 在线视频欧美精品| 久久久久久有精品国产| 亚洲激情视频网站| 国产精品av久久久久久麻豆网| 亚洲欧美成人一区二区三区| 久久综合亚洲社区| 一本色道久久88综合日韩精品| 国产精品xxxav免费视频| 性欧美长视频| 亚洲精品乱码视频| 欧美专区在线播放| 日韩视频―中文字幕| 国产综合亚洲精品一区二| 欧美成人午夜激情在线| 亚洲欧美文学| 亚洲精品三级| 男女精品视频| 欧美在线一二三区| 亚洲精品免费一区二区三区| 国产欧美激情| 欧美另类久久久品| 久久久久久九九九九| 国产精品99久久久久久久久| 免费欧美日韩国产三级电影| 亚洲视频一区二区| 亚洲国产成人在线播放| 国产精品嫩草99av在线| 欧美激情视频在线播放| 久久国产天堂福利天堂| 亚洲香蕉网站| 一区二区三区国产盗摄| 欧美韩日一区二区三区| 久久久久久九九九九| 午夜国产精品视频免费体验区| 日韩天堂在线观看| 亚洲国产高清在线观看视频| 国内精品久久久久久影视8| 欧美性做爰猛烈叫床潮| 欧美日韩成人一区二区| 欧美77777| 久久综合久久综合久久| 久久精品123| 先锋影音久久久| 亚洲嫩草精品久久| 亚洲视频福利| 亚洲一区二区三区精品在线| 亚洲最新在线视频| 一本色道久久综合亚洲精品不| 亚洲精品久久久久中文字幕欢迎你| 欧美韩日一区二区三区| 亚洲国产小视频在线观看| 亚洲成人在线免费| 欧美日韩激情小视频| 欧美成人xxx| 欧美成人一区二免费视频软件| 久久久伊人欧美| 久久婷婷一区| 久久亚洲精品中文字幕冲田杏梨| 欧美影院午夜播放| 久久精品在线| 麻豆精品在线播放| 欧美日本韩国一区二区三区| 欧美日韩第一区| 欧美另类视频| 国产精品成人一区二区三区吃奶| 欧美日韩三级视频| 国产精品男女猛烈高潮激情| 国产精品影片在线观看| 国产综合精品一区| 亚洲第一精品影视| 91久久精品美女| 一区二区三区**美女毛片| 亚洲免费在线看| 久久精品道一区二区三区| 久久尤物视频| 亚洲日本乱码在线观看| 亚洲图中文字幕| 久久久久91| 欧美日韩一区二区三区在线 | 国产精品啊啊啊| 国产一区久久| 亚洲精品一区二区在线| 亚洲自拍啪啪| 欧美插天视频在线播放| 亚洲欧洲精品成人久久奇米网| 亚洲一区二区三区影院| 久久性色av| 欧美视频你懂的| 极品尤物av久久免费看| 亚洲精品欧美日韩| 香蕉成人久久| 欧美国产精品人人做人人爱| 在线视频中文亚洲| 免费亚洲一区二区| 国产日韩精品电影| 夜夜夜精品看看| 噜噜噜在线观看免费视频日韩| 亚洲精品免费观看| 久久精品午夜| 国产精品爽爽ⅴa在线观看| 亚洲福利视频二区| 久久av资源网| 一区二区三区四区五区精品视频| 久久久久久噜噜噜久久久精品| 国产精品入口尤物| 日韩小视频在线观看|