使用命名空间来创建全局函数,但是获得多个定义的符号错误

时间:2011-08-05 22:01:43

标签: c++ linker-errors precompiled-headers

这些函数是我的大多数程序对象将使用的实用程序类型的东西。我希望将它们放在命名空间中并使它们具有全局性。此命名空间在标头中定义,然后添加到我的预编译标头中。但到目前为止,我已经在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

和我的预编译标题

// 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类标题相同。

2 个答案:

答案 0 :(得分:10)

您的函数定义(即:源代码)不应位于标题中。您获得多个定义的原因是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;
    }
};

虽然你应该只将它用于小功能。

答案 1 :(得分:2)

Manager.cppBot.cpp都包含Util.h

因此,在编译它们时,两个目标文件都会导出符号“GetRandomBetween”。当链接器将这些目标文件组合成可执行文件时,它会找到该函数的2个实例。链接器无法确定使用哪一个(并且它不理解它们是相同的)。

如果要使对象文件不导出符号(这样就不会发生链接器冲突),请删除extern关键字。