2017-10-15 59 views
3

我想與外部連接和不完整的類型聲明進行實驗,並寫了這個例子:C++的extern聯

Source.cpp:

//Source.cpp 
class A { 
public: 
    int a=10; 
}; 

A* var1 = new A(); 

void printA(A* arg) 
{ 
    cout << arg->a << endl; 
} 

Source1.cpp:

//Source1.cpp 
class A 
{ 
public: 
    int b = 20; 
    int c = 30; 
}; 

A* var2 = new A(); 

void printB(A* a) 
{ 
    std::cout << a->b; 
} 

主。 cpp:

//main.cpp 
class A; 
extern A* var1; 
extern A* var2; 
int main() 
{ 
    void printA(A*); 
    void printB(A*); 
    printA(var1); //Prints 10 
    printA(var2); //Prints 10 
    printB(var2); //Prints 10 
    return 0; 
} 

第一次撥打printA()後,會按照我的預期打印「10」。但是爲什麼在printA()printB()的第二次呼叫之後還打印了「10」?

回答

5

歡迎來到一個定義規則違規的美妙世界。您有兩個類,都定義在文件範圍內,共享一個名稱。

由於類默認具有外部鏈接,所以對同一個類有兩個定義,這兩個定義彼此不一致。這會讓你的程序不合格,編譯器/鏈接器可能會抱怨,或者只是繼續做奇怪的事情。

在另一面,迫使內部鏈接的一類方法是聲明它不具名命名空間:

namespace { 

    class A { 
    public: 
     int a=10; 
    }; 

} 

由於未命名空間是唯一的每個翻譯單元,你實際上將有兩個單獨的類定義。需要注意的是,您不能再從翻譯單元外向他們聲明extern變量。

5

您的程序以不需要診斷的方式違反One Definition Rule,因此不合格。程序中的兩個翻譯單元都定義了一個名爲A的類,它具有外部鏈接,但定義不同。編譯器和鏈接器被允許假設它們是同一個類。您的程序沒有「正確的」輸出。

+0

所以這是未定義的行爲? – Nikita

+0

@Nikita標準確實說這是未定義的行爲,但我認爲他們的意思是說它不合格,不需要診斷。如果一個不合格的NDR程序實際編譯並運行,則行爲未定義。 – Brian