前向声明原因"one or more multiplied defined symbol found"?
Forward declaration cause "one or more multiplied defined symbol found"?
我使用的是前向声明,我已经注意不要在头文件中有任何定义(只有声明),并且在每个头文件之前都有#pragma once指令。然而,不知何故,多重定义错误仍在发生。所以在 GlobalSys.h 中,我使用前向声明,然后我将把这个文件包含到任何需要访问这个全局变量的文件中。在 application.h 中,我初始化了这个全局变量,所以我必须包含 EventManager.h 否则编译器会报错。我哪里做错了?
GlobalSys.h
#pragma once
class EventManager;
namespace GlobalSys {
EventManager * eventManager;
}
Application.h
#include "GlobalSys.h"
#include "../Event/EventManager.h"
class Application {
public:
Application();
};
Application.cpp
#include "Application.h"
Application::Application() {
GlobalSys::eventManager = new EventManager();
}
and I have already been careful not to have any definition inside header files (only declaration)
不,你 defined GlobalSys::eventManager
在 GlobalSys.h
.
Definitions are declarations that fully define the entity introduced by the declaration. Every declaration is a definition, except for the following:
- Any declaration with an extern storage class specifier or with a language linkage specifier (such as extern "C") without an initializer
您可以使用 extern
.
将其更改为声明
GlobalSys.h
#pragma once
class EventManager;
namespace GlobalSys {
extern EventManager * eventManager; // declaration
}
然后在另一个实现文件中定义它,例如
GlobalSys.cpp
#include "GlobalSys.h"
namespace GlobalSys {
EventManager * eventManager; // definition
}
once
(以及其他 include guards) won't prevent multiple definitions. once
prevents a header from being included twice by a single cpp file (translation unit)。如果多个翻译单元包含相同的 header,它们都将拥有该 header 中所有内容的副本。这包括定义的变量和函数。所有这些翻译单元都是单独编译的,所以编译器的任何一个 运行 都不知道另一个 运行 已经包含了 header 并生成了一个 object 文件,其中有它的自己的相同内容副本。
但是,链接器必须将这些多个翻译单元放入一个程序中。它找到了所有的重复项。与其试图梳理程序员真正想要的是什么,不如放弃,请程序员澄清。
Songyuanyao的回答为这个问题提供了一种解决方法:用extern
声明变量而不是在header中定义变量,然后在单个翻译单元中定义变量。这允许多个翻译单元共享一个变量。您可以使用 inline
关键字对函数定义执行相同的操作。
有时,但这次不会,您希望每个翻译单元都有自己的变量。那样的话
#pragma once
class EventManager;
namespace GlobalSys {
namespace {
EventManager * eventManager;
}
}
匿名命名空间将 eventManager
的链接限制为单个翻译单元,因此每个翻译单元的 eventManager
不会冲突。
我使用的是前向声明,我已经注意不要在头文件中有任何定义(只有声明),并且在每个头文件之前都有#pragma once指令。然而,不知何故,多重定义错误仍在发生。所以在 GlobalSys.h 中,我使用前向声明,然后我将把这个文件包含到任何需要访问这个全局变量的文件中。在 application.h 中,我初始化了这个全局变量,所以我必须包含 EventManager.h 否则编译器会报错。我哪里做错了?
GlobalSys.h
#pragma once
class EventManager;
namespace GlobalSys {
EventManager * eventManager;
}
Application.h
#include "GlobalSys.h"
#include "../Event/EventManager.h"
class Application {
public:
Application();
};
Application.cpp
#include "Application.h"
Application::Application() {
GlobalSys::eventManager = new EventManager();
}
and I have already been careful not to have any definition inside header files (only declaration)
不,你 defined GlobalSys::eventManager
在 GlobalSys.h
.
Definitions are declarations that fully define the entity introduced by the declaration. Every declaration is a definition, except for the following:
- Any declaration with an extern storage class specifier or with a language linkage specifier (such as extern "C") without an initializer
您可以使用 extern
.
GlobalSys.h
#pragma once
class EventManager;
namespace GlobalSys {
extern EventManager * eventManager; // declaration
}
然后在另一个实现文件中定义它,例如
GlobalSys.cpp
#include "GlobalSys.h"
namespace GlobalSys {
EventManager * eventManager; // definition
}
once
(以及其他 include guards) won't prevent multiple definitions. once
prevents a header from being included twice by a single cpp file (translation unit)。如果多个翻译单元包含相同的 header,它们都将拥有该 header 中所有内容的副本。这包括定义的变量和函数。所有这些翻译单元都是单独编译的,所以编译器的任何一个 运行 都不知道另一个 运行 已经包含了 header 并生成了一个 object 文件,其中有它的自己的相同内容副本。
但是,链接器必须将这些多个翻译单元放入一个程序中。它找到了所有的重复项。与其试图梳理程序员真正想要的是什么,不如放弃,请程序员澄清。
Songyuanyao的回答为这个问题提供了一种解决方法:用extern
声明变量而不是在header中定义变量,然后在单个翻译单元中定义变量。这允许多个翻译单元共享一个变量。您可以使用 inline
关键字对函数定义执行相同的操作。
有时,但这次不会,您希望每个翻译单元都有自己的变量。那样的话
#pragma once
class EventManager;
namespace GlobalSys {
namespace {
EventManager * eventManager;
}
}
匿名命名空间将 eventManager
的链接限制为单个翻译单元,因此每个翻译单元的 eventManager
不会冲突。