2

I have an abstract base class, which serves the purpose of allowing an array of pointers to a base class to be created. (Useful for 'many things'...)

My abstract base class contains no member functions. Therefore there are no pure virtual methods, and therefore I guess it is not technically abstract.

However, I do not want to be able to create an instance of this class.

Is it possible to create a memberless abstract base class? If not, is there another resolution to preventing an instance of my "abstract base" from being created? Will making the constructor protected suffice?

It has been pointed out to me that actually, an abstract base class would not be required if the purpose of that class was to allow a vector or array of pointers to the base class to be created - one could simply not have a base class and use as the base class the class at the top of the inheritance hierarchy. Alternatively, one could copy and paste that top class and exchange the implemented methods for pure virtual functions with no implementation, however this seems logically inconstant with the idea of abstract base pointers, and would lead to more difficult to maintain code.

FreelanceConsultant
  • 13,167
  • 27
  • 115
  • 225
  • does it contain member variables? – David Haim Aug 03 '15 at 15:26
  • 6
    What would the use of such a thing be? It's a base class, but has nothing in it? – Barry Aug 03 '15 at 15:27
  • 4
    @Barry Did you not read the question? `(Useful for 'many things'...)` ;) – fredoverflow Aug 03 '15 at 15:32
  • @DavidHaim It does not – FreelanceConsultant Aug 03 '15 at 15:32
  • Since it carries no virtual methods, I suppose you need it to carry at least one variable, one that will tell your code later what its type *really* is so you can recast it before using it (although that's not part of your question). – Havenard Aug 03 '15 at 15:33
  • This is a duplicate of [Inheritance from empty base class in C++](https://stackoverflow.com/questions/13989454/inheritance-from-empty-base-class-in-c). Except that the "best answer" there contains a (fixable) error. If the destructor is defined, it has to be done outside of the class definition. – ex-bart Aug 03 '15 at 15:36
  • @ex-bart: That's not true. It can be inlined like any other member function. – Christian Hackl Aug 03 '15 at 15:45
  • 1
    @ChristianHackl C++11 §10.4[class.abstract]/2: [ *Note:* A function declaration cannot provide both a pure-specifier and a definition *— end note* ] – ex-bart Aug 03 '15 at 15:55
  • @ChristianHackl But I suppose there are compilers that allow it. Not g++-4.8, though. – ex-bart Aug 03 '15 at 15:56
  • @ex-bart: You are right, I have been fooled by VC, which at least in its 2013 version does accept it. – Christian Hackl Aug 03 '15 at 15:59

3 Answers3

12

Provide a pure virtual destructor:

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

inline Base::~Base() {}

You need to provide an implementation, which you could right in the header by making it inline.


An abstract class is a class with some pure virtual function:

[...] A class is abstract if it has at least one pure virtual function. [...]

[N4431 §10.4/2]

Since you want an array of pointers to instances of (classes derived from) your abstract class, I assume you also want to be able to eventually delete and thus destruct one or more of those instances via these pointers:

Base * instance = // ... whatever ...
delete instance;

To call the correct destructor (of the derived class) in that case, the destructor has to be virtual.

So since it's virtual either way, and you don't want some pure virtual member function, it's best to make the destructor pure virtual.

To make a virtual function pure, you append the pure-specifier to its declaration:

struct Foo {
 virtual void bar(void) /* the */ = 0; // pure-specifier
};

Now, regarding the definition, you wonder why we need to provide one, since ...

[...] A pure virtual function need be defined only if called with, or as if with (12.4), the qualified-id syntax (5.1). [...]

[N4431 §10.4/2]

This is because when destructing a derived class, after the derived classes destructor has been called, the destructors of the bases classes will also be called:

struct Derived : public Base {
 ~Derived() {
  // contents
  // Base::~Base() will be called
 }
};

After executing the body of the destructor [...] a destructor for class X calls [...] the destructors for X’s direct base classes and, if X is the type of the most derived class (12.6.2), its destructor calls the destructors for X’s virtual base classes. All destructors are called as if they were referenced with a qualified name [...]

[N4431 §12.4/8]

So a definition of the pure virtual destructor if the Base class is needed. However ...

[...] A function declaration cannot provide both a pure-specifier and a definition [...]

[N4431 §10.4/2]

... so it has to be defined outside of the class definition. This could be done in a separate source file, or thanks to ...

An inline function shall be defined in every translation unit in which it is odr-used and shall have exactly the same definition in every case [...]

[N4431 §7.1.2/4]

... as a inline function in the header.


The standard is even explicit about the requirement of a definition in this case:

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. [...]

[N4431 §12.4/9]

Daniel Jour
  • 15,896
  • 2
  • 36
  • 63
1

Is it possible to create a memberless abstract base class?

The simplest way is to make the destructor pure virtual.

class AbstractBase
{
   public:
      virtual ~AbstractBase() = 0;
};
R Sahu
  • 204,454
  • 14
  • 159
  • 270
1

If you are going to delete instances of that class polymorphically, then you must have a virtual destructor anyway. It's not just to prevent instantiations of the base class, it's required to avoid undefined behaviour. Just make it pure virtual. And give it an empty implementation (yes, this works in C++).

If, however, you are not using polymorphism at all, then you should avoid adding a virtual destructor and instead just make the constructor protected. Remember that a base class does not necessarily have to establish a polymorphic class hierarchy (see examples in the C++ library like std::input_iterator_tag).

Christian Hackl
  • 27,051
  • 3
  • 32
  • 62