【问题标题】:Forward declaration cause "one or more multiplied defined symbol found"?前向声明导致“找到一个或多个多重定义的符号”?
【发布时间】:2019-01-29 05:01:28
【问题描述】:

我正在使用前向声明,并且我已经小心不要在头文件中进行任何定义(仅声明),并且在每个头文件之前都有#pragma once 指令。然而,不知何故,多重定义错误仍在发生。所以在 GlobalSys.h 中,我使用前向声明,然后我将把这个文件包含到任何需要访问这个全局变量的文件中。在 application.h 中,我初始化了这个全局变量,所以我必须包含 EventManager.h,否则编译器会报错。我哪里做错了?

GlobalSys.h

#pragma once
class EventManager;

namespace GlobalSys {
    EventManager * eventManager;
}

应用程序.h

#include "GlobalSys.h"
#include "../Event/EventManager.h" 

class Application {

public:
    Application();
};

应用程序.cpp

#include "Application.h"

Application::Application() {
    GlobalSys::eventManager = new EventManager();
}

【问题讨论】:

    标签: c++ declaration definition


    【解决方案1】:

    而且我已经小心不要在头文件中包含任何定义(仅声明)

    不,你是definedGlobalSys::eventManagerGlobalSys.h

    定义是完全定义由声明引入的实体的声明。每个声明都是一个定义,但以下内容除外:

    • 任何带有外部存储类说明符或语言链接说明符(例如 extern "C")但没有初始化器的声明

    您可以使用extern 将其更改为声明。

    GlobalSys.h

    #pragma once
    class EventManager;
    
    namespace GlobalSys {
        extern EventManager * eventManager; // declaration
    }
    

    然后在另一个实现文件中定义它,例如

    GlobalSys.cpp

    #include "GlobalSys.h"
    
    namespace GlobalSys {
        EventManager * eventManager; // definition
    }
    

    【讨论】:

    • 感谢您的回答,但我仍然对我的代码错误的原因感到困惑。我想如果你做这样的 EventManager * eventManager,它只是一个声明而不是一个定义?
    • @HarryKane 我在答案中添加了一些解释。
    【解决方案2】:

    once(和其他include guards)不会阻止多个定义。 once 防止标头被单个 cpp 文件包含两次 (translation unit)。如果多个翻译单元包含相同的标题,则它们都将拥有该标题中所有内容的自己的副本。这包括定义的变量和函数。所有这些翻译单元都是单独编译的,因此编译器的任何一次运行都不知道另一次运行已经包含了标头并生成了一个目标文件,该文件具有自己的相同内容的副本。

    然而,链接器必须将这些多个翻译单元整合到一个程序中。它会找到所有重复项。它没有试图理清程序员真正想要什么,而是放弃并要求程序员澄清。

    宋元尧的回答为这个问题提供了一种解决方案:用extern声明变量而不是在header中定义,然后在单个翻译单元中定义变量。这允许多个翻译单元共享一个变量。您可以使用 inline 关键字对函数定义执行相同的操作。

    有时,但这次不是,您希望每个翻译单元都有自己的变量。那样的话

    #pragma once
    class EventManager;
    
    namespace GlobalSys {
        namespace {
            EventManager * eventManager;
        }
    }
    

    匿名命名空间将eventManager 的链接限制为单个翻译单元,因此每个翻译单元的eventManager 不会发生冲突。

    【讨论】:

      猜你喜欢
      • 2011-09-22
      • 2012-09-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多