8

これらの関数は、ほとんどのプログラムオブジェクトが使用するユーティリティタイプのものです。それらを名前空間に入れてグローバルにしたい。この名前空間はヘッダーで定義され、プリコンパイル済みヘッダーに追加されます。ただし、これまでに2つの異なるオブジェクトでこの名前空間の関数を使用しており、コンパイラーはこれら2つのオブジェクトで多重定義シンボルエラーをスローしています。

名前空間ファイル

#ifndef UTILS_H
#define UTILS_H

#include <random>
#include <cmath>


namespace Utils
{
    extern int GetRandomBetween(int low, int high)
    {
        if (low < 0 || low >= high)
            return 0;
        int seed = high - low;

        return (rand() % seed) + low;
    }
};

#endif

と私のprecompヘッダー

// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//

#pragma once

#include "targetver.h"

//#define WIN32_LEAN_AND_MEAN             // Exclude rarely-used stuff from Windows headers
// Windows Header Files:
#include <windows.h>

// C RunTime Header Files
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>
#include <random>


#define SAFE_DELETE( p )       { if( p ) { delete ( p );     ( p ) = NULL; } }
#define SAFE_DELETE_ARRAY( p ) { if( p ) { delete[] ( p );   ( p ) = NULL; } }
#define SAFE_RELEASE( p )      { if( p ) { ( p )->Release(); ( p ) = NULL; } }
// TODO: reference additional headers your program requires here

#include "Utils.h"
#include "Manager.h" // this object uses utils
#include "Bot.h"    // this object uses utils
#include "LinkedList.h"
#include "Village.h"  // this object will use utils in the future

リンカのエラーメッセージ:

Manager.obj : error LNK2005: "int __cdecl Utils::GetRandomBetween(int,int)" (?GetRandomBetween@Utils@@YAHHH@Z) already defined in Bot.obj stdafx.obj : error LNK2005: "int __cdecl Utils::GetRandomBetween(int,int)" (?GetRandomBetween@Utils@@YAHHH@Z) already defined in Bot.obj c:\users\lee\documents\visual studio 2010\Projects\AI\Debug\AI.exe : fatal error LNK1169: one or more multiply defined symbols found

また、ManagerクラスヘッダーでBotを前方宣言したことにも注意してください。Villageクラスヘッダーと同じです。

4

2 に答える 2

11

関数定義(つまり、ソースコード)をヘッダーに含めることはできません。複数の定義を取得する理由はextern、関数定義(ソースコード)を関数宣言(つまり、プロトタイプのみ)に変換できないためです。したがって、これを行う必要があります。

Util.h:

namespace Utils
{
    int GetRandomBetween(int low, int high);
};

SomeSourceFile.cpp(おそらくUtil.cpp):

namespace Utils
{
    int GetRandomBetween(int low, int high);
    {
        if (low < 0 || low >= high)
            return 0;
        int seed = high - low;

        return (rand() % seed) + low;
    }
};

inlineまたは、ヘッダーで関数を宣言することもできます。

namespace Utils
{
    inline int GetRandomBetween(int low, int high)
    {
        if (low < 0 || low >= high)
            return 0;
        int seed = high - low;

        return (rand() % seed) + low;
    }
};

ただし、これは小さな機能にのみ使用する必要があります。

于 2011-08-05T22:27:25.753 に答える
2

Manager.cppBot.cpp両方が含まれていますUtil.h

このため、コンパイル時に、両方のオブジェクトファイルがシンボル「GetRandomBetween」をエクスポートします。リンカがこれらのオブジェクトファイルを実行可能ファイルに結合しようとすると、関数の2つのインスタンスが検出されます。リンカはどちらを使用するかを決定できません(そしてそれらが同一であることを理解していません)。

オブジェクトファイルでシンボルをエクスポートしないようにする場合(リンカーの競合が発生しないようにするため)、externキーワードを削除します。

于 2011-08-05T22:11:08.260 に答える