9

I want to make an empty base class called "Node", and then have other classes derived from this such as "DecisionNode" and "Leaf." It makes sense to do this so I can take advantage of polymorphism to pass these different kinds of nodes to methods without knowing at compile time what will be passed to the method, but each of the derived classes do not share any state or methods.

I thought the best way to implement this, without creating an additional pure virtual method in the base class, which would add clutter, would be to make the constructor pure virtual. In the header file for the class, "Node.h" I therefore wrote:

class Node {
 private:
  virtual Node();
};

and in "Node.cpp" I wrote:

#include "Node.h"
virtual Node::Node() = 0;

This implementation prevents Node from ever being instantiated by another class, since the only constructor is private and uses the pure virtual specifier to indicate that the class is abstract. However, this gives the compiler errors:

Node.h:6:21: error: return type specification for constructor invalid
Node.h:6:21: error: constructors cannot be declared virtual [-fpermissive]

My question is: is there a neat way to make an empty abstract base class?

Froskoy
  • 2,967
  • 5
  • 20
  • 21
  • 4
    Use a virtual destructor, which you should do anyway. – R. Martinho Fernandes Dec 21 '12 at 11:38
  • 3
    If none of the nodes share methods, how do you actually plan to *use the node*? – Waleed Khan Dec 21 '12 at 11:39
  • 1
    http://stackoverflow.com/questions/9588788/good-practice-to-design-a-abcabstract-base-class-in-c has an ABC implementation in the question. – Waleed Khan Dec 21 '12 at 11:41
  • 1
    @WaleedKhan: In method signatures, so I can pass in any of the classes derived from Node. – Froskoy Dec 21 '12 at 11:46
  • You are ignoring the constructors, destructor, copy, and assignment that the compiler builds for you. – Ed Heal Dec 21 '12 at 12:00
  • 3
    @Froskoy, if they don't share code and don't have any virtual methods, then passing `Node*` is no better than passing `void*` - in both cases you will have to cast to specific classes back and forth. – hate-engine Dec 21 '12 at 12:26
  • @hate-engine: Thanks - I'll reconsider my design. I'm still very much learning OOP. – Froskoy Dec 21 '12 at 13:50
  • 2
    @hate-engine: Respectfully disagreeing; you cannot dynamic cast (and thus check the actual type) from a `void*`. Passing `Node*` is better than passing `void*`. It ensures that passed object inherit from Node and allows safe `dynamic_cast` (or `static_cast` by the way) to any inherited type. – Yves Lhuillier Jun 17 '19 at 09:57

6 Answers6

10

you can't make the constructor virtual. If no other pure virtual functions are needed you can make the destructor pure virtual:

class Node
{
public:
    virtual ~Node() = 0;
};

Node::~Node()
{
  // Compulsory virtual destructor definition,
  // even if it's empty
}
Antonio
  • 19,451
  • 13
  • 99
  • 197
Marius
  • 833
  • 5
  • 11
8

C++ doesn't support virtual constructor.

§ 12.1 Constructors

12.1.4 A constructor shall not be virtual (10.3) or static (9.4).

Below code won't compile:

virtual Node::Node() = 0;

My question is: is there a neat way to make an empty abstract base class?

Yes, make destructor a pure virtual function, also provides destructor function definition

class Node 
{
public:
    virtual ~Node()=0
    {
    }
};
billz
  • 44,644
  • 9
  • 83
  • 100
  • 2
    This won't work, at least not on g++. You have to provide the definition of the constructor outside of the class definition. – ex-bart Aug 03 '15 at 15:43
4

Create a virtual destructor and also provide an "empty" implementation.

class Node {
    virtual ~Node() = 0;
}

Node::~Node() {}  // You will get linker error if you do not have this

The other alternative is to make the constructor protected, as others have commented. See also this question for some differences between the two. protected constructor versus pure virtual destructor

Edit Make sure you document why you are using the pure virtual destructor. The code by itself is cryptic in this regard and does not make it clear to someone who doesn't know about this "trick".

Edit 2 Your constructor should be protected, not private. You won't be able to inherit if your constructor is private.

Community
  • 1
  • 1
Masked Man
  • 1
  • 7
  • 40
  • 80
  • Thanks! I don't understand why there is a linker error without the implementation? – Froskoy Dec 21 '12 at 11:48
  • That's because the derived class destructor needs to call the base class destructor. When you declare the base class destructor yourself, the compiler does not generate one for you. – Masked Man Dec 21 '12 at 11:55
  • By the way, go through the accepted answer in the link I provided for comparison between the two approaches. (As well, upvote the answers and the question if they helped you. ;) ) – Masked Man Dec 21 '12 at 11:59
0

In C++, constructors cannot be virtual. To prevent anyone from instantiating your base class, give it a protected constructor, like this:

class Node {
protected:
  Node() {}
};

It will not be abstract, but only derived classes will be able to create its instances.

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
0

Simply:

class Node 
{
protected:
    Node()
    {
    }
public:
    virtual ~Node()
    {
    }
}
Spook
  • 25,318
  • 18
  • 90
  • 167
0

What you are trying to do is

class Node {
 private:
  virtual Node();
};
and in "Node.cpp" I wrote:

#include "Node.h"
// This is the error as your class name and function name i.e. same so compiler assumes 
// that this as a constructor and as per the c++ standard a constructor can not have 
// return type as well as can not be virtual
virtual Node::Node() = 0;

So you make a virtual distructor as ** virtual ~Node() = 0;**

Astro - Amit
  • 767
  • 3
  • 15
  • 36