4

I try to implement examples of "C++ An Introduction To Programming" by Jesse Liberty and Tim Keogh but on implementing pure virtual functions is compiling but not building. It is giving the error : undefined reference to 'vtable for circle'

I have tried substituting the variable itsRadius for a virtual function GetItsRadius to see if it would work but it started giving me the same errors in the switch statement but for Rectangle and Square and also the same error as before for circle.

Here is the code:

#include <iostream>

using namespace std;

enum BOOL { FALSE, TRUE };

class Shape
{
    public:
        Shape(){}
        ~Shape(){}
        virtual long GetArea() = 0; // error
        virtual long GetPerim()= 0;
        virtual void Draw() = 0;
    private:
};

void Shape::Draw()
{
    cout << "Abstract drawing mechanism!\n";
}

class Circle : public Shape
{
    public:
        Circle(int radius):itsRadius(radius){}
        ~Circle(){}
        long GetArea() { return 3 * itsRadius * itsRadius; }
        long GetPerim() { return 9 * itsRadius; }
        void Draw();
    private:
        int itsRadius;
        int itsCircumference;
};

class Rectangle : public Shape
{
    public:
        Rectangle(int len, int width):
        itsLength(len), itsWidth(width){}
        ~Rectangle(){}
        long GetArea() { return itsLength * itsWidth; }
        long GetPerim() { return 2*itsLength + 2*itsWidth; }
        virtual int GetLength() { itsLength; }
        virtual int GetWidth() { itsWidth; }
        void Draw();
    private:
        int itsWidth;
        int itsLength;
};

void Rectangle::Draw()
{
    for (int i = 0; i<itsLength; i++)
    {
        for (int j = 0; j<itsWidth; j++)
            cout << "x ";

        cout << "\n";
    }
    Shape::Draw();
}

class Square : public Rectangle
{
    public:
        Square(int len);
        Square(int len, int width);
        ~Square(){}
        long GetPerim() {return 4 * GetLength();}
};

Square::Square(int len):
    Rectangle(len,len)
{}

Square::Square(int len, int width):
    Rectangle(len,width)
{
    if (GetLength() != GetWidth())
        cout << "Error, not a square... a Rectangle??\n";
}

void startof()
{
    int choice;
    BOOL fQuit = FALSE;
    Shape * sp;

    while (1)
    {
        cout << "(1)Circle (2)Rectangle (3)Square (0)Quit: \n";
        cin >> choice;

        switch (choice)
        {
            case 1: sp = new Circle(5);
                break;
            case 2: sp = new Rectangle(4,6);
                break;
            case 3: sp = new Square (5);
                break;
            default: fQuit = TRUE;
                break;
        }
        if (fQuit)
            break;

        sp->Draw();
        cout << "\n";
    }
}


int main()
{
    startof();
}
Garf365
  • 3,619
  • 5
  • 29
  • 41
AlleyCat
  • 41
  • 6
  • @Garf365 - that's a helpful link for this question, but I would not call this a duplicate. This question has the OP asking for help with some specific code. – Smeeheey May 26 '16 at 11:59

1 Answers1

3

The problem here is that you have not defined the function Circle::Draw(). If you define it the code compiles.

As an aside, you should make the Shape destructor virtual (otherwise instances of derived classes may not be properly destroyed in some cases). The rule here is that if a class has any virtual members the destructor should also be virtual.

I know the compilation message you see is quite cryptic. I have seen scenarios where this "undefined v-table" compiler error is a side-effect of some other problem, as in this case. Just to let you know, a good way to make this error go away is to move one of the virtual function definitions of the affected class out of line (I did this with the Circle destructor above, having made the Shape destructor virtual first). This revealed the true problem with a better compiler error.

Smeeheey
  • 9,906
  • 23
  • 39
  • Also, I don't think this is @user5550660's intention, but if they wanted calls to `Circle::Draw()` to call `Shape::Draw()`, as it is pure virtual they would need to explicitly call `Shape::Draw()` from within the definition of `Circle::Draw()`. – Matt Dunn May 26 '16 at 11:52