В настоящее время я работаю над программой, которая использует пользователя виртуальных функций. Я использую только одну виртуальную функцию и натолкнулся на то, что кажется общей проблемой общего решения, которое я пробовал, но, к сожалению, безуспешно.
У меня изначально была виртуальная пустота calcArea (); в BasicShape.h без какого-либо определения или обозначения как чисто виртуальная функция. Я изменил его и добавил {} в конце (как предложено в другом потоке с похожей проблемой), но я все еще получаю следующую ошибку:
Я ввожу:
g++ BasicShape.h BasicShape.cpp circle.h circle.cpp Rectangle.h Rectangle.cpp driver.cpp -o Lab4
И тогда я получаю:
/tmp/ccf1Y4Br.o: In function `BasicShape::BasicShape()': circle.cpp:(.text._ZN10BasicShapeC2Ev[_ZN10BasicShapeC5Ev]+0xf): undefined reference to `vtable for BasicShape'
/tmp/ccf1Y4Br.o:(.rodata._ZTI6circle[_ZTI6circle]+0x10): undefined reference to `typeinfo for BasicShape'
/tmp/ccc7gjtH.o:(.rodata._ZTI9Rectangle[_ZTI9Rectangle]+0x10): undefined reference to `typeinfo for BasicShape'
collect2: error: ld returned 1 exit status
Есть идеи?
Это файл реализации BasicShape.h:
#ifndef BASICSHAPE_H
#define BASICSHAPE_H
class BasicShape
{
protected:
double area;
public:
double getArea() const;
virtual void calcArea();
};
#endif
Прилагаемый файл BasicShape.cpp:
#include "BasicShape.h"
double BasicShape::getArea() const
{
return area;
}
void BasicShape::calcArea()
{
}
circle.h:
#include "BasicShape.h"
#ifndef CIRCLE_H
#define CIRCLE_H
class circle : public BasicShape
{
private:
long centerX;
long centerY;
double radius;
public:
circle(long, long, double);
long getCenterX() const;
long getCenterY() const;
virtual void calcArea();
};
#endif
circle.cpp:
#include "circle.h"
// constructor
circle::circle(long userIn, long userIn2, double userIn3)
{
centerX = userIn;
centerY = userIn2;
radius = userIn3;
calcArea();
}
// accesors
long circle::getCenterX() const
{
return centerX;
}
long circle::getCenterY() const
{
return centerY;
}
// virtual function
void circle::calcArea()
{
area = (3.14159 * radius * radius);
}
Rectangle.h
#include "BasicShape.h"
#ifndef RECTANGLE_H
#define RECTANGLE_H
class Rectangle : public BasicShape
{
private:
long width;
long length;
public:
Rectangle(long, long);
long getWidth() const;
long getLength() const;
virtual void calcArea();
};
#endif
Rectangle.cpp:
#include "Rectangle.h"
// constructor
Rectangle::Rectangle(long userIn, long userIn2)
{
width = userIn;
length = userIn2;
calcArea();
}
// accessors
long Rectangle::getWidth() const
{
return width;
}
long Rectangle::getLength() const
{
return length;
}
void Rectangle::calcArea()
{
area = (length * width);
}
Программа драйвера неполная, но все равно не имеет отношения к моей проблеме (по крайней мере, я так думаю).
#include <cassert>
#include <iostream>
#include "BasicShape.h"#include "Rectangle.h"#include "circle.h"using namespace std;
int main()
{
cout << "Testing the functionality and efficiency of the circle class...\n";
// declare circle object and test accessors and area computation
circle objCircle(8,8,4);
assert(objCircle.getCenterX() == 8);
assert(objCircle.getCenterY() == 8);
assert(objCircle.getArea() == 50.26544);
cout << "Circle object testing completed successfully\n";
cout << "Testing the functionality and efficiency of the Rectangle class...\n";
// declare rectangle object and test accessors and area computation
//Rectangle objRec();
return 0;
}
На самом деле, как было указано, вы не должны компилировать заголовки. (Хотя вы можете, это не имеет значения здесь — gcc будет генерировать предварительно скомпилированные заголовки).
И еще интереснее: ваш пример отлично работает здесь, GCC 4.6.3.
Кроме того, sidenote: calcArea не должно быть публичным
Вы не должны пытаться скомпилировать заголовки:
g ++ BasicShape.cpp circle.cpp Rectangle.cpp driver.cpp -o Lab4
Вашему компилятору нужен как минимум один модуль перевода, где виртуальный член определен вне определения класса для каждого полиморфного класса. Он будет создавать некоторые внутренние данные для класса (таблица виртуальных функций, полиморфная информация о типах), только если есть такая единица перевода.
(Отказ от ответственности: по крайней мере, это был тот случай, когда я последний раз использовал его, давно)
Вы можете использовать определение вне класса для BasicShape::calcArea
функционировать или добавить виртуальный (необязательно даже чисто виртуальный) деструктор в BasicShape
и определить его вне класса. Лучшее место, вероятно, будет BasicShape.cpp
файл.
Кстати: как уже отмечали другие, вы, как правило, не должны передавать заголовочные файлы как отдельные единицы перевода в компилятор. Это не принесет вреда (кроме раздувания времени компиляции), но также не принесет пользы.
Итак, по-видимому, все это, похоже, проблема компилятора. Все это время я использовал gedit в качестве текстового редактора и g ++ в качестве компилятора, но когда я переключился на блоки кода, он работал просто отлично.