Многократно определенные символы - PullRequest
3 голосов
/ 12 мая 2009

Если я объявляю глобальную переменную в заголовочном файле и включаю ее в два файла .cpp, компоновщик выдает ошибку, говоря, что символ определен многократно. Мой вопрос: почему это происходит только для определенных типов объектов (например, int), а не для других (например, enum)?

Код теста, который я использовал, приведен ниже:

test.h

#ifndef TEST_HEADER
#define TEST_HEADER

namespace test
{           
        int i_Test1 = -1;
        int i_Test2 = -1;
};

#endif // TEST_HEADER

Class1.h

#ifndef CLASS_1_HEADER
#define CLASS_1_HEADER

class class1
{
public:
        void count();
};

#endif //CLASS_1_HEADER

class1.cpp

#include <iostream>
#include "class1.h"
#include "test.h"

void class1::count()
{
        std::cout << test::i_Test1 << std::endl;
}

class2.h

#ifndef CLASS_2_HEADER
#define CLASS_2_HEADER

class class2
{
public:
        void count();
};

#endif //CLASS_2_HEADER

class2.cpp

#include "class2.h"
#include <iostream>
#include "test.h"

void class2::count()
{
        std::cout << test::i_Test2 << std::endl;
}

main.cpp

#include "class1.h"
#include "class2.h"

int main(int argc, char** argv)
{
        class1 c1;
        class2 c2;
        c1.count();
        c2.count();
        return -1;
}

Создание этого кода с помощью:

g++ main.cpp class1.cpp class2.cpp -o a

производит следующий вывод:

ld: fatal: symbol test::i_Test1' is multiply-defined: (file /var/tmp//ccwWLyrM.o type=OBJT; file /var/tmp//ccOemftz.o type=OBJT); ld: fatal: symbol test :: i_Test2 'имеет несколько значений: (файл /var/tmp//ccwWLyrM.o type = OBJT; файл /var/tmp//ccOemftz.o тип = OBJT); ld: fatal: Обработка файлов ошибки. Нет вывода, записанного в collect2: ld вернул 1 статус выхода

Если я изменю файл test.h, как указано ниже:

test.h (с перечислением)

#ifndef TEST_HEADER
#define TEST_HEADER

namespace test
{
        enum val
        {
                i_Test1 = 5,
                i_Test2
        };
        //int i_Test1 = -1;
        //int i_Test2 = -1;
};

#endif // TEST_HEADER

Я не получаю ошибку "множественное определение", и программа выдает желаемый результат:

5
6

1 Ответ

21 голосов
/ 12 мая 2009

Это потому, что перечисления не являются объектами - они являются типами. Типы классов (class, struct, union) и перечисления могут определяться несколько раз по всей программе, при условии, что все определения удовлетворяют некоторым ограничениям (суммируемым так называемым One Definition Rule (ODR)). Два самых важных из них:

  • Все определения имеют одинаковую последовательность токенов (идентично тексту)
  • Используемые имена должны иметь одинаковое значение (разрешать одни и те же вещи) во всех определениях. (это требование в контексте определения)

Ваше определение перечисления удовлетворяет всем условиям ODR. Таким образом, это допустимо, и компоновщик / компилятор не имеет причин стонать (на самом деле, для нарушения ODR компилятору также не требуется выдавать сообщение - большая часть его относится к так называемому , диагностика не требуется). правило, некоторые нарушения также приводят к неопределенному поведению).

Однако для каждой не встроенной функции и объекта они должны быть определены только один раз. Умножьте их определение на ложные ошибки, как в вашем случае. Чтобы решить эту проблему, поместите только декларацию в заголовочный файл (используя «extern» без инициализатора) и поместите определение one в один из этих файлов .cpp (без «extern» затем, или установка инициализатора. Если это const-объект, вам все еще нужен "extern", так как по умолчанию переменные const имеют внутреннюю связь, и символ не экспортируется в противном случае).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...