Visual C++中向命名空间添加可修改变量引发链接错误求助
解决命名空间中全局变量的多重定义链接错误
问题场景
在包含CongregationDatabaseManager命名空间的头文件中添加两个可修改的全局变量后,出现LNK2005多重定义链接错误。
原头文件代码
#ifndef CONGREGATION_DATABASE_MANAGER #define CONGREGATION_DATABASE_MANAGER #pragma once namespace CongregationDatabaseManager { int iEditMenuID; int iDeleteMenuID; static const COLORREF GetAssignedTextColour() { return theApp.GetNumberSetting(L"Options", L"AssTextColour", PALETTERGB(0, 0, 255)); } } #endif
链接错误信息
7>CongregationOptionsDlg.obj : error LNK2005: "int CongregationDatabaseManager::iLocalEditMenuId" (?iLocalEditMenuId@CongregationDatabaseManager@@3HA) already defined in CongregationDlg.obj 7>CongregationOptionsDlg.obj : error LNK2005: "int CongregationDatabaseManager::iLocalDeleteMenuId" (?iLocalDeleteMenuId@CongregationDatabaseManager@@3HA) already defined in CongregationDlg.obj 7>CongregationSpeakerDlg.obj : error LNK2005: "int CongregationDatabaseManager::iLocalEditMenuId" (?iLocalEditMenuId@CongregationDatabaseManager@@3HA) already defined in CongregationDlg.obj 7>CongregationSpeakerDlg.obj : error LNK2005: "int CongregationDatabaseManager::iLocalDeleteMenuId" (?iLocalDeleteMenuId@CongregationDatabaseManager@@3HA) already defined in CongregationDlg.obj 7>ChristianLifeMinistryStudentMaterialDlg.obj : error LNK2005: "int CongregationDatabaseManager::iLocalEditMenuId" (?iLocalEditMenuId@CongregationDatabaseManager@@3HA) already defined in CongregationDlg.obj 7>ChristianLifeMinistryStudentMaterialDlg.obj : error LNK2005: "int CongregationDatabaseManager::iLocalDeleteMenuId" (?iLocalDeleteMenuId@CongregationDatabaseManager@@3HA) already defined in CongregationDlg.obj 7>Meeting Schedule Assistant.obj : error LNK2005: "int CongregationDatabaseManager::iLocalEditMenuId" (?iLocalEditMenuId@CongregationDatabaseManager@@3HA) already defined in CongregationDlg.obj 7>Meeting Schedule Assistant.obj : error LNK2005: "int CongregationDatabaseManager::iLocalDeleteMenuId" (?iLocalDeleteMenuId@CongregationDatabaseManager@@3HA) already defined in CongregationDlg.obj 7>Meeting Schedule AssistantDlg.obj : error LNK2005: "int CongregationDatabaseManager::iLocalEditMenuId" (?iLocalEditMenuId@CongregationDatabaseManager@@3HA) already defined in CongregationDlg.obj 7>Meeting Schedule AssistantDlg.obj : error LNK2005: "int CongregationDatabaseManager::iLocalDeleteMenuId" (?iLocalDeleteMenuId@CongregationDatabaseManager@@3HA) already defined in CongregationDlg.obj 7>WeekendMeetingDlg.obj : error LNK2005: "int CongregationDatabaseManager::iLocalEditMenuId" (?iLocalEditMenuId@CongregationDatabaseManager@@3HA) already defined in CongregationDlg.obj 7>WeekendMeetingDlg.obj : error LNK2005: "int CongregationDatabaseManager::iLocalDeleteMenuId" (?iLocalDeleteMenuId@CongregationDatabaseManager@@3HA) already defined in CongregationDlg.obj 7>PublishersDatabaseDlg.obj : error LNK2005: "int CongregationDatabaseManager::iLocalEditMenuId" (?iLocalEditMenuId@CongregationDatabaseManager@@3HA) already defined in CongregationDlg.obj 7>PublishersDatabaseDlg.obj : error LNK2005: "int CongregationDatabaseManager::iLocalDeleteMenuId" (?iLocalDeleteMenuId@CongregationDatabaseManager@@3HA) already defined in CongregationDlg.obj 7>D:\My Programs\2022\MeetSchedAssist\Meeting Schedule Assistant\Release\Meeting Schedule Assistant.exe : fatal error LNK1169: one or more multiply defined symbols found
错误原因
头文件中直接写int iEditMenuID;属于变量定义,当多个源文件包含该头文件时,每个源文件都会生成该变量的独立副本。链接阶段,链接器发现多个相同符号的定义,就会抛出LNK2005错误。
解决方案
遵循C++分离编译规则,将变量的声明和定义分开:
步骤1:修改头文件,仅声明变量
在头文件中用extern关键字声明变量,告诉编译器变量的存在,实际定义在其他文件中:
#ifndef CONGREGATION_DATABASE_MANAGER #define CONGREGATION_DATABASE_MANAGER #pragma once namespace CongregationDatabaseManager { // 仅声明变量,不定义 extern int iEditMenuID; extern int iDeleteMenuID; static const COLORREF GetAssignedTextColour() { return theApp.GetNumberSetting(L"Options", L"AssTextColour", PALETTERGB(0, 0, 255)); } } #endif
步骤2:创建单独的.cpp源文件,定义变量
新建一个比如CongregationDatabaseManager.cpp的文件,在其中定义变量,提供唯一的实例:
#include "CongregationDatabaseManager.h" namespace CongregationDatabaseManager { // 变量的实际定义,仅此处存在一份 int iEditMenuID; int iDeleteMenuID; }
额外说明
如果需要给变量初始化默认值,直接在.cpp的定义处添加即可,比如:
int iEditMenuID = 0; int iDeleteMenuID = 0;
这样修改后,所有包含头文件的源文件都会共享.cpp中定义的唯一变量实例,链接错误就会消除。
内容的提问来源于stack exchange,提问作者Andrew Truckle
相关产品推荐
相关产品推荐

