2010-07-22 76 views
1
class Base{ 
    public: 
     Base(int val):_id(val){}; 
     int _id; 
}; 

class Derived : Base { 
    public: 
     Derived(int val):Base(_id+val){}; 
}; 

int main(){ 
    Derived d(60); 
} 

爲什麼這不會給出錯誤?基類仍然沒有構建,但我可以使用'_id'?繼承,調用基類ctors

感謝

回答

1

這不是建造,但其分配內存,因此存在_id並持有​​未初始化值。

0

我不明白這個問題。它的工作原理是因爲C++標準允許這種行爲。 這個類的內存已經被分配了,所以可以使用這個變量。

+1

我不明白你不明白問題 – stijn 2010-07-22 12:14:58

2

一個更簡單的例子:int x = x + 1;告訴你,C++編譯器不跟蹤變量初始化。 在你的例子中,_id存在於內存中(它有一個地址),但從未初始化。但是,由於編譯器沒有跟蹤,所以沒有錯誤。

0

基類仍然沒有構建,但我可以使用'_id'?

不,你不使用_id,因爲沒有一個對象_id呢。但是存在對象的原始內存,您可以使用標識符訪問該對象,將原始內存解釋爲int對象。

做調用未定義的行爲你最好不要這樣做。未定義的行爲可能會導致你的HD格式化,你懷孕了,或者程序看起來工作得很好,並且正在做它應該做的事情。而且你永遠不知道它是哪一個,因爲它可能與每個編譯器,編譯器版本,月相或者其他的不同。

在上述情況下,將原始存儲器解釋爲一個int對象,通常的結果是,該位置存在的任何位模式都被解釋爲一個整數並使用結果。但是,平臺也可以捕獲對未初始化的內存的訪問並拋出硬件異常。
如果_id是非POD(std::string),則可能的但不是保證的結果將是訪問衝突。

編輯迴應評論:

您可以訪問基類成員,甚至是未初始化的,在派生類的初始化列表就好:

#include <iostream> 

class Base{ 
public: 
    Base(int val):id_(val){}; 
protected: 
    int id_; 
}; 

class Derived : Base { 
public: 
    Derived(int val):Base(id_+val), blah_(id_) {}; 
    int blah() const {return blah_;} 
private: 
    int blah_; 
}; 

int main(){ 
    Derived d(60); 
    std::cout << d.blah() << '\n'; 
    return 0; 
} 
+0

好了,它試圖找到_id的範圍是基類作用域,因爲基類構造函數被調用?如果我嘗試訪問派生的初始化程序列表中的_id(無需明確調用base ctor),則會發生錯誤。 – tuco 2010-07-22 12:56:48

+0

@tuco:在派生類的初始化列表中訪問基類成員__syntactically__沒有任何錯誤。看到我的回答,我添加了一些編譯好的代碼。 – sbi 2010-07-22 13:06:08

+0

很酷。我意識到我試圖在派生的初始化列表中初始化基類成員並獲取錯誤。 – tuco 2010-07-22 13:13:50

0

想象有在您輸入:以啓動初始化程序列表的位置看不到malloc。它會給你一個未初始化的內存塊,足以容納一個Derived對象,包括Base部分。編譯器知道_id所指的偏移量,所以它會隨心所欲地爲您提供生活在那裏的垃圾值。

在初始化程序列表中調用Base()之後引用_id是合法的。當基類構造函數尚未被調用時,編譯器不會做出特殊情況。

0

如果您正確聲明瞭您的成員屬性private,那將是一個錯誤。像這樣將公有數據與繼承混合在一起可能只會導致混淆或不正確的行爲,例如你所觀察到的。如果你的成員是私有的,那麼編譯器會防止這個錯誤,並增強你的類封裝。

編輯:_id可用的原因是因爲它的內存已被分配,它只是還沒有被初始化。想一些沿線:

int x; 
int y = x; 

你不知道什麼將在y因爲x從未初始化。