2010-06-14 195 views
3

我在C++中的一些概念中變得非常困惑。對於例如:我有以下兩個文件靜態初始化混淆

//file1.cpp 
class test 
{ 
    static int s; 
    public: 
    test(){s++;} 
}; 

static test t; 
int test::s=5; 

//file2.cpp 
#include<iostream> 
using namespace std; 
class test 
{ 
    static int s; 
    public: 
    test(){s++;} 
    static int get() 
    { 
    return s; 
    } 
}; 

static test t; 

int main() 
{ 
    cout<<test::get()<<endl; 
} 

現在我的問題是:
1.如何兩個文件成功鏈接,即使他們有不同的類定義?
2.兩個類的靜態成員是否相關,因爲我得到的輸出爲7.

請解釋這個靜態的概念。

回答

3

它們之間的鏈接是因爲鏈接器幾乎不瞭解C++語言。但是,如果你這樣做,你打破了一個定義規則,你的程序的行爲將是未定義的。編寫無效的代碼不是學習C++的好方法。另外,你似乎有很多關於靜態變量的問題 - 這個概念實際上並不那麼複雜 - 你使用的C++教科書不能很好地解釋它嗎?

+0

Ok..Now假設我寫在同一個類定義兩個文件。 那我的第二個問題呢? 這兩個類的靜態成員是相關的嗎? – 2010-06-14 10:31:14

+0

@Happy只能有一個名稱爲test的類,所以只能有一個靜態變量。其他任何東西都是連接器產生的人工製品。 – 2010-06-14 10:33:18

+0

我正在使用Bruce Eckel的C++中的Thinking。其實我正在閱讀schwarz計數器技術的靜態初始化命令失敗,但我無法理解爲解釋該技術而編寫的代碼。 如果你有這本書,你能解釋一下這個代碼嗎? – 2010-06-14 10:34:27

1

這些類(就鏈接器而言)是相同的。 get()只是鏈接器從不會看到的內聯函數。

類中的靜態不會將成員限制爲文件作用域,但會使其成爲全部類實例的全局對象。

[編輯]你會得到一個鏈接器錯誤,如果你將int test::s=5;也放入第二個文件中。

1

靜態是C++中的一種奇怪的野獸,根據上下文的不同有着不同的含義。

在File1.cpp中,類定義中的「static int s」表示s是一個靜態成員,即對於所有測試實例都是通用的。

但是,「靜態測試t」具有不同的含義:靜態全局變量僅存在於編譯單元中,並且不會被其他單元看到。這是爲了避免鏈接器混淆,如果你使用兩個不同的東西同名。在現代C++中,應當使用匿名命名空間是:

namespace 
{ 
    test t; 
} 

這意味着T內File1.cpp和T內File2.cpp是單獨的對象。

在File2.cpp中,您還定義了一個靜態方法get:靜態方法是屬於類而不是實例的方法,並且只能訪問該類的靜態成員。

最後一次使用靜態,你沒有在你的例子中使用的是本地靜態變量。局部靜態變量初始化它首先執行的時間,並保持整個執行它的價值,有點像一個本地範圍的全局變量:

int add() 
{ 
    static value = 0; 
    value++; 
    return value; 
} 

調用add()反覆將返回1,那麼2 ,然後3 ...這個本地靜態結構可以用於本地緩存。

0
  1. 即使它們具有不同的類定義,兩個文件如何成功鏈接?

您違反了在不同的翻譯單位不同定義同班一個定義規則(ODR)。這調用了可怕的未定義的行爲。這意味着代碼可以做任何事情,包括但不限於做你想做的事,格式化你的硬盤,或者造成未被認定的日蝕。
請注意,不要求編譯器/鏈接器檢測ODR違規。

  • 涉及兩個類的靜態成員是因爲我得到的輸出7.
  • 也許他們,也許他們都沒有。真的,未定義的行爲可能會做任何事情。你看到的只是你的編譯器和鏈接器的實現。
    一個可能的實現將很高興地將所有對test::s的引用鏈接到同一個實例,但讓每個翻譯單元都有 - 並鏈接到 - 它們自己的t對象。 (由於類只有inline功能,最有可能的連接者甚至從未見過除了test::s和那些t實例test東西。)的C++如何實際工作

    0

    Unnice副作用。使用名稱空間使類名與外部不同。

    在過去,我在實踐中使用了相當繁瑣的規則:每個庫和文件必須有一個專用的命名空間以避免這種鏈接衝突。或者將實用程序類放入主類定義中。無論如何:不要污染全球名稱空間,最重要的是要確保整個項目名稱的唯一性。 (編寫,現在我發現我用幾乎逐字概念從Java)。

    我對C的靜態在C++中的等價搜索是徒勞的......

    +0

    C++與C有完全相同的靜態概念,加上一些。 – 2010-06-14 12:17:17

    +0

    @neil:如何創建* static *方法或類,這些方法或類在編譯單元之外是不可見的? C具有函數和數據 - 將* static *應用於它們使其成爲本地。 C++有類 - 但我沒有找到任何東西來編譯本地編譯單元的類。 – Dummy00001 2010-06-14 14:15:26

    +0

    非類靜態函數在C++中的工作原理與C中的相同。事實上,你不能編譯單元本地類靜態函數(儘管你當然可以擁有私有函數)並不矛盾我的評論。 – 2010-06-14 15:27:33