2009-05-12 2 views
3

Если я объявляю глобальную переменную в файле заголовка и включаю ее в два .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: фатальный: символ 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; file /var/tmp//ccOemftz.o type = OBJT); ld: fatal: Обработка файлов ошибок. Нет сигнала на выходе записывается в collect2: л.д. не возвращается 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 

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

5 
6 

ответ

21

Это потому, что перечисления не являются объектами cts - это типы. Типы классов (класс, структура, объединение) и перечисления могут быть определены несколько раз в течение всей программы, если все определения удовлетворяют некоторым ограничениям (суммируются так называемым Правило одного определения (ODR)). Два наиболее важных из них являются

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

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

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

Смежные вопросы