Karl Nicoll Karl Nicoll - 2 months ago 6
C++ Question

Can I force a class to be inherited?

Consider the following class:

//! Counter class base. Must be inherited.
class base_seeded_counter
{
public:
//! Destructor
virtual ~base_seeded_counter() { };

//! Get the next value.
int get_next();

protected:
//! Override the counter next value.
void set_next(const int next);

private:
int m_next_value; // Next value.
}

// ------------------------------------------------------

inline int base_seeded_counter::get_next()
{
return m_next_value++;
}

// ------------------------------------------------------

inline void base_seeded_counter::set_next(const int next)
{
m_next_value = next;
}


The purpose of this class is to implement a base counter object with the intention that it must be inherited. It does not have any virtual methods other than the destructor and, more importantly, does not initialize the
m_next_value
member
. This is the job of the derived class. For example:

class file_seeded_counter : public base_seeded_counter
{
public:
file_seeded_counter(const std::string &file_name);

void reseed();

private:
std::string m_file_name;
}

inline int file_seeded_counter::file_seeded_counter(const std::string &file_name) :
m_file_name(file_name)
{
reseed();
}

inline void file_seeded_counter::reseed()
{
int seed_from_file;

// open file here and get seed value...

set_next(seed_from_file);
}


This class, deriving from base_seeded_counter reads the initial counter value from a file, and offers the ability to re-read the seed from the file via the
reseed()
method. There may be other classes that offer similar functionality to seed from databases, network sources, or a PRNG, for example.

My question is this: Given that I have no pure virtual methods, does C++ offer a mechanism to prevent someone from creating an instance of
base_seeded_counter
?

Answer

Given that you already have a virtual destructor, the obvious way would be to declare it pure virtual. It's entirely legitimate to have a pure virtual destructor that's also defined in the base class:

class base_seeded_counter {
public:
    virtual ~base_seeded_counter() = 0;
    int get_next();
protected:
    void set_next(const int next);
private:
    int m_next_value;
}

inline virtual base_seeded_counter::~base_seeded_counter() {}

Defining the destructor this way doesn't change the fact that it's a pure virtual, so this class can't be instantiated.


As an aside, the comments you currently have in the code are 100% useless visual noise. A comment of get next on a function named get_next adds nothing useful at all.