2009-11-07 2 views
1

Все в порядке, и последняя проблема настолько раздражает. Компиляция велик, но ссылка не удается:Что мне делать с этой странной ошибкой?

bash-3.2$ make 
g++ -Wall -c -g Myworld.cc 
g++ -Wall -g solvePlanningProblem.o Position.o AStarNode.o PRM.o PRMNode.o World.o SingleCircleWorld.o Myworld.o RECTANGLE.o CIRCLE.o -o solvePlanningProblem 

**Undefined symbols: 

"vtable for Obstacle", referenced from: 
     Obstacle::Obstacle()in Myworld.o 

"typeinfo for Obstacle", referenced from: 
     typeinfo for RECTANGLEin RECTANGLE.o 
     typeinfo for CIRCLEin CIRCLE.o 

ld: symbol(s) not found 

collect2: ld returned 1 exit status 

make: *** [solvePlanningProblem] Error 1** 

Obstacle.hh

#ifndef Obstacle_hh 
#define Obstacle_hh 

#include <vector> 
#include <iostream> 

class Obstacle{ 
public: 
    Obstacle(){} 
    virtual bool collidesWith(double x,double y); 
    virtual void writeMatlabDisplayCode(std::ostream &fs); 
    virtual ~Obstacle(){} 
}; 
#endif 

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

+0

У вас есть класс «Препятствие», если это так, у каких исходных файлов есть определения для его функций-членов? –

+0

дубликат? http://stackoverflow.com/questions/1693634/undefined-symbols-vtable-for-and-typeinfo-for – Amro

+0

yes, Class Obstacle - базовый класс с двумя подклассами CIRCLE и RECTANGLE. все они имеют две общие виртуальные функции. – Lisa

ответ

4

Вы объявляете не-абстрактный класс Obstacle, но не выполняете все его функции-члены.

Лучше объявить его как абстрактный класс:

class Obstacle{ 
public: 
    Obstacle(){} // this is superfluous, you can (and should) remove it 
    virtual bool collidesWith(double x,double y) = 0; 
    virtual void writeMatlabDisplayCode(std::ostream &fs) = 0; 
    virtual ~Obstacle(){} 
}; 

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

Ваш код пленками эту схему: Вы включаете Obstacle.hh в какой-то единицы компиляции, компилятор видит класс Obstacle, который имеет collidesWith как первый не-инлайн виртуальной функции-члена, но она не определена в текущем модуле компиляции, поэтому компилятор считает, что он может отложить создание vtable и typeinfo для класса. Поскольку нет определения collidesWith, они оба теряются, когда программа связана.

+0

это действительно имеет смысл, но эти два вирутальных функционала связаны с ошибкой «typeinfo for Obstacle»? – Lisa

+0

отредактировал мой ответ, чтобы объяснить причины - надеюсь, что это не слишком сложно ... – hjhill

+0

Большое вам спасибо. кратким и правильным! – Lisa

2

Видимо, вам не хватает и объектного файла или библиотеки. Тот, который определяет и объявляет объект Obstacle.

Хорошее место для поиска файлов заголовков (* .h), указанных в Myworld, так как это даст вам представление о том, что cpp/libraries (обычно с тем же именем) лежат в основе объектов, используемых Мой Мир.

Редактировать, учитывая ответ Лизы:
Нет, вам не нужно добавлять файлы * .hh в исходный код. Проблема заключается в времени соединения, а не во время компиляции.
Нет ли там файла Obstacle.cpp? Это нужно будет скомпилировать, и соответствующие файлы .o должны быть добавлены в последнюю строку gcc в make.

Bingo! Увидев Obstacle.hh
Эти два виртуальных метода не являются чисто виртуальными, и, следовательно, компилятор ожидает, что они каким-то образом будут определены. А также конструктор и деструктор не определены.
Самый простой, вероятно, будет писать что-то вроде:

class Obstacle{ 
public: 
    // Obstacle(); 
    virtual bool collidesWith(double x,double y) = 0; // = 0 makes them pure virtual 
    virtual void writeMatlabDisplayCode(std::ostream &fs) = 0; 
    //~Obstacle(); 
}; 

В качестве альтернативы вы можете объявить небольшое ничегонеделания конструктор и деструктор или вы могли бы сделать деструктор [чистого] виртуальной, чтобы заставить производные классы реализовать destructor ...

+0

в MyWorld, #include "World.hh" #include "Obstacle.hh" #include "CIRCLE.hh" #include "RECTANGLE.hh" включено там что-то не так с этим, так как RECTANGLE и Круговые подклассы препятствия. следует ли включать «CIRCLE.hh» и «RECTANGLE.hh»? – Lisa

+0

У меня нет Obstacle.cc и Obstacle.o, потому что я думаю, что это не нужно, потому что препятствие.hh имеет ничего, кроме некоторой виртуальной функции и конструктора. – Lisa

+0

Можете ли вы разместить Obstacle.hh (или соответствующие фрагменты из него)? – mjv

0

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

+0

Препятствие - это просто базовый класс для RECANGLE и CIRCLE. поэтому я просто включаю «Obstacle.hh» в myworld.hh. это нормально – Lisa

+0

Это не нормально. Вам нужны реальные определения. – alternative

+0

Как я могу сделать реальное определение? – Lisa

2

Препятствие класса требует виртуального деструктора. Измените определение деструктора быть:

virtual ~Obstacle(); 

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

+0

+1, в любом случае это жизненно важно для класса с виртуальными методами. Другой вопрос - вам нужна реализация. –

+0

@ Roman Nikitchenko: Это не _vital_ для классов с виртуальными методами. Это очень важно, если вы собираетесь удалять производные классы с помощью указателей на этот базовый класс. Это обычная альтернатива для защиты защищенных и не виртуальных деструкторов базового класса. –

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