2

以下のように、同じ名前を宣言する 2 つのファイルがありますclass C

// C1.cpp
class C { 
public: void foo (int, float);
};

int main () {
  C c;
  c.foo(1, 2.3);
}

void C::foo (int, float) {}

// C2.cpp
class C { 
public:
  int i;  // <--- extra variable
  void foo (int, float);  // <--- non static
};

void foo () {
  C c;
  c.foo(0, 0.0);
  c.i = 0;
}

g++ C1.cpp C2.cpp!で正常にコンパイルされます。

  1. 名前だけが同じ で本体が同じではない場合、コンパイラ/リンカー エラーが発生しないのはなぜですか?
  2. と非静的バージョンC::foo(..)の両方で、 なぜ serve の定義が 1 つなのですか?static
  3. または、これがコンパイラの別の未定義の動作ケースである場合、それを防ぐことはできますか?
4

1 に答える 1

1

あなたのプログラムは1 つの定義規則に違反しており、未定義の動作をしています。からn3337 3.2/5、強調鉱山:

クラス型(9 節)、列挙型 (7.2)、外部リンケージを持つインライン関数 (7.1.2)、クラス テンプレート (14 節)、非静的関数テンプレート (14.5.6) の複数の定義が存在する可能性があります。 、クラス テンプレートの静的データ メンバー (14.5.1.3)、クラス テンプレートのメンバー関数 (14.5.1.1)、または一部のテンプレート パラメータが指定されいないテンプレートの特殊化 (14.7、14.5.5)定義は別の翻訳単位に表示され、定義が次の要件を満たしていることが条件です。D という名前のエンティティが複数の翻訳単位で定義されている場合、

D の各定義は、同じ一連のトークンで構成されるものとします。

D の各定義において、対応する名前は、3.4 に従って検索され、D の定義内で定義されたエンティティを参照するか、またはオーバーロードの解決(13.3) および部分的なテンプレートの特殊化のマッチングの後 (ただし、オブジェクトが D のすべての定義で同じリテラル型を持ち、オブジェクトが定数式 (5.19) で初期化され、値がオブジェクトの (アドレスではなく) が使用され、オブジェクトは D のすべての定義で同じ値を持ちます。と

[ ... 例に直接関係のないものは省略 ... ]

D の定義がこれらの要件をすべて満たす場合、プログラムは D の定義が 1 つしかないかのように動作します。D の定義がこれらの要件を満たさない場合、動作は未定義です。

一度に 1 つの翻訳単位しか認識しないため、コンパイラ エラーが発生することはありません。リンカとそのエラー メッセージは C++ 標準の範囲外であるため、なぜ診断されないのかという明確な答えはないと思います。C遭遇した最初のシンボルを取り、残りを破棄するだけだと思います。

于 2013-07-14T14:09:28.413 に答える