24

Scott said on Effective C++, 3rd Edition, pg. 43 that to make an abstract class, we just need to give it a pure virtual destructor:

class AWOV {                  // AWOV = "Abstract w/o Virtuals"
public:
  virtual ~AWOV() = 0;        // declare pure virtual destructor
};

Then, he went on said that there is one twist: we must provide a definition for the pure virtual destructor:

AWOV::~AWOW() {}              // definition of pure virtual dtor

My question is, by specifiying = 0, for pure virtual functions, we are saying that the function cannot have any definition for the class where this pure virtual function is declared.

Why is it OK to provide a definition (even it is empty) for the pure virtual destructor here?

Coding Mash
  • 3,338
  • 5
  • 24
  • 45
Qiang Xu
  • 4,353
  • 8
  • 36
  • 45

6 Answers6

16

"we are saying that the function cannot have any definition for the class where this pure virtual function is declared."

That's not what pure virtual means. Pure virtual only means that the containing class cannot be instantiated (is abstract), so it has to be subclassed, and subclasses must override the method. E.g.,

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

A::~A() {}

struct B : A {};

int main()
{
    A a;  // error
    B b;  // ok
}

Here, the B destructor is implicitly defined. If it was another method that is pure virtual, you'd have to explicitly override it:

struct A {
    virtual void foo() = 0;
};

void A::foo() {}

struct B : A {};

int main()
{
    B b;  // error
}

Providing a definition for a pure virtual method is desirable when the base class must be abstract but still provide some default behavior.

In the specific case of a destructor, it has to be provided because it will be called automatically when subclass instances are destroyed. A program that tries to instantiate a subclass of a class with a pure virtual destructor without a definition will not pass the linker.

Community
  • 1
  • 1
Fred Foo
  • 355,277
  • 75
  • 744
  • 836
  • I got this impression from Andrew Koenig's "Accelerated C++", specifically, Section 15.1.2: "Instead of forcing us to concoct an arbitrary definition for these operations, the C++ language lets us say that there will be no definition for a given virtual function. " – Qiang Xu Oct 16 '12 at 16:43
  • 1
    @QiangXu: in fact, that is the main use case for pure virtuals, but it's not how they work from a language/compiler point of view. Also, you just can't omit the definition for the destructor, because it must be called in a well-behaved program. – Fred Foo Oct 16 '12 at 21:01
7

Making it pure forces derived (non-abstract) classes to implement their own.

Providing an implementation allows derived classes to invoke base class behavior (which destructors do by default).

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
BCS
  • 75,627
  • 68
  • 187
  • 294
5

There are 2 cases.

Pure virtual destructor

This case is specifically treated by the standard.

12.4 Destructors [class.dtor]

9) A destructor can be declared virtual (10.3) or pure virtual (10.4); if any objects of that class or any derived class are created in the program, the destructor shall be defined. If a class has a base class with a virtual destructor, its destructor (whether user- or implicitly-declared) is virtual.

The case of the destructor is different because all destructors are called in an inheritance hierearchy (assuming correct deletion) in reverse order of construction, even if not explicitly. So the base class destructor is called when the object gets deleted - that's why it needs an implementation.

Pure virtual method

These differ from destructors in that they're not required to be implemented, nor do they need an implementation. The difference for the missing requirement is that when a Derived::foo() gets called, it doesn't automatically call Base::foo() (not that it could, since it can or can not be implemented).

Why you would want to implement a pure virtual method depends on the case. I look at the pure specifier as a hint to the programmer, as opposed to related to the logic. It tells you - the programmer - that you should implement that method. It doesn't really matter if the base class has an implementation or not.

by specifiying = 0, for pure virtual functions, we are saying that the function cannot have any definition for the class where this pure virtual function is declared.

Not really. You're saying derived non-abstract classes have to override that function. This doesn't prevent you from implementing it yourself.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
  • 1
    OK, got it. A pure virtual function is not required to be implemented, but the implementation is not forbidden, either. And for a pure virtual destructor, an implementation is even required. Am I right? – Qiang Xu Oct 16 '12 at 16:55
2

This is not necessary for all pure virtual functions. Not at all.

This way, the derived classes will still be forced to override the implementation, but there will be a default implementation in the base class, in case you need to call it. And that's the case here - because you're dealing with a destructor: when a derived object is being destroyed, its destructor is called and its base classes destructors are called as well. That's why you need an implementation for A::~A.

Kiril Kirov
  • 37,467
  • 22
  • 115
  • 187
0

By making a function pure virtual we force the user of the class to replace the function with another in the derived class.

The base class function can still be called with BaseClass::myfunction(...)

Now the base class might want to provide some core functionality that the derived class may use if it chooses to do so.

doron
  • 27,972
  • 12
  • 65
  • 103
-1

Correct answer: Suppose there are 2 pure virtual functions in class. Now assume that both have implementation. The reason for providing implementation for PVF is that the Base class method can act as default behavior if Base class is derived by child by implementing these PVF methods(to make class as concrete)

Nitin G
  • 1
  • 1
  • 2
    "if Base class is derived by child by implementing at least one of the method (to make class as concrete)" - no, the derived class must implement *both* virtual functions. – Eugene Dec 08 '21 at 14:33