2010-06-21 164 views
0

我有一個C++初始化的令人討厭的經驗,我試圖看看是否有一個現實世界的例子證明編譯器沒有警告。爲什麼?從未初始化的父類成員隱式初始化

以下代碼編譯正確,但foo和bar會使用uninit值(我從未初始化的父類假定)進行初始化。編譯器,g ++和VS都不會發出任何警告。 我當然被告知,將成員公開並且不裝飾它們是不好的行爲。但是,我認爲編譯器可能會發現這種不一致,並且至少在最高警告級別發出警告,因爲我看不到任何此類代碼的應用程序。

#include <iostream> 
using namespace std; 

class base_class { 
    public: 
     int foo; 
     int bar; 

    base_class(int foo,int bar): 
     foo(foo),bar(bar) 
    {} 
}; 

class derived_class: public base_class { 
    public: 
    derived_class(int Foo, int Bar): 
     base_class(foo,bar) 
    { 
        int a = Foo * Bar; 

        a++; 
        cout << foo << " " << bar << endl; 
    } 
}; 

int main() 
{ 
    derived_class *buzz = new derived_class(1,2); 
    buzz->print(); 
} 
+2

你應該調整代碼示例,它不會編譯自第9行的引用Foo和Bar(注意大寫),它們應該是什麼? – stijn 2010-06-21 08:43:39

+0

foo初始化爲1,bar初始化爲2.什麼是不一致? – Sjoerd 2010-06-21 08:46:39

+1

嘗試將您的構造函數參數重命名爲與成員名稱不同。 – 2010-06-21 08:46:59

回答

1

我認爲你的問題是,你必須以大寫字母構造函數參數:

用下面的代碼,我得到了正確的價值觀:

#include <iostream> 
using namespace std; 

class base_class { 
    public: 
     int foo; 
     int bar; 

    base_class(int foo,int bar): 
     foo(foo),bar(bar) 
     { 
     int a = foo * bar; 

     a++; 

     cout << "Base : " << foo << ", " << bar << ", " << a << endl; 
    } 

}; 

class derived_class: public base_class { 
    public: 
    derived_class(int foo, int bar): 
     base_class(foo,bar) 
    { 
     cout << "derived : " << foo << ", " << bar << endl; 
    } 
}; 

int main() 
{ 
    derived_class baz(1,2); 
} 

輸出:

Base : 1, 2, 3 
derived : 1, 2 

然後會發生什麼情況是您的成員被初始化爲未初始化的成員值:)

MY2C

+1

我不這麼認爲。如果是這樣,它應該導致編譯器錯誤。但他的意思是編譯。可能是因爲在這裏輸入問題而錯過了。 – liaK 2010-06-21 08:52:47

+0

@liak:基類構造函數不能編譯。當你糾正錯字(foo * bar)時,它會編譯但是具有單位值。我認爲最初有兩個錯字被修正以使代碼編譯,然後他得到未初始化的值...... @Metiu:對嗎?如果沒有給我們整個確切的編譯代碼... – neuro 2010-06-21 08:59:03

0

此:

#include <iostream> 

class base_class { 
public: 
    int foo; 
    int bar; 
    base_class(int foo,int bar) : foo(foo),bar(bar) {} 
}; 

class derived_class : public base_class { 
public: 
    derived_class(int foo, int bar) : base_class(foo,bar) {} 
}; 

int main() 
{ 
    derived_class baz(1,2); 
    std::cout << baz.foo << ", " << baz.bar << '\n'; 
    return 0; 
} 

編譯罰款我使用VC9和VC10並在這兩種情況下寫1, 2。你還有其他什麼嗎?

但是,請注意,同時命名您的成員變量和構造函數參數都會造成混淆。

標準免責聲明:除了這樣愚蠢的例子,千萬不要使用public數據。

+0

請參閱代碼的最新版本,它修復了打字錯誤 – Metiu 2010-06-22 10:41:52

+0

@Metiu:爲什麼要__I__回到您的代碼並嘗試找到您已更改的內容?這不是我想要的東西,而是你。所以請花時間來解釋你改變了什麼,爲什麼,以及這與我的答案有關。順便說一句,我的回答問你,你是否得到了我的代碼相同的結果(暗示你看看我和你的區別,如果它)。你還沒有迴應。 – sbi 2010-06-22 11:02:26

0

在編譯時需要分析使用未初始化變量的分析非常複雜,並且似乎只有在啓用優化時GCC纔會這樣做。據推測有人認爲它放慢了一個非優化的構建不可接受。

g++ -Wall -O編寫代碼確實會發出警告。我無法對Visual Studio發表評論。

+0

請參閱代碼修訂版本7:即使使用-O3 -pedantic -W -Wall,也不會發出警告,只需使用新代替靜態初始化 – Metiu 2010-06-22 10:42:52

+0

@Metiu:我相當肯定靜態分析不可能保證它可以找到任何可以使用的未初始化變量,因此編譯器必須在某處繪製該行。然而,編譯器的狡猾之處在於,你總是可以設計一個失敗的例子。另一方面,像Valgrind這樣的運行時分析工具會發現問題,只要代碼在分析過程中的某個時刻執行。 – 2010-06-22 12:22:48

1

你更新的代碼顯示您的問題:

在第17行使用foo和酒吧從base_class調用base_class與尚未initiliazed屆時值構造函數。結果是未定義的行爲,因此是奇怪的值。正如邁克所說:你只會在打開優化的情況下發出警告,這很奇怪。

+0

是的,我懷疑這是錯誤的原因,當然我可以在防守方面進行編程,但請參閱版本7,其中使用指針甚至不會使用-O3提供任何警告。 – Metiu 2010-06-21 12:40:20

0

我想你並沒有編譯所有激活的警告(你真的應該)。例如,在你的代碼,這裏是G ++輸出:

g++ -O3 -W -Wall init.cc -o init 
init.cc: In function ‘int main()’: 
init.cc:22: warning: ‘baz.derived_class::<anonymous>.base_class::foo’ is used uninitialized in this function 
init.cc:28: note: ‘baz.derived_class::<anonymous>.base_class::foo’ was declared here 
init.cc:22: warning: ‘baz.derived_class::<anonymous>.base_class::bar’ is used uninitialized in this function 
init.cc:28: note: ‘baz.derived_class::<anonymous>.base_class::bar’ was declared here 

你會注意到-W -Wall以確保最大的警告。否則,正如前面所指出的那樣,錯誤在用於變量初始化的情況下。

+0

是的你是對的,雖然它只適用於-O,沒有優化它不會工作。 請看我的修訂7例子,它沒有給出任何警告。 – Metiu 2010-06-21 12:28:39