0

カスタム乱数ジェネレーターを作成し、それらのグローバル関数を SamRandom.h という名前のファイルに配置しました。ファイルは次のようになります。

#ifndef _SAM_RANDOM_H
#define _SAM_RANDOM_H

#include <cstdlib>
#include <ctime>

void InitialiseRandomSeed()
{
    //...
}

//...

#endif

私は非常に複雑なオブジェクト指向プログラムで作業しており、あちこちにさまざまなコンポーネントが含まれています。とにかくこのファイルに関連するファイルを追加するたびに、次の競合メッセージが表示されます。

LaserBase.obj:-1: error: LNK2005: "void __cdecl InitialiseRandomSeed(void)" (?InitialiseRandomSeed@@YAXXZ) already defined in main.obj
error: LNK1169: one or more multiply defined symbols found

MSVC と MinGW では次のようになります。

In function `Z20InitialiseRandomSeedv':
SamRandom.h:8: multiple definition of `InitialiseRandomSeed()'
error: first defined here
:-1: error: collect2: ld returned 1 exit status

なぜこうなった?私は、プリプロセッサ ディレクティブがこの問題の発生を防ぐはずだと思っていました...これは本当に私を夢中にさせます!!!

PS: 問題は関数名とは無関係です。

ご尽力いただきありがとうございます

4

3 に答える 3

2

ファイルを .cpp ファイルに含めると、プリプロセッサはそれをそのファイルに直接コピーします。したがって、その .cpp ファイルをコンパイルすると、オブジェクト ファイル (認識しなくてもコンパイラが常に実行するステップ) にその関数が含まれます。複数の .cpp ファイルに含めると、各オブジェクト ファイルに関数が含まれます。リンカーがすべてのオブジェクト ファイルを実行可能ファイルにリンクしようとすると、関数 x-times が検出され、そのエラーが発生します。「1 つまたは複数の複数定義されたシンボルが見つかりました」は、関数 (または変数) の 1 つが複数回見つかり、その処理方法がわからないことを示しています。

これを回避するには、関数の署名のみを配置する必要があります。

//whatever.h
#ifndef _SAM_RANDOM_H
#define _SAM_RANDOM_H

void InitialiseRandomSeed();

#endif

ヘッダー ファイルに追加し、実装を別の .cpp ファイルに入れます。

//whatever.cpp
#include "whatever.h"
#include <cstdlib>
#include <ctime>

void InitialiseRandomSeed()
{
    //...
}
于 2012-04-08T22:46:47.737 に答える
2

ヘッダー ガードにより、関数が 1 つのコンパイル ユニット (.cpp ファイル) で複数回定義されていないことが保証されます。ただし、関数が複数のコンパイル単位で一度に定義されることを妨げるものではありません。これは、ヘッダーに関数の定義が含まれているためです。そのため、ヘッダーを含むすべての .cpp には関数の独自の定義があります。

定義を SamRandom.cpp に移動し、代わりに次のようにヘッダーで関数を宣言できます。

void InitialiseRandomSeed();

または、関数がインラインであることを指定して、複数の定義を受け入れられるようにすることもできます。

inline void InitialiseRandomSeed()
{
    //...
}

関数がパフォーマンス クリティカルではなく、頻繁に呼び出されないと仮定すると、前者のアプローチを使用します。これにより、ヘッダーが読みやすくなり、(一般に) コンパイル時間が短縮されます。

于 2012-04-08T22:54:02.120 に答える
1

定義を .cpp ファイルに分割し、ヘッダーで関数を宣言するだけです。

于 2012-04-08T22:43:21.833 に答える