Заголовок C++ не может быть включен без ошибки LNK2005

У меня есть большой проект, который предназначен для контроля и тестирования оборудования.

Существует 4 класса управления устройствами (для интерферометров, пьезодвигателя, системы PXI и контроллера нанопозиционирования).

Я создал «главный» класс под названием MainIO, в котором хранится экземпляр каждого из вышеперечисленных классов, чтобы выполнять операции во всем диапазоне ввода-вывода (например, перемещать двигатель и проверять интерферометры). Заголовочный файл MainIO включает в себя 4 заголовка управляющих классов.

Затем у меня есть отдельный «глобальный» файл hpp/cpp, который содержит глобальные переменные, преобразования, операции с файлами ini и так далее. Это выложено с пространствами имен для типов операций, а не для создания класса, то есть GCONV::someFunction(); и GMAIN::controllerModel;

Мне нужно, чтобы все 4 класса управления имели доступ к преобразованию и другим глобальным операциям. У меня были они все, включая global.hpp в какой-то момент, но я что-то изменил (не могу придумать, что это может быть!), и теперь кажется, что я не могу включить global.hpp ни в ЛЮБОЙ из моих классов управления hpp или cpp. без получения ошибки компоновщика -

global.obj:-1: error: LNK2005: "class QString GMAIN::controllerModel" (?controllerModel@GMAIN@@3VQString@@A) already defined in controllers.obj

Я абсолютно уверен, что сделал что-то глупое, и решение смотрит мне прямо в лицо, но дело дошло до того, что я настолько разочаровался в этом, что не вижу леса за деревьями.


person Sam Frost    schedule 14.11.2014    source источник


Ответы (3)


Я обнаружил, что я делал неправильно, и хотя это досадно просто, мне потребовалось некоторое время, чтобы найти соответствующую документацию, чтобы обнаружить мою ошибку, и поэтому я отвечу на свой вопрос в надежде облегчить кому-то жизнь.

Оказывается, в global.hpp я объявлял переменные в пространстве имен следующим образом:

namespace GMAIN {
    QString controllerModel;
}

По сути, это означает, что каждый файл, содержащий global.hpp, будет включать собственное определение QString controllerModel, что приведет к ошибке компоновщика. Каждый класс управления будет иметь свое собственное определение одной и той же именованной переменной, нарушая правило одного определения.

Чтобы исправить это, QString controllerModel должен быть экстернирован. Ключевое слово extern позволяет объявлять переменную в нескольких местах, имея только одно определение (и, следовательно, не нарушая правила).

Итак, рабочий код теперь:

//in global.hpp
namespace GMAIN {
    extern QString controllerModel; //declaration - this is called for each `#include global.hpp`
}

//in global.cpp
namespace GMAIN {
    QString controllerModel; //definition - only called once as .cpp is never included
}
person Sam Frost    schedule 14.11.2014

Вы определяете controllerModel, где вы должны только объявлять его? http://www.cprogramming.com/declare_vs_define.html

person Tony Park    schedule 14.11.2014
comment
спасибо, я обнаружил свою ошибку прямо перед вашим комментарием, но проблема была именно в этом - person Sam Frost; 14.11.2014

Вы должны экспортировать свою dll. Используйте 1_. Вы можете включить __declspec(dllexport) в качестве макроса в файл заголовка и поместить макрос в начало каждой функции-члена.

Например: В вашем файле Header.h включите

#define MYMACRO __declspec(dllexport);

и в вашем классе

class classname
{
  public:
  MYMACRO void MYFUNCTION();
  MYMACRO void MYFUNCTION2();
};
person Anil Solanki    schedule 14.11.2014