C++ 中如何解决这些名称冲突?
假设我有这样的物理结构:
/
+-- conflicttest
| +-- A.cpp
| +-- A.h
| +-- main.cpp
+-- libconflict
| +-- conflict
| | +-- A.h
| | +-- B.h
| +-- A.cpp
| +-- B.cpp
这些是 libconflict 的来源,深吸一口气:
libconflict 中的 class B
header:
// libconflict B.h
class B
{
public:
void bar();
protected:
int j_;
};
class B
libconflict 中的实现:
// 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_;
};
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;
}
现在是冲突测试的来源,几乎结束了:
conflicttest 中的 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;
}
唷...我正在使用 Visual Studio 2010 来构建此解决方案。 conflicttest
是一个链接到静态库libconflict
的可执行文件。 这编译起来就像一个魅力,但是,不管你信不信,输出是:
A is alive
B::bar
链接器实际上使用来自 conflicttest
的符号 A
,它绝对不是 B< /code> 更糟糕的是,它可以调用
B::bar()
。
我迷路了,为什么编译器不抱怨?
Say I have this physical structure:
/
+-- conflicttest
| +-- A.cpp
| +-- A.h
| +-- main.cpp
+-- libconflict
| +-- conflict
| | +-- A.h
| | +-- B.h
| +-- A.cpp
| +-- B.cpp
These are the sources of libconflict, take a deep breath:
class B
header in libconflict:
// libconflict B.h
class B
{
public:
void bar();
protected:
int j_;
};
class B
implementation in libconflict:
// libconflict B.cpp
#include "conflict/B.h"
void B::bar()
{
std::cout << "B::bar" << std::endl;
}
class A
header in libconflict:
// libconflict A.h
# include "conflict/B.h"
class A : public B
{
public:
A();
private:
int i_;
};
class A
implementation in 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;
}
Now the sources of conflicttest, it's almost over:
class A
header in conflicttest:
// conflicttest A.h
class A
{
public:
A();
void foo();
};
class A
implementation in 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;
}
and finally, main.cpp
:
// main.cpp in conflicttest
#include "conflict/A.h"
int main()
{
B* b = new A;
b->bar();
return 0;
}
Phew... I am using Visual Studio 2010 to build this solution. conflicttest
is an executable which is linked against the static library libconflict
.
This compiles like a charm, but, believe it or not, the output is :
A is alive
B::bar
The linker actually uses the symbol A
from conflicttest
which is absolutely not a B
and worse, it can invoke B::bar()
.
I am lost, how come the compiler doesn't complain?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您违反了单一定义规则。
编译器没有抱怨,因为它在跨越翻译单元边界时可以检测到的东西是有限的。
You have violated the One Definition Rule.
The compiler didn't complain because it is limited in the things it can detect when crossing translation unit boundaries.
我猜你实际上并没有链接你的conflictlib。但实际上,不要这样做。如果您绝对必须,请使用名称空间。
I'm guessing you aren't actually linking your conflictlib. But really, just don't do that. If you absolutely MUST, use namespaces.
答案很简单。你对编译器撒了谎,作为回报,编译器也将你的谎言回馈给你。函数的内部实现是这样的,它们只是排列在每个类的某个函数表中。当您有不同的类声明时,编译器会根据它推导函数表,但推导是错误的。该表中没有函数名称,因此编译器无法检测到错误情况。
The answer is very simple. You have lied to compiler, and in return the compiler is serving your lie back to you. Internal implementation of functions is such that they are just lined up in some function table for each class. When you have different class declaration the compiler deduces the function table according to it, but the deduction is wrong. In this table there are no function names, so compiler can't detect the fault condition.
您对 A 类有两个不同的定义。这违反了 ODR。因此该程序不是有效的 C++ 程序。编译器不需要诊断此错误。
You have two different definitions of class A. This is a violation of ODR. The program therefore is not a valid C++ program. Compilers are not required to diagnose this error.