34

File A.h

#ifndef A_H_
#define A_H_

class A {
public:
    virtual ~A();
    virtual void doWork();
};

#endif

File Child.h

#ifndef CHILD_H_
#define CHILD_H_

#include "A.h"

class Child: public A {
private:
    int x,y;
public:
    Child();
    ~Child();
    void doWork();
};
#endif

And Child.cpp

#include "Child.h"

Child::Child(){
    x = 5;
}

Child::~Child(){...}

void Child::doWork(){...};

The compiler says that there is a undefined reference to vtable for A. I have tried lots of different things and yet none have worked.

My objective is for class A to be an Interface, and to seperate implementation code from headers.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
rjmarques
  • 369
  • 1
  • 3
  • 10

3 Answers3

77

Why the error & how to resolve it?

You need to provide definitions for all virtual functions in class A. Only pure virtual functions are allowed to have no definitions.

i.e: In class A both the methods:

virtual ~A();
virtual void doWork();

should be defined(should have a body)

e.g.:

A.cpp

void A::doWork()
{
}
A::~A()
{
}

Caveat:
If you want your class A to act as an interface(a.k.a Abstract class in C++) then you should make the method pure virtual.

virtual void doWork() = 0;

Good Read:

What does it mean that the "virtual table" is an unresolved external?
When building C++, the linker says my constructors, destructors or virtual tables are undefined.

Community
  • 1
  • 1
Alok Save
  • 202,538
  • 53
  • 430
  • 533
  • @user1227351: Updated the answer to explain better.Read the links for further explanation. – Alok Save Feb 23 '12 at 03:20
  • Having virtual ~A(); virtual void doWork() = 0; still gives vtable error =/. But without the destructor it works fine. However without it, if i do something like: A *a = new Child(); delete a; obviously it will not call Child::~Child(). Is there a workaround? – rjmarques Feb 23 '12 at 03:34
  • The solution is to place A::~A(){} in Child.cpp – rjmarques Feb 23 '12 at 03:57
  • With C++11, you can use "default" keyword to let the compiler do the job. ex: virtual doSomething() = default; – Onur May 15 '15 at 07:44
6

My objective is for A to be an Interface, and to seperate implementation code from headers.

In that case, make the member function as pure virtual in class A.

class A {
  // ...
  virtual void doWork() = 0;
};
Mahesh
  • 34,573
  • 20
  • 89
  • 115
  • That removes the error if I also remove the destructor. In that case if i do: A a = new Child(); delete a; what destructor would it call? – rjmarques Feb 23 '12 at 03:17
  • Destruction is always in reverse order of construction. In this case, class `A` destructor must be virtual which enforces `Child` destructor called first followed by `A` destructor. If the `A` class destructor is not virtual then the behavior is undefined. – Mahesh Feb 23 '12 at 03:20
  • It will call the child's destructor as you have made the parent class destructor virtual. After that, the parent class's destructor. – Izza Feb 23 '12 at 03:22
  • Having both the destructor and the pure virtual doWork(), in A, leads to a vtable error. How can i define a virtual destructor so that: A *a = new Child(); delete a; leads to a call to Child::~Child()? – rjmarques Feb 23 '12 at 03:43
  • The solution is to place A::~A(){} in Child.cpp – rjmarques Feb 23 '12 at 03:58
2

Make sure to delete any "*.gch" files if none of the other responses help you.