说我有这种物理结构:
/
+-- conflicttest
| +-- A.cpp
| +-- A.h
| +-- main.cpp
+-- libconflict
| +-- conflict
| | +-- A.h
| | +-- B.h
| +-- A.cpp
| +-- B.cpp
这些是libconflict的来源,请深呼吸:
libconflict中的 class B
标头:
// libconflict B.h
class B
{
public:
void bar();
protected:
int j_;
};
libconflict中的 class B
实现:
// libconflict B.cpp
#include "conflict/B.h"
void B::bar()
{
std::cout << "B::bar" << std::endl;
}
libconflict中的 class A
标头:
// libconflict A.h
# include "conflict/B.h"
class A : public B
{
public:
A();
private:
int i_;
};
libconflict中的 class A
实现:
#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;
}
现在冲突的根源,它几乎结束了:
冲突中的 class A
标题:
// conflicttest A.h
class A
{
public:
A();
void foo();
};
冲突中的 class A
实施:
// 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;
}
Phew ...我正在使用Visual Studio 2010来构建此解决方案。 conflicttest
是一个与静态库libconflict
链接的可执行文件。
这就像魅力一样编译,不管你信不信,输出是:
A is alive
B::bar
链接器实际使用来自A
的符号conflicttest
,它绝对不是B
,更糟糕的是,它可以调用B::bar()
。
我迷路了,为什么编译器不抱怨?
答案 0 :(得分:6)
您违反了One Definition Rule。
编译器没有抱怨,因为它在跨越翻译单元边界时可以检测到的东西是有限的。
答案 1 :(得分:1)
我猜你实际上并没有链接你的conflictlib。但实际上,就是不要这样做。如果绝对必须使用命名空间。
答案 2 :(得分:1)
答案很简单。你已经骗了编译器,作为回报,编译器正在为你撒谎。函数的内部实现是这样的,它们只是在每个类的一些函数表中排列。当你有不同的类声明时,编译器会根据它推断出函数表,但是推论是错误的。在此表中没有函数名称,因此编译器无法检测到故障情况。
答案 3 :(得分:1)
您对A类有两种不同的定义。这违反了ODR。因此,该程序不是有效的C ++程序。编译器不需要诊断此错误。