如何在C ++中解决这些名称冲突?

时间:2011-06-14 16:15:45

标签: c++ compiler-construction linker conflict

说我有这种物理结构:

/
  +-- 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()

我迷路了,为什么编译器不抱怨?

4 个答案:

答案 0 :(得分:6)

您违反了One Definition Rule

编译器没有抱怨,因为它在跨越翻译单元边界时可以检测到的东西是有限的。

答案 1 :(得分:1)

我猜你实际上并没有链接你的conflictlib。但实际上,就是不要这样做。如果绝对必须使用命名空间。

答案 2 :(得分:1)

答案很简单。你已经骗了编译器,作为回报,编译器正在为你撒谎。函数的内部实现是这样的,它们只是在每个类的一些函数表中排列。当你有不同的类声明时,编译器会根据它推断出函数表,但是推论是错误的。在此表中没有函数名称,因此编译器无法检测到故障情况。

答案 3 :(得分:1)

您对A类有两种不同的定义。这违反了ODR。因此,该程序不是有效的C ++程序。编译器不需要诊断此错误。