細談C++多態(tài)性的“動”與“靜”

字號:

在我們討論多態(tài)的時候,先看看什么是硬編碼和軟編碼:硬編碼就是把代碼寫死了,導(dǎo)致彈性不足,降低了可擴展性,例如在代碼里的
    if...else...;switch...case...
    這些代碼通常都屬于硬編碼,項目中的這些代碼多了,就相當于說明這個代碼的靈活性、擴展性、彈性等等的少了。
    所以,我們要盡量使用軟編碼,通俗點就是“別把話說死了,留點轉(zhuǎn)彎的余地”。多態(tài)性就是這種軟編碼特性的反映,下面我們一起來研究一下多態(tài)性。
    多態(tài)性是一種抽象,把事物的特征抽象出來,然后事物的具體形態(tài)我們就不關(guān)心了。
    例如對工人這種事物來說,他的特征就是工作,至于是什么工人,他做什么工作,我們就不用關(guān)心了,只要我們以“工人.工作”這種方式去調(diào)用。那他就會為我們工作了。
    那為什么我們不抽象出其他的特征,只抽象出工作這個特征呢?因為我們只對這個特征感興趣,他的什么吃飯、睡覺、如廁等的特性我們都不關(guān)心了。有了多態(tài),我們就可以實現(xiàn)軟編碼了!
    講解了多態(tài)的概念之后,我們來看看多態(tài)的實現(xiàn)(C++的實現(xiàn)):
    多態(tài)的實現(xiàn)是通過虛函數(shù)表(VTable),每個類如果有虛函數(shù),那它就有一個虛函數(shù)表,所有的對象都共享這一個VTable。這個概念也叫做動態(tài)聯(lián)編,還有靜態(tài)聯(lián)編,這些概念都是通過在程序執(zhí)行的時候表現(xiàn)出來的性質(zhì)來定的,我們下面會看看它的“動”和“靜”究竟體現(xiàn)在哪里。
    先看一段代碼:
    class C0
    ...{
    public:
    void Test()
    ...{
    cout << "call C0 Test()。" << endl;
    }
    };
    這個類沒有虛函數(shù),調(diào)用的時候就是靜態(tài)調(diào)用。調(diào)用的代碼如下:
    // 靜態(tài)編譯(早綁定 early binding)
    C0 *pO0;
    C0 obj0;
    pO0 = &obj0;
    pO0->Test();
    它的反匯編代碼如下:
    // 直接調(diào)用函數(shù)(已經(jīng)知道地址)
    00401432 mov ecx,dword ptr [ebp-0Ch]
    00401435 call @ILT+160(C0::Test) (004010a5)
    下面看看帶虛函數(shù)的類:
    class C1
    ...{
    public:
    virtual void Test()
    ...{
    cout << "call C1 Test()" << endl;
    }
    };
    class C11 : public C1
    ...{
    public:
    void Test()
    ...{
    cout << "call C11 Test()" << endl;
    }
    };
    它的調(diào)用:
    C11 obj11;
    C1 *pObj1;
    pObj1 = &obj11;
    // 這里生成的匯編代碼
    // 0040144A lea edx,[ebp-14h] // 尋址找到pObj1
    // 0040144D mov dword ptr [ebp-1Ch],edx
    pObj1->Test();
    // 這里生成的匯編代碼
    // 00401450 mov eax,dword ptr [ebp-1Ch] // 取得虛表地址
    // 00401453 mov edx,dword ptr [eax]
    // 00401455 mov esi,esp
    // 00401457 mov ecx,dword ptr [ebp-1Ch] // 根據(jù)虛表的位置來取得Test()函數(shù)
    // 0040145A call dword ptr [edx] // 調(diào)用Test()函數(shù)