19

Say I've got a class called "Base", and a class called "Derived" which is a subclass of Base and accesses protected methods and members of Base.

What I want to do now is make it so that no other classes can subclass Derived. In Java I can accomplish that by declaring the Derived class "final". Is there some C++ trick that can give me the same effect?

(Ideally I'd like to make it so that no class other than Derived can subclass Base as well. I can't just put all the code into the same class or use the friend keyword, since Base and Derived are both templated, with Base having fewer template arguments than Derived does....)

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
Jeremy Friesner
  • 70,199
  • 15
  • 131
  • 234
  • I would include some source code - since it involves templates. – sylvanaar Aug 07 '09 at 21:44
  • If a class does not have a virtual destructor you should probably not be dertiving from it (that just good programming). C++ recognizes that sometimes you need the ability to strech the bounds and lets you inherit from it anyway. So you problem is not a language one put an educational one. – Martin York Aug 08 '09 at 01:00
  • Vote: remove the keyword/final tag but add **derived-class** tag instead – fmuecke Dec 08 '09 at 11:03
  • The [C++ FAQ Lite](http://www.parashift.com/c++-faq-lite/) has [a topic](http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.11) for this. – Sean Bright Aug 07 '09 at 21:34
  • So it does... however, none of those techniques seem entirely satisfactory: #1 means that users of Derived have to use a non-standard idiom to use the class; they can't just declare it directly like you normally would; instead you have to call a Named Constructor. #2 isn't won't generate any compile time errors if subclassing is attempted (which is the effect I am looking for) #3 Will add a vtable to my objects, which I'd prefer to avoid. – Jeremy Friesner Aug 07 '09 at 21:47
  • In which case the answer to your question (whether there is a technique) is almost certainly "No". – David Thornley Aug 07 '09 at 22:04
  • @Jeremy - Right, as David suggested, you may be out of luck. – Sean Bright Aug 07 '09 at 22:24
  • Not sure why this has been voted as high (?) Isn't this answer the equivalent of RTFM? – Alan Aug 08 '09 at 06:59
  • @Alan: It's more like "read this exact page of the manual". The second link (a topic), goes directly to an answer. 'RTFM' implies that an answer exists in the documentation, but doesn't specify where. – Conspicuous Compiler Aug 08 '09 at 11:03
  • -1 A link is not an answer. Quote pertinent sections of the cited text if you must, but actually write an answer. – Lightness Races in Orbit Dec 26 '11 at 13:17

5 Answers5

15

As of C++11, you can add the final keyword (technically a special identifier since it is not actually a keyword) to your class, eg

class Derived final
{
...

You can read more about the final keyword at http://en.wikipedia.org/wiki/C++11#Explicit_overrides_and_final

Peter N Lewis
  • 17,664
  • 2
  • 43
  • 56
  • +1 Interesting to have this solution with C++11. An additional link to a more detailed description, would make this answer even more helpful. – Wolf Feb 27 '14 at 08:23
9

You can have a private constructor for 'Derived' and a public static Create function for instantiation

Indy9000
  • 8,651
  • 2
  • 32
  • 37
6

The easiest way to prohibiting subclassing is by making the constructor private:

class Foo
{
private:
    Foo() {}

public:
    static Foo* CreateFoo() { return new Foo; }
};

Edit: Thanks to Indeera for pointing out that this needs a static Factory method

Alan
  • 13,510
  • 9
  • 44
  • 50
3

There is no simple and clean way to do it.

What the standard library does is simply make the destructor nonvirtual. That doesn't prevent subclassing, but it is a strong signal to users that it is not designed for inheritance, and it means you have to be very careful when using the derived class.

Ultimately though, do you need to absolutely make subclassing impossible? Isn't it good enough to indicate that "deriving from this class is a bad idea"?

People can always break your code if they really want to. The best you can do is make them aware of what they should and shouldn't do, and hope they won't actively try to break your code.

Protect your code against Murphy, not Machiavelli. ;)

jalf
  • 243,077
  • 51
  • 345
  • 550
1

Since you are using templates I was thinking that the last part of your question about preventing any class other than Derived to subclass from Base could be done using appropriate partial specialisations.

The following code snippet is what I came up with but the complexity required only goes to reinforce the answer by jalf. Is it worth it? If anything this has helped me understand partial specialisation more than working out a technique I would ever use in practice.

I use COMMON to indicate a shared template parameter between Base and Derived and EXTRA to denote the extra parameters that you say Derived has. The actual numbers of these could be anything I just happened to have picked one and two for these respectively.

// Forward declaration of class Derived
template< class COMMON
        , class EXTRA1
        , class EXTRA2 >
class Derived;


// Definition of general class template Base
template< class SUBCLASS
        , class COMMON >
class Base
{
private:
    Base() {}
};


// Definition of partial specialisation of template class Base to open up
// access to the constructor through friend declaration.
template< class COMMON
        , class EXTRA1
        , class EXTRA2 >
class Base< Derived< COMMON, EXTRA1, EXTRA2 >
          , COMMON >
{
private:
    Base() {}

    friend class Derived< COMMON, EXTRA1, EXTRA2 >;
};


// Definition of class Derived
template < class COMMON
         , class EXTRA1
         , class EXTRA2 >
class Derived
    : public Base< Derived< COMMON, EXTRA1, EXTRA2 >
                 , COMMON >
{
public:
    static Derived* create() { return new Derived; }

private:
    Derived() : Base< Derived< COMMON, EXTRA1, EXTRA2 >
                    , COMMON >()
    {
    }
};


// Definition of class HonestDerived.
// It supplies itself as the SUBCLASS parameter to Base.
template < class COMMON
         , class EXTRA1
         , class EXTRA2 >
class HonestDerived
    : public Base< HonestDerived< COMMON, EXTRA1, EXTRA2 >
                 , COMMON >
{
public:
    HonestDerived() : Base< HonestDerived< COMMON, EXTRA1, EXTRA2 >
                          , COMMON >()
    {
    }
};


// Definition of class DishonestDerived
// It supplies Derived rather than itself as the SUBCLASS parameter to Base.
template < class COMMON
         , class EXTRA1
         , class EXTRA2 >
class DishonestDerived
    : public Base< Derived< COMMON, EXTRA1, EXTRA2 >
                 , COMMON >
{
public:
    DishonestDerived() : Base< Derived< COMMON, EXTRA1, EXTRA2 >
                             , COMMON >()
    {
    }
};


template< class COMMON, class EXTRA1, class EXTRA2 >
class DerivedFromDerived
    : public Derived< COMMON, EXTRA1, EXTRA2 >
{
public:
    DerivedFromDerived() : Derived< COMMON, EXTRA1, EXTRA2 >()
    {
    }
};

// Test partial specialisation gives Derived access to the Base constructor
Derived< int, float, double >* derived
    = Derived< int, float, double >::create();

// Test that there is no access to the Base constructor for an honest subclass
// i.e. this gives a compiler error
HonestDerived< int, float, double > honestDerived;

// Test that there is no access to the Base constructor for a dishonest subclass
// i.e. this gives a compiler error
DishonestDerived< int, float, double > dishonestDerived;

// Test that there is no access to the Derived constructor
// i.e. this gives a compiler error
DerivedFromDerived< int, float, double > derivedFromDerived;

This code was tested with gcc 4.3.2.

Note that an alternative to the friend declaration would be to make the constructor protected in the partial specialisation of Base but then that would allow classes like DishonestDerived to work.

Troubadour
  • 13,334
  • 2
  • 38
  • 57