Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Protected constructor to make base class not instantiable

Is it good practice to make a base class constructor protected if I want to avoid instances of it? I know that I could as well have a pure virtual dummy method, but that seems odd...

Please consider the following code:

#include <iostream>

using std::cout;
using std::endl;

class A 
{
protected:
    A(){};
public:
    virtual void foo(){cout << "A\n";};
};

class B : public A
{
public:
    void foo(){cout << "B\n";}
};

int main()
{
    B b;
    b.foo();
    A *pa = new B;
    pa->foo();

    // this does (and should) not compile:
    //A a;
    //a.foo();
    return 0;
}

Is there a disadvantage or side-effect, that I don't see?

like image 457
steffen Avatar asked Sep 30 '13 09:09

steffen


People also ask

How do you make a class not Instantiable?

We can make a class non-instantiable by making the constructor of the class private . By making the constructor private, the following happens: The constructor becomes inaccessible outside the class, so class objects can't be created.

How do you make a class not Instantiable in C#?

Marking a class as abstract or static (they are mutually exclusive) are the only two ways. Marking all constructors as private does not make the class uninstantiateable since the class can still construct itself, and others might be able to do it via reflection. Is a sealed class, non-instantiable?

What happens when a constructor is defined as protected?

A protected constructor means that only derived members can construct instances of the class (and derived instances) using that constructor. This sounds a bit chicken-and-egg, but is sometimes useful when implementing class factories. Technically, this applies only if ALL ctors are protected.

Can we use protected in constructor?

Access specifiers/modifiers allowed with constructorsModifiers public, protected and, private are allowed with constructors.


4 Answers

It is common practice to make base class constructors protected. When you have a pure-virtual function in your base class, this is not required, as you wouldn't be able to instantiate it.

However, defining a non-pure virtual function in a base class is not considered good practice, but heavily depends on your use case and does not harm.

There isn't any disadvantage or side-effect. With a protected constructor you just tell other developers that your class is only intended to be used as a base.

like image 141
villekulla Avatar answered Nov 15 '22 07:11

villekulla


What you want to achieve is normally done via the destructor, instead of the constructors, just beacause you can steer the behavior you need with that one function instead of having to deal with it with every new constructor you write. It's a common coding style/guideline, to

  • make the destructor public, if you want to allow instances of the class. Often those classes are not meant to be inherited from.
  • make the destructor pure virtual and public, if you want to use and delete the class in a polymorphic context but don't want to allow instances of the class. In other words, for base classes that are deleted polymorphcally.
  • make the destructor nonvirtual and protected, if you don't want to allow instances of the class and don't want to delete its derivates polymorphically. Normally, you then don't want to use them polymorphically at all, i.e. they have no virtual functions.

Which of the latter two you chose is a design decision and cannot be answered from your question.

like image 40
Arne Mertz Avatar answered Nov 15 '22 07:11

Arne Mertz


It does what you're asking.

However I'm not sure what you are gaining with it. Someone could just write

struct B : A {
   // Just to workaround limitation imposed by A's author
};

Normally it's not that one adds nonsense pure-virtual functions to the base class... it's that there are pure virtual functions for which no meaningful implementation can be provided at the base level and that's why they end up being pure virtual.

Not being able to instantiate that class comes as a nice extra property.

like image 31
6502 Avatar answered Nov 15 '22 05:11

6502


Make the destructor pure virtual. Every class has a destructor, and a base class should usually have a virtual destructor, so you are not adding a useless dummy function.

Take note that a pure virtual destructor must have a function body.

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

If you don't wish to put the destructor body in the header file, put it in the source file and remove inline keyword.

like image 44
Neil Kirk Avatar answered Nov 15 '22 07:11

Neil Kirk