2011-06-14 37 views
3

說我有這樣的物理結構:這些名稱衝突如何在C++中解決?

/ 
    +-- conflicttest 
    |  +-- A.cpp 
    |  +-- A.h 
    |  +-- main.cpp 
    +-- libconflict 
    |  +-- conflict 
    |  |  +-- A.h 
    |  |  +-- B.h 
    |  +-- A.cpp 
    |  +-- B.cpp 

這些libconflict的來源,深呼吸:

// libconflict B.h 
class B 
{ 
public: 
    void bar(); 
protected: 
    int j_; 
}; 

class B在libconflict實現:在libconflict

class B

// libconflict B.cpp 
#include "conflict/B.h" 

void B::bar() 
{ 
    std::cout << "B::bar" << std::endl; 
} 

class A頭球libconflict:

// libconflict A.h 
# include "conflict/B.h" 

class A : public B 
{ 
public: 
    A(); 
private: 
    int i_; 
}; 

class A在libconflict實現:

#include "conflict/A.h" 

A::A() 
{ 
    std::cout << "libconflict A is alive" << std::endl; 
    i_ = 51; // some random fields and values... I should admit I am lost 
    j_ = 47; 
} 

現在conflicttest的來源,它幾乎在:在conflicttest

class A頭:

// conflicttest A.h 
class A 
{ 
public: 
    A(); 
    void foo(); 
}; 

class A實施conflicttest:

// conflicttest A.cpp 
#include "A.h" 

A::A() 
{ 
    std::cout << "A is alive" << std::endl; 
} 

void A::foo() 
{ 
    std::cout << "A::foo" << std::endl; 
} 

最後,main.cpp

// main.cpp in conflicttest 
#include "conflict/A.h" 

int main() 
{ 
    B* b = new A; 
    b->bar(); 
return 0; 
} 

呼...我使用Visual Studio 2010來構建這個解決方案。 conflicttest是與靜態庫libconflict鏈接的可執行文件。 這將編譯有魅力,但是,不管你信不信,輸出爲:

A is alive 
B::bar 

鏈接器實際使用從conflicttest符號A這絕對不是一個B更糟的是,它可以調用B::bar()

我迷路了,編譯器怎麼沒有抱怨?

+2

你讓我失去了一半。但顯而易見的答案是 - 不要像這樣構建你的項目。 – 2011-06-14 16:20:03

回答

6

您已違反One Definition Rule

編譯器沒有抱怨,因爲它在穿越翻譯單元邊界時可以檢測到的東西有限。

1

我猜你實際上並沒有鏈接你的conflictlib。但是,真的,不要那樣做。如果你絕對必須使用名稱空間。

+0

是的,圖書館實際上是在這裏清除重複的來源。但是一旦一次,似乎一些重複的資料來源被修改而沒有給他們一個新的名字。 – 2011-06-14 16:26:16

1

答案很簡單。你騙了編譯器,作爲回報,編譯器正在向你回報你的謊言。函數的內部實現是這樣的,它們只是排列在每個類的某個函數表中。當你有不同的類聲明時,編譯器根據它來推導出函數表,但扣除是錯誤的。在這個表中沒有函數名,所以編譯器不能檢測到錯誤條件。

1

您有兩類不同的A類定義。這是違反ODR的。該程序因此不是有效的C++程序。編譯器不需要診斷此錯誤。