探解c++多態

對c++多態的探解
什麼是多態呢?請看如下程序

例1
class Base
{
public :
     virtual void func()=0;
};

class Drive1 : public Base
{
     public :
     virtual void func()
     {
          cout<<"Drive1::func"<<endl;
     }

};

class Drive2 : public Base
{
public :
     virtual void func()
     {
        cout<<"Drive2::func"<<endl;
     }
};

int main(int argc, char **argv)
{
     int i;
     Base *p[1];
     p[0] = new Drive1();
     p[1] = new Drive2();
     for(i = 0; i < 2; i++)
     {
        p[i]->func();
     }
     return 0;
}
//output
Drive1::func
Drive2::func
這就是多態。 c++中的多態通常是用虛函數實現的,但也有中template技術實現的,ATL中就是用template的技術實現了多態。就性能上說,用虛函數的方法,程序的性能會相對較差點。那麼編譯器到底悄悄做了什麼呢?請看小馬哥翻譯的 “ATL布幔之下的祕密”http://www.vckbase.com/document/viewdoc/?id=1350。完了再往下看。我們知道當類中有虛函數的時候,編譯器會偷偷給類加上一個vfptr指針,指針指向一個vtable,vtable中虛函數的地址。不信?請看vs給的圖。
有類:
class Foo
{
public :
virtual void func() {}
public :
   int a;
};

產生一個對象 Foo f


那麼定義一個Foo的指針會是什麼情況呢? 請看-> Foo *p

同樣,Foo類型的指針指向的內存塊也有vfptr和成員變量a,只是沒有”初始值“。所以可以猜想,當把派生類的指針賦給父類指針的時候,派生類的基類子對象裏的vfptr會賦值給基類指針的vfptr,從而實現了多態的行爲。

請看例1的程序,調試截圖。

那麼多重繼承的情況又是如何?考慮如下程序

#include <iostream>
using namespace std;

class Base1
{
public :
      virtual void func()=0;
};
class Base2
{
public :
      virtual void func()=0;
};

class Drive : public Base1, public Base2
{
public :
      virtual void func()
      {
            cout<<"Drive::func"<<endl;
      }
};

int main(int argc, char **argv)
{
     Base1 *p1 = new Drive;
       Base2 *p2 = new Drive;
      p1->func();
      p2->func();
      return 0;
}

多重繼承情況下,派生類的對象裏會有連個vfptr,排放的順序和繼承的順序相關。

當把派生類的指針賦值給p2的時候,好心的編譯器又會偷偷的加上些東西。由於派生類的Base2子對象的vfptr排在Base1子對象的vfpt的後邊,所以就會有一個偏移量--4個字節,(因爲指針是一個32的整數,4*8)。當Base2 *p2 = new Drive;時,new返回的指針會加上4再賦值給p2,編譯器都爲我們做好了。

看圖

裏邊的[thunk]:Drive::func`adjustor{4}`就爲4個字節的偏移量,thunk結構由編譯器維護。具體結構挺複雜,有待研究。

現在,相信你對c++會有新的認識了吧。c++的編譯器太好心了,總是偷偷的,默默無聞的爲我們操心。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章