@frilix
Иногда "творю"

Надо решить проблему с include?

доброго времени суток, возникла проблема при компилировании. Дело в том, что я использую заголовочный файл, где храню глобальные переменные. Мне надо использовать его в 2 классах, но оба этих класса используются в третьем, а при компилировании выскакивает ошибка Multiple definition of first defined here. Помогите решить проблему или подкиньте альтернативу для хранения констант.

#ifndef CONSTANTS_H_INCLUDED
#define CONSTANTS_H_INCLUDED

// Interface Constants
const int LEFTPANEL = 200;
const int TOPPANEL  = 50;

// Window Defaults
const int WINDOW_WIDTH  = 800;
const int WINDOW_HEIGHT = 600;

// Text Defaults
int SYMBOL_WIDTH = 12;
int LINE_HEIGHT  = 20;
const int LINE_PADDING = 4;

#endif // CONSTANTS_H_INCLUDED
  • Вопрос задан
  • 344 просмотра
Решения вопроса 1
@Mercury13
Программист на «си с крестами» и не только
Учи понятие «единица компиляции».

Два варианта.
a) Несколько единиц компиляции (основной вариант, когда идёт активная разработка проекта). Тогда в хедере каждую переменную отмечаешь модификатором extern — «переменная есть, но где-то в другом месте». В одной из единиц компиляции объявляешь переменные, уже без extern.

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

///// unit.h /////
#ifndef UNIT_H
#define UNIT_H

extern int myVar;

#endif

///// unit.cpp /////
#include "unit.h"

int myVar;

///// main.cpp /////
#include "unit.h"

int main()
{
   myVar = 1;
}


б) Одна большущая единица компиляции (в такой вид часто преобразуют библиотеки перед выпуском). Тогда достаточно оградить каждый хедер от двойного включения, и всё в порядке.

///// unit.h /////
#ifndef UNIT_H
#define UNIT_H

int myVar;

#endif

///// main.cpp /////
#include "unit.h"

int main()
{
   myVar = 1;
}


ЗЫ. Когда я писал ответ, кода ещё не было. А тут он взял и пришёл. Для переменных (SYMBOL_WIDTH, LINE_HEIGHT) решение то самое. А для констант вариантов несколько.

Путь сишный.
#define LEFTPANEL 200
ВОЗМОЖНО для литеральных констант, и особенно классно работает с текстовыми строками (например, "[" TEXT "]").
НЕДОСТАТКИ: это препроцессор, и при пересечении имён будет нехорошо.

Путь перечислимый.
enum {
  LEFTPANEL = 200
};
ВОЗМОЖНО для констант, влезающих в int.
НЕДОСТАТКИ: возможны приколы с кроссплатформенностью, если на отдельных платформах константа вылезет за грань int.

Путь переменный.
extern const int LEFTPANEL;
....
const int LEFTPANEL = 200;
ВОЗМОЖНО для любых констант.
НЕДОСТАТКИ: нет вычисления при компиляции. Только линкер знает, что это 200.

Путь C++11.
constexpr int LEFTPANEL = 200;
ВОЗМОЖНО для литеральных констант.
НЕДОСТАТКИ: только C++11.

Путь «на рывок»
static const int LEFTPANEL = 200;
ВОЗМОЖНО для всех литеральных типов, но при этом может создавать дублирующиеся переменные: так, в Borland будет дублироваться всё сверх int — и, соответственно, не допускать предкомпилированных заголовков, ибо создаётся код.
НЕДОСТАТКИ: семантика зависит от компилятора и типа, ради чего и сделали constexpr.
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
GavriKos
@GavriKos
#pragma once для майкрософтовского компилятора, ну или аналог прагмы с дефайнами:
#ifndef MODULE_NAME
#define MODULE_NAME
тело модуля
#endif
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы