2012-02-23 5 views
0

Хорошо, так что это действительно ужасно. Я никогда не встречал ничего подобного.Не удается создать экземпляр класса из другого пространства имен?

Часть моей программы (не удается скомпилировать) содержит три пространства имен следующим образом:

// namespaceA.h 
namespace A { 
enum Kind { jimmy, david }; 
} 
// end of namespaceA.h 

// namespaceB.h 
#include "namespaceA.h" 
namespace B { 
class Tree { 
    public: 
    Tree *prev; 
    Tree *next; 
    Tree *down; 
    A::Kind kind; 

    Tree(); 
    ~Tree(); 
}; 
} 
// end of namespaceB.h 
// Implementation details of the class are placed in namespaceB.cc 
// Constructor/Desctructor defined in the namespaceB.cc file! 
// Something like this, 
#include "namespaceB.h" 
namespace B { 
inline Tree::Tree() { ... } 
inline Tree::~Tree() { ... } 
} 

// namespaceC.cc 
#include "namespace.B" 
namespace C { 
void run() { 
    B::Tree *tree; // FINE 
    B::Tree tree;  // Fail to compile!? 
} 
} 
// end of namespaceC.cc 

Теперь г ++ шел очень хорошо, но компоновщик л.д. жалуется:

"namespaceC.cc: undefined reference to `B::Tree::Tree()' 
"namespaceC.cc: undefined reference to `B::Tree::~Tree()' 

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

Я был бы очень признателен за любую помощь.

Спасибо,

+0

Как вы пытаетесь его связать? Похоже, вы забыли связать с файлом, где B определен. – Tim

+0

Я скомплектовываю всю программу глупо. Я просто "g ++ -Wall *" это. Может быть, это проблема? –

+0

Это должно сработать. Я помню, что у меня были проблемы с встроенными конструкторами, возможно, вы могли бы попытаться удалить строку inline перед B :: Tree() и Tree :: ~ Tree() – Tim

ответ

2

Ваши определения B::Tree::Tree() и B::Tree::~Tree() объявлены рядный. Это означает, что они доступны только в этом исходном файле, а не в других.

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

+0

Вы, сэр, мужчина! Большое спасибо. И здесь я думал, что вложение улучшит эффективность и таковую. Сегодня я пробыл до 4 утра. ЧЕЛОВЕК СПАСИБО СООО МНОГО! –

1

Вы должны написать конструктор и деструктор B::Tree где-либо встроенный или в namespaceB.cc. Создав экземпляр B, вы требуете существования конструктора и деструктора.

+0

Да, я сделал это только в namespaceB.cc с чем-то по строке «inline Tree :: Tree() {...} ...» –

2
namespaceC.cc: undefined reference to `B::Tree::Tree()' 
namespaceC.cc: undefined reference to `B::Tree::~Tree()' 

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

См this answer для того, что это заявление и что такое определение и то, что они хороши/необходимы для.

+0

Я определил конструктор и деструктор в файле namespaceB.cc , Я отредактирую свой вопрос, чтобы уточнить его. –

+0

@BeyondSora: тогда вы либо не скомпилировали файл namespacB.cc, либо не передали результирующий объектный файл в компоновщик. Поскольку сообщение об ошибке однозначно говорит, что компоновщик не может найти такое определение. – sbi

0

Указатель компилируется отлично, потому что все указатели одинаковы. Это просто семантика, допускаемая для разных типов объектов.
Он бы скомпилировал поиск до тех пор, пока вы не попытались его использовать.
Но для создания фактического объекта вам нужно фактическое определение.

Чтобы использовать определение из другого пространства имен, вы использовали либо области, или использовать using:

#include "namespace.B" 
using namespace B; 
namespace C { 
void run() { 
    Tree *tree; // FINE 
    Tree tree;  // Fail to compile!? 
} 
} 

или:

#include "namespace.B" 
    namespace C { 
    void run() { 
     B::Tree *tree; // FINE 
     B::Tree tree;  // Fail to compile!? 
    } 
    } 
0

Вы объявляете Tree конструктора & деструктор, но вы не» t показать нам, где вы их определяете (вы просто говорите, что вы внедряете Tree в namespaceB.cc)

Предполагая, что вы определили их, вы должны убедиться, что вы включаете оба namespaceC.o и namespaceB.o на вашей линии ссылок.

0

Это не пространство имен проблема, не ошибка компилятора. Компилятор счастлив, но линкер не находит определения B::Tree::Tree(). Вам нужно предоставить исходный файл для реализации или использовать флаг -c для «просто компиляции».

0

Сначала вы объявили конструктор и деструктор класса Tree, поэтому компилятор не предоставил реализацию по умолчанию - вам нужно реализовать их самостоятельно! (Или просто удалите эти объявления ...).

Это не достаточно, чтобы включить заголовки, но вы должны явно сказать, что вы используете пространство имена из этих заголовков:

В namespaceC.cc добавить using namespace B; после включать namespace.B или, еще лучше, типы PREPEND с пространством имен классификатора :

B::Tree *tree;  
B::Tree tree;  
+0

Я злюсь, у меня было пространство имен в моей реальной программе ... Теперь я отредактирую свой квесто, чтобы исправить это. –

0

Я пробовал коды в Visual studio 2005. Если я удалю «inline» в namespaceB.cc для конструктора и деструктора, он может связываться без ошибок.

Тогда я нашел этот пост: G++ won't accept inline constructors in C++

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

+0

да, это похоже на случай. Я удалил все inline из моего кода на данный момент ... –

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