编译器构造-如何在C++中解决这些名称冲突

compiler construction - How these names conflict is resolved in C++?

本文关键字:解决 冲突 C++ 编译器      更新时间:2023-10-16

假设我有这样的物理结构:

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

这些都是诽谤的来源,深吸一口气:

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构建此解决方案。CCD_ 8是针对静态库CCD_。这编译起来很有魅力,但信不信由你,输出是:

A is alive
B::bar

链接器实际上使用来自conflicttest的符号A,它绝对不是B,更糟的是,它可以调用B::bar()

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

您违反了一个定义规则。

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

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

答案很简单。你们对编译器撒谎了,作为回报,编译器正在把你们的谎言还给你们。函数的内部实现是这样的,即它们只是在每个类的某个函数表中排列。当你有不同的类声明时,编译器会根据它来推导函数表,但推导是错误的。该表中没有函数名,因此编译器无法检测到故障情况。

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