16

Consider:

// in header.h
class A {
public:
    virtual ~A() = 0;
};


class B : public A {
public:
    ~B() override {}
}

The linker reports that it cannot resolve:

external symbol "public: virtual __thiscall A::~A(void)" referenced in function "public: virtual __thiscall B::~B(void)"

I find that I have to write the definition of A::~A().

I used to think that a pure virtual class defines interface (function declaration), and they don't have to contain a function definition. Should I write definitions for all virtual functions in a pure virtual base class? Or should I just need to write the destructor function?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Marvis Lu
  • 441
  • 3
  • 10

4 Answers4

16

It's because unlike regular virtual functions, a destructor isn't just overridden. When you call a regular virtual function on a base class, you end up only calling the function which has overridden that function.

In the case of the destructor, however, the destructors of the base classes must also be called. But since you don't provide an implementation of ~A(), your code fails to link.

But you can define the function even though it's pure virtual: like here.

Fatih BAKIR
  • 4,569
  • 1
  • 21
  • 27
11

Should a C++ pure virtual class need a definition?

The first mistake is that you invent terms on behalf of yourself. There is no such thing as "a pure virtual class". There is only "virtual function" and "pure virtual function". Understanding that there is no such thing "pure virtual class" is a key of understanding why this question does not hold.

I used to think that pure virtual class defines an interface (function declaration)

I think C++ is not your first language, but a second language after Java/C#, and you think in Java/C# ideas that has nothing to do with C++.

C++ has interfaces - it's just the declaration of the class:

struct A{

    void doNothing();

};

//A.cpp:
void A::doNothing(){

}

This is the interface of struct A. Does it have anything to do with inheritance, virtual functions or polymorphism? No. It's just the declaration of the class, what method and properties exist within it.

Every class needs a valid destructor to allow the program to clean the object resources - memory, etc. It has nothing to do with polymorphism. In your example, A needs to be destructed somehow. It doesn't matter that B inherits from it. It must tell the program how to deal with it when it gets out of scope.

As mentioned in the comments, if you only want a virtual destructor (so not UB will be manifested in the case of A* a = new B()), just declare the destructor as default:

virtual ~A() = default;
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
David Haim
  • 25,446
  • 3
  • 44
  • 78
  • 2
    Java's *interface* equivalent in C++ is a class with only pure virtual functions. And your *struct A {…};* above is a definition of the struct. Declaration would be just *struct A;* – hyde Apr 20 '17 at 17:02
  • 1
    I kinda think that people coming to C++ from languages like Java or C# should be taught early on that in C++, an abstract class is one with one or more pure virtual functions, a class interface is just the part of the class' definition that's visible to outside entities (i.e. the `public` part), and that Java `interface`s are just a gimped form of multiple inheritance that's harder to screw up. – Justin Time - Reinstate Monica Apr 20 '17 at 17:24
  • 1
    @JustinTime Though with Java 8 default methods, `interface` multiple inheritance is now easier to screw up. – JAB Apr 20 '17 at 17:33
4

In supplement to my predecessors you can read about it here.

The definition of a pure virtual function may be provided (and must be provided if the pure virtual is the destructor): the member functions of the derived class are free to call the abstract base's pure virtual function using qualified function id. This definition must be provided outside of the class body (the syntax of a function declaration doesn't allow both the pure specifier = 0 and a function body)

Logman
  • 4,031
  • 1
  • 23
  • 35
2

Well to make a class abstract you need to make at least one virtual function pure. If you do not have any other then destructor could be a good candidate. But on another side destructir is a special case - you must define it even if it is pure.

Note: you can also define regular pure virtual function for example to intercept error condition (something like pure function is called from ctor or dtor), but unlike destructor it is fine not to provide such definition and compiler would generate error handler there, which will report that pure virtual function called.

Slava
  • 43,454
  • 1
  • 47
  • 90