Объявление вперед вызывает "найден один или несколько умноженных определенных символов"? - PullRequest
0 голосов
/ 29 января 2019

Я использую предварительное объявление, и я уже был осторожен, чтобы не иметь никаких определений внутри заголовочных файлов (только объявление), а также иметь директиву #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();
}

Ответы [ 2 ]

0 голосов
/ 29 января 2019

once (и другие включают охрану ) не будут препятствовать множественным определениям.once предотвращает включение заголовка дважды одним файлом cpp ( единица перевода ).Если несколько блоков перевода включают в себя один и тот же заголовок, у всех них будет своя копия всего в этом заголовке.Это включает в себя определенные переменные и функции.Все эти модули перевода скомпилированы отдельно, поэтому любой прогон компилятора не знает, что другой прогон уже включил заголовок и создал объектный файл, который имеет свою собственную копию того же материала.

The Linker,однако, нужно взять эти несколько единиц перевода и объединить их в одну программу.И он находит все дублирование.Вместо того, чтобы пытаться разобраться, что на самом деле хочет программист, он сдается и просит программиста уточнить.

Ответ Songyuanyao дает одно решение этой проблемы: объявите переменную с помощью extern вместо ее определения взаголовок, а затем определить переменную в одной единице перевода.Это позволяет нескольким переводчикам использовать одну переменную.Вы можете сделать то же самое с определением функции с ключевым словом inline.

Иногда, , но не на этот раз , вы хотите, чтобы каждая единица перевода имела свою собственную переменную.В этом случае

#pragma once
class EventManager;

namespace GlobalSys {
    namespace {
        EventManager * eventManager;
    }
}

Анонимное пространство имен ограничивает связь eventManager с одной единицей перевода, поэтому eventManager каждой единицы перевода не конфликтуют.

0 голосов
/ 29 января 2019

и я уже был осторожен, чтобы не иметь никаких определений внутри заголовочных файлов (только объявление)

Нет, вы определены GlobalSys::eventManager в GlobalSys.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
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...