Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prevent subclass outside of a header file

I have the following three class defined in a .h file:

class Base
{ // number of pure virtual functions };

class Derived1 : public Base
{ // number of pure virtual functions };

class Derived2 : public Base
{ // number of pure virtual functions };

I want users of this header file to only subclass Derived1 or Derived2. I want to prevent users from subclass'ing Base. I "could" have used the keyword "final" for class Base, but that would prevent me from subclassing in my header file. I need to have all the above classes in the header file as a user needs to provide definitions of methods in Base and DerivedX classes.

I am thinking of something like limiting the scope of inheritance to within a header file (similar to a static variable). Any suggestions or ideas would be greatly appreciated.

like image 834
Ahmed A Avatar asked Aug 22 '14 14:08

Ahmed A


1 Answers

You could make the Base constructor private and have those two classes friends, e.g.

#include <iostream>

class Base
{
private:
    Base() {}
    friend class Derived1;
    friend class Derived2;
};

class Derived1 : public Base
{
};

class Derived2 : public Base
{
};

int main() {

    Derived1 obj;
    Base obj2; // Error

    return 0;
}

http://ideone.com/NUWad0

Also notice: copy/move constructor of base class should probably also be private. I'm not adding the code to focus on the main proposal but you should think about it too.


Edit with regard to friend constructors.

First off: you cannot reference the members of an incomplete type before its definition is seen by the compiler (it works as a one-time pass and there might be some overload resolution involved). This means the following won't work:

class Derived1;
class Derived2;

class Base
{
private:
    Base() {}
    friend Derived1::Derived1(); // Error - incomplete type 'Derived1' in nested name specifier
};

class Derived1 : public Base
{
    public:
    Derived1() {};
};

...    

and you cannot forward declare a base class (you wouldn't know how much space to allocate for a derived object):

class Base;

class Derived1 : public Base // Error: base class has incomplete type
{
    public:
    Derived1() {};
};

class Base
{
private:
    Base() {}
    friend Derived1::Derived1();
};

...

therefore in your specific case you'd better off with a friend class access unless you want to modify something in your design.

like image 164
Marco A. Avatar answered Nov 14 '22 15:11

Marco A.