プロジェクトに2つのソースファイルがあり、それぞれが同じ名前のクラスを定義している場合、使用されるクラスのバージョンは何によって決まりますか?
例えば:
// 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
コードを入力する順序を変更するだけで(途中でビルドして)、同じコードで、リンカーによって選択されるさまざまなバージョンを取得することができました。
確かに、同じ名前空間に同じ名前のクラスの異なる定義を含めることは、プログラミングの実践としては不十分です。ただし、リンカーによって選択されるクラスを決定する定義済みのルールはありますか?その場合、それらは何ですか?
この質問への有用な補足として、コンパイラ/リンカがクラスをどのように処理するかを(一般的に)知りたいです-コンパイラは、各ソースファイルをビルドするときに、クラス名とコンパイルされたクラス定義をオブジェクトファイルに組み込みますが、リンカ(名前の衝突のシナリオでは)は、コンパイルされたクラス関数/メンバー定義の1つのセットを破棄しますか?
#included
名前の衝突の問題は難解ではありません-ヘッダーのみのテンプレートファイルが2つ以上のソースファイルによって毎回発生することに気付きました(その後、同じテンプレートクラスがインスタンス化され、同じメンバー関数が呼び出されますSTLの一般的なシナリオと同様に、複数のソースファイル)。各ソースファイルには、同じインスタンス化されたテンプレートクラス関数の個別にコンパイルされたバージョンが必要です。したがって、リンカは、リンケージ時にこれらの関数のコンパイルされたバージョンを選択する必要があります)。
--Javaに関する関連質問の補遺-
さまざまな回答が、C ++の単一定義規則( http://en.wikipedia.org/wiki/One_definition_rule )を示していることに注意してください。興味深いことに、Javaにはそのようなルールがないというのは正しいですか?Java仕様によってJavaで複数の異なる定義が許可されていますか?