關於類成員的初始化順序問題

2021-04-12 13:27:18 字數 2472 閱讀 7251

1.關於類成員的初始化順序問題

條款13的標題是:initialization list中的members初始化次序應該和其在class內的宣告次序相同。

我不知道大家在用c++開發的時候有沒有注意過這個問題,反正我是從來沒有往這方面想過!

下面來看例子:

class cmyintarray

;private:

std::vectordata;

size_t size;

int lbound, hbound;

};cmyintarray::cmyintarray(int lowbound, int highbound)

: size(highbound - lowbound +1)

, lbound(lowbound)

, hbound(highbound)

, data(size)

如果沒有看過這本書,沒有任何提示,我想很多搞c++開發的人看不出這簡單幾行**有什麼問題(當然,編譯肯定是不會有問題的)。

可是,如果程式中有類似於下面的**,問題就會在程式執行的時候爆發出來:

cmyintarray otest(5, 13);

cout << otest.getarraysize() << endl;

而且你就算在debug狀態下進行跟蹤也很難發現問題的根源所在!

問題處在什麼地方呢?就在於成員變數的宣告次序上!上面變數宣告的次序改為:

size_t size;

int lbound, hbound;

std::vectordata;

問題就可以迎刃而解!

驚奇嗎?為什麼會這樣?書中給出了答案:class members係以它們在class內的宣告次序來初始化;和它們在member initialization list中出現的次序完全無關。

上面**的錯誤根源是:data在得到size之前就已經初始化了,也就是說data的大小是不確定的,呼叫它的size方法當然會出錯!

2.關於「切割問題」

下面是書中的一段話(條款22中):

當乙個derived class object被交出去當作乙個base class object時,它原本所以「成為乙個derived class object」的所有特徵,都會被切除(slicing)掉,只留下內部乙個base class object。

下面是我寫的小例子:

class cbase;};

class cderived : public cbase;};

下面是兩個函式:

void test1(cbase test)

void test2(const cbase& test)

用下面的**分別呼叫函式test1和test2:

cderived otest;

test1(otest);

test2(otest);

問題是:呼叫函式test1和函式test2分別輸出什麼?

正確答案是:

output from cbase!

output from cderived!

驚奇嗎?一點兒也不驚奇!書中已經給出了為什麼會這樣:以by reference的方式傳遞引數,有另乙個優點:可避免所謂的「切割(slicing)問題」。

3.關於非虛函式的靜態繫結和虛函式的動態繫結

下面是例子:

class cbase;};

class cderived : public cbase;};

現在有下面的**呼叫:

cderived  d;

cbase *pb = &d;

pb->test();

cderived  *pd = &d;

pd->test();

輸出是:

output from cderived!

output from cderived!

output from cbase!

output from cderived!

這時,有些人就會奇怪了,pb和pd指向的都是d,為什麼會這樣輸出呢?

答案就是:非虛函式是靜態繫結的,虛函式是動態繫結的。

書中的條款37給了大家忠告:絕對不要重新定義繼承而來的非虛函式。

4.關於預設值的靜態繫結

還是看例子:

class cbase

;class cderived : public cbase;};

下面是呼叫**:

cbase *p = new cderived;

p->test();

我們的本意是想輸出1,可是結果卻是輸出0!

不用驚奇,書中給出了答案:虛函式系動態繫結(dynamically bound),而預設引數值卻是靜態繫結(statically bound)。

而且,書中的條款38也給了大家忠告:絕對不要重新定義繼承而來的預設引數。

Java類成員初始化順序

首先看下這段測試 public class classloader 1.第二步,靜態變數和靜態 塊的載入順序由編寫先後決定 static int snum 4 2.第三步,靜態塊,然後執行靜態 塊,因為有輸出,故列印 static 4.第五步,按照順序載入匿名 塊,塊中有列印 5.第六步,按照順序載...

java類成員初始化順序

乙個類中,最首先被初始化的是靜態成員。只要乙個類建立物件或呼叫該類的靜態方法時靜態成員就都會被初始化,並且靜態資料在記憶體中只占用乙份儲存區域,無論建立多少個物件,靜態資料被所有物件共享。初始化靜態成員後再初始化非靜態成員。屬性 方法 構造方法和自由塊都是類的成員,在建立類物件時,類中各執行順序 b...

Java類成員的初始化順序

靜態成員 靜態變數 靜態初始化塊 變數 初始化塊 構造器 只要乙個類被使用 呼叫了類中的某個靜態方法或者是建立物件 這兩種情況表明該類被使用了。如果是有類的繼承關係,則優先執行父類中的成員,屬性及構造器,及初始化順序為 父類的靜態成員 子類的靜態成員 父類的變數 初始化塊 父類構造器 子類的變數 初...