2011-06-14 69 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++程序。编译器不需要诊断此错误。