1. 程式人生 > >多型物件模型

多型物件模型

1.多型相關概念及使用時需要注意問題。

C++中類的繼承中有多型性的概念,所謂的多型就是在類裡使用虛擬函式後,用父類作為物件指標,來正確的呼叫不同子類或父類來作為相應虛擬函式。虛基類實際就是繼承時使用virtual關鍵字來定義,為的是讓在多重繼承時遇到相同的基類時只保留一份,以確定其使用那個類。

2.多型原理。

 當使用基類的指標或引用呼叫重寫的虛擬函式時,當指向父類呼叫的就是父類的虛擬函式,指向子類呼叫的就是子類的虛擬函式

3.什麼是動態聯編,什麼靜態兩邊。

動態聯編 和 靜態聯編 都是多型性的一種體現

聯編是指一個計算機程式自身彼此關聯的過程,在這個聯編過程中,需要確定程式中的操作呼叫(函式呼叫)與執行該操作(函式)的程式碼段之間的對映關係;按照聯編所進行的階段不同,可分為靜態聯編和動態聯編;

靜態聯編:
是指聯編工作是在程式編譯連線階段進行的,這種聯編又稱為早期聯編;因為這種聯編是在程式開始執行之前完成的;

在程式編譯階段進行的這種聯編又稱靜態束定;在編譯時就解決了程式中的操作呼叫與執行該操作程式碼間的關係,確定這種關係又被稱為束定;編譯時束定又稱為靜態束定;

動態聯編:
編譯程式在編譯階段並不能確切地知道將要呼叫的函式,只有在程式執行時才能確定將要呼叫的函式,為此要確切地知道將要呼叫的函式,要求聯編工作在程式執行時進行,這種在程式執行時進行的聯編工作被稱為動態聯編,或動態束定,又叫晚期聯編;C++規定:動態聯編是在虛擬函式的支援下實現的;

4.單繼承/多繼承/菱形繼承/菱形虛擬繼承。多型場景下物件模型

單繼承:當子類與父類構成多型時,子類繼承父類的虛表之後,子類虛表裡虛擬函式在記憶體裡的儲存情況

多繼承:

當一個子類繼承多個父類時構成多繼承,此時子類會繼承這些父類的虛表,子類虛表裡虛擬函式在記憶體裡的儲存情況。

菱形繼承:

class A  
{  
public:  
    virtual void f1()  
    {  
        cout<<"A::f1()"<<endl;  
    }  
    virtual void f2()  
    {  
        cout<<"A::f2()"<<endl;  
    }  
public:  
    int _a;  
};  


class B:public A  
{  
public:  
    virtual void f1()  
    {  
        cout<<"B::f1()"<<endl;  
    }  
    virtual void f3()  
    {  
        cout<<"B::f3()"<<endl;  
    }  
public:  
    int _b;  


};  


class C:public A  
{  
public:  
    virtual void f1()  
    {  
        cout<<"C::f1()"<<endl;  
    }  
    virtual void f4()  
    {  
        cout<<"C::f4()"<<endl;  
    }  
public:  
    int _c;  
};  


class D:public B,public C  
{  
public:  
    virtual void f1()  
    {  
        cout<<"D::f1()"<<endl;  
    }  
    virtual void f5()  
    {  
        cout<<"D::f5()"<<endl;  
    }  
public:  
    int _d;  
};  


//列印虛擬函式表  
typedef void(*V_FUNC)();  


void PrintVtable(int* vtable)  
{  
    printf("vtable:%p\n",vtable);  
    int** pvtable=(int**)vtable;  
    for(size_t i=0; pvtable[i]!=0;i++)  
    {  
        printf("vtable[%u]:0x%p->",i,pvtable[i]);  
        V_FUNC f=(V_FUNC)pvtable[i];  
        f();  
    }  
    cout<<"------------------------------------\n";  
}  


void test()  
{  
    D d;  
    d.B::_a=5;  
    d.C::_a=6;  
    d._b=1;  
    d._c=2;  
    d._d=3;  
    PrintVtable(*(int**)&d);  
    PrintVtable(*(int**)((char*)&d+sizeof(B)));  
}  
int main()  
{  
    test();  
    return 0;  

}  

在普通的菱形繼承中,處於最先的D型別的物件d,它繼承了B,C,並且B,C中分別儲存了一份來自繼承A的變數;除此之外,B,C還存了虛表指標,通過它可以找到虛表中存的虛擬函式地址,最後,d物件還存放了自己定義的變數和繼承B,C自己定義的變數。 

菱形虛擬繼承:

菱形虛擬繼承與菱形繼承的區別在於,B,C繼承A的公共成員a,既不儲存在 

B裡,也不儲存在C裡,而是儲存在一塊公共的部分,而會將B,C相對於這個變數的 
偏移地址(這裡的偏移量地址叫做虛基表)存在B,C裡。所以說,物件d裡的B,C裡存放了虛表指標、虛基表指標、自己的變數。