如果我在一个项目中有两个源文件,每个源文件都定义了一个同名的类,那么是什么决定了使用哪个版本的类?
例如:
// file1.cpp:
#include <iostream>
#include "file2.h"
struct A
{
A() : a(1) {}
int a;
};
int main()
{
// foo() <-- uncomment this line to draw in file2.cpp's use of class A
A a; // <-- Which version of class A is chosen by the linker?
std::cout << a.a << std::endl; // <-- Is "1" or "2" output?
}
...
//file2.h:
void foo();
...
// file2.cpp:
#include <iostream>
#include "file2.h"
struct A
{
A() : a(2) {}
int a;
};
void foo()
{
A a; // <-- Which version of class A is chosen by the linker?
std::cout << a.a << std::endl; // <-- Is "1" or "2" output?
}
我已经能够A
使用相同的代码获得链接器选择的不同版本 - 只需更改我键入代码的顺序(沿途构建)。
诚然,在同一个名称空间中包含具有相同名称的类的不同定义是一种糟糕的编程习惯。但是,是否有定义的规则来确定链接器将选择哪个类 - 如果是,它们是什么?
作为这个问题的一个有用的附录,我想知道(通常)编译器/链接器如何处理类 - 编译器在构建每个源文件时是否将类名和编译的类定义合并到目标文件中,而链接器(在名称冲突的情况下)丢弃一组编译的类函数/成员定义?
名称冲突的问题并不神秘 - 我现在意识到它每次都会发生一个仅包含头文件的模板文件#included
由两个或多个源文件(随后实例化相同的模板类,并调用相同的成员函数,在这些多个源文件),这是 STL 的常见场景。我认为,每个源文件都必须具有相同实例化模板类函数的单独编译版本,因此链接器必须在链接时在这些函数的不同此类编译版本中进行选择)。
-- 附有 Java 相关问题的附录 --
我注意到各种答案都表明了 C++ 的单一定义规则 ( http://en.wikipedia.org/wiki/One_definition_rule )。顺便说一句,我是否正确地认为 Java 没有这样的规则 - 因此 Java 规范允许在 Java 中使用多个不同的定义?