2012-06-20 2 views
3

У меня есть два файла с именем file_utils.h и file_utils.cpp, которые содержат некоторые методы и переменные, которые используются разными классами. Вот пример того, как это выглядит:C++ extern ключевое слово и глобальные переменные

file_utils.h:

namespace my_namespace 
{ 
extern Foo* foo; 
extern Bar* bar; 

void my_function(Blah* blah); 
} 

file_utils.cpp

#include "file_utils.h" 

void my_namespace::my_function(Blah* blah) 
{ 
    foo = 0; // undefined reference to my_namespace::foo 
    bar = 0; // undefined reference to my_namespace::bar 
    //... 
} 

some_class.cpp

#include "file_utils.h" 

some_function() 
{ 
    my_namespace::my_function(blah); 
    this->foo = *my_namespace::foo; // will that work ok? 
} 

Таким образом, ошибки в комментариях , Если я удалю ключевое слово extern, я получаю ошибку multiple definition of my_namespace::foo. В чем проблема? Это даже хорошая идея с точки зрения дизайна, или я должен попытаться использовать класс со статическими элементами и методами вместо этого?

+5

вы должны ** определить ** свои объекты где-нибудь, в '.cpp', а 'extern' only ** объявляет ** объект со статической связью. – akappa

ответ

7

Проблема в том, что вы только объявили, но не определены переменные.

Вы должны обеспечить определение в одном файле реализации:

file_utils.cpp

#include "file_utils.h" 

//definition: 
namespace my_namespace 
{ 
    Foo* foo; 
    Bar* bar; 
} 

//alternatively, to keep the same formatting you have 
//Foo* my_namespace::foo; 
//Bar* my_namespace::bar; 

void my_namespace::my_function(Blah* blah) 
{ 
    foo = 0; 
    bar = 0; 
    //... 
} 
+1

Я предпочитаю стиль, который вы закомментировали, 'Foo * my_namespace :: foo;'. Таким образом, ошибочное имя переменной вызовет ошибку компиляции, вместо того, чтобы молча объявить новую переменную. –

+0

@MikeSeymour: попытаться скомпилировать "пространство имен ns {} char * ns :: foo;" и посмотреть, что вы получаете. – abarnert

0

Начнем с того, я бы действительно рекомендуем вам уточнить себе два отличия:

  • Объявление об определении
  • компилятор vs линкер

В вашем случае вы получаете ошибку компоновщика. Неопределенная ссылка означает, что ваш код указывает где-то, но компоновщик не может определить, где.

Ключевое слово extern используется для подавления ошибки компилятора при использовании объекта, найденного где-то в вашем коде. В вашем примере компоновщик пытается найти экземпляры ваших классов, но не работает. Это обычно не используется с указателями (исправьте меня, если я ошибаюсь). Поэтому :

utils.h:

namespace mySpace{ 
    extern Foo foo; // notes that foo of type Foo will be used. 

    void myFn(); 
} 

utils.cpp:

#include "utils.h" 

void mySpace::myFn(){ 
    foo.bar = 5; // changes a member of foo from globals.cpp 
} 

globals.cpp

Foo mySpace::foo; // this is the actual foo used. 

Если вы хотите, чтобы ваш вопрос о some_class.cpp ответил, пожалуйста, предоставьте сообществу знания о том, что такое conversions и чего вы хотите достичь.

Судя по семантике, я считаю, что это ссылка на члена класса conversions.

+0

Это была опечатка, должно было быть 'my_namespace :: foo'. – jaho

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