Search code examples
c++destructorvirtual-functionsvirtual-destructor

virtual destrutors vs normal methods in C++


Consider the following three programs in C++:

program 1

struct base{
  virtual ~base() =0;
};

struct derived: public base{
  ~derived();
};

derived::~derived(){}

int main(){}

program 2

struct base{
  virtual ~base() =0;
};

struct derived: public base{
  ~derived(){}
};

int main(){}

program 3

struct base{
  virtual void func() =0;
};

struct derived: public base{
  void func();
};

void derived::func(){}

int main(){}

The programs #2 and #3 compile and run fine however the first gives the following error:

Undefined symbols for architecture x86_64:
  "base::~base()", referenced from:
    derived::~derived() in main-d923b9.o
ls: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

I'd like to know why I am unable to define virtual destructors outside of the class definition however I am able to do it inside the class definition. Additionally I can define methods outside the class, just not destructors.


Solution

  • This is wrong

    struct base{
      virtual ~base() =0;
    };
    

    because base::~base is not defined. Even though it has been declared as a pure virtual, it needs to be defined (outside of the class, there is no syntaxic way to declare a function as pure virtual and define it inline) so derived can inherit from it:

    struct base
    {
        virtual ~base() = 0;
    };
    
    base::~base() {}
    

    I'd like to know why I am unable to define virtual destructors outside of the class definition

    Well, you can: I just did.


    Then, why do you need to implement a function (~base) which has been declared pure virtual?

    Since derived inherit from base, when an object of type derived is destructed, it necessarily calls base's destructor. This is how inheritance work. In a sense, derived::~derived needs to link with base::~base. Even though base::~base is a pure virtual (meaning a class inheriting from base is not a complete type unless it defines a destructor) it needs to be defined so ~derived finds it and the linker become happy.