01關於對象

在C語言中,數據和操作是分開聲明的。C++將數據和操作封裝在一起。

C++的數據成員包含在類對象中,成員函數不包含在類對象中。非內聯函數只產生一個函數實例,內聯函數在每一個調用處展開。C++封裝數據和操作帶來的開銷主要由虛函數機制和虛基類函數引起的。還有一些多重繼承下的額外負擔。

C++有靜態和非靜態兩種數據成員,靜態,非靜態和虛擬三種成員函數。

簡單對象模型爲每一個數據成員和成員函數分配一個槽,每個槽中有指針指向數據成員或者成員函數。對象中的成員以槽的索引值來尋址。該模型並沒有實際應用,但索引和槽的概念被用於後面的模型。

表格驅動對象模型爲對象分配兩個槽,分別指向數據成員表格和成員函數表格。成員函數表格中存儲了相應的成員。成員函數表格是一些槽,這些槽又分別指向各自的成員函數。這個模型也沒有應用,但是成員函數表的概念應用到了虛函數上。

C++對象模型將非靜態數據成員放在對象內,靜態數據成員放在對象外,靜態成員函數和非靜態成員函數也放在對象外,虛函數則在對象中放置一個指針vptr,該指針指向一個虛表vtbl,該虛表中存放的是相應虛函數的指針。vptr的設定和修改由類的ctor,dtor和assign自動完成。虛表中的第一個槽用來存放指向type_info對象的指針,該對象用來支持RTTI。

C++對象模型的優點是空間和存取時間的效率,缺點是如果類的非靜態數據成員有所修改,應用程序的代碼也要重新編譯。

在虛擬繼承下,基類不管被派生類多少次,永遠只有一個實例存在。繼承的對象模型在3.4節。

假設類X有一個cctor,vdtor和虛擬foo成員函數,那麼下面的代碼:

X foobar(){
    X xx;
    X*px=new X;

    xx.foo();
    px->foo();

    delete px;
    return xx;
}

可能被轉換爲:

void foobar(X&_result){
    _result.X::X();
    px=_new(sizeof(X));
    if(px!=0)
        px->X::X();
    foo(&_result);
    (*px->vtbl[2])(px);
    (*px->vtbl[1])(px);
    _delete(px);
    return;
}

struct和class的區別是struct的訪問控制默認是public,class的訪問控制默認是private。

把一個子類對象賦給一個父類變量,會發生對象切割。

多態只存在於public類體系中,非public的派生,void*指針不支持。

多態可以把派生類的指針賦給父類指針變量。也可以通過dynamic_cast和typeid運算符:

circle*pc=dynamic_cast<circle*>(ps);

多態的用途是通過一個共同的接口來影響類型的封裝,這個接口通常定義在一個抽象的基類中。

類對象大小:

1.非靜態數據成員大小

2.對齊填充的大小

3.vptr指針

指針本身的大小是固定的。本質上,一個引用通常是以一個指針來實現的。

void*類型的指針變量只能有一個地址,不能通過它操作所指的對象,因爲不知道該對象的地址空間。所以要顯式轉換,指明所要訪問的地址空間的大小。

轉換cast是一種編譯器指令,它並不 一個指針所含的真正地址,隻影響該段內存的大小和內容的解釋方式。

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