Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ object without subclasses?

Tags:

c++

I was wondering if there is a way to declare an object in c++ to prevent it from being subclassed. Is there an equivalent to declaring a final object in Java?

like image 734
marchinram Avatar asked Oct 06 '10 21:10

marchinram


2 Answers

From C++ FAQ, section on inheritance

This is known as making the class "final" or "a leaf." There are three ways to do it: an easy technical approach, an even easier non-technical approach, and a slightly trickier technical approach.

The (easy) technical approach is to make the class's constructors private and to use the Named Constructor Idiom to create the objects. No one can create objects of a derived class since the base class's constructor will be inaccessible. The "named constructors" themselves could return by pointer if you want your objects allocated by new or they could return by value if you want the objects created on the stack.

The (even easier) non-technical approach is to put a big fat ugly comment next to the class definition. The comment could say, for example, // We'll fire you if you inherit from this class or even just /*final*/ class Whatever {...};. Some programmers balk at this because it is enforced by people rather than by technology, but don't knock it on face value: it is quite effective in practice.

A slightly trickier technical approach is to exploit virtual inheritance. Since the most derived class's ctor needs to directly call the virtual base class's ctor, the following guarantees that no concrete class can inherit from class Fred:

 class Fred;

 class FredBase {
 private:
   friend class Fred;
   FredBase() { }
 };

 class Fred : private virtual FredBase {
 public:
   ...
 }; 

Class Fred can access FredBase's ctor, since Fred is a friend of FredBase, but no class derived from Fred can access FredBase's ctor, and therefore no one can create a concrete class derived from Fred.

If you are in extremely space-constrained environments (such as an embedded system or a handheld with limited memory, etc.), you should be aware that the above technique might add a word of memory to sizeof(Fred). That's because most compilers implement virtual inheritance by adding a pointer in objects of the derived class. This is compiler specific; your mileage may vary.

like image 147
Vincent Robert Avatar answered Sep 29 '22 11:09

Vincent Robert


No, there isn't really a need to. If your class doesn't have a virtual destructor it isn't safe to derive from it anyway. So don't give it one.

You can use this trick, copied from Stroustrup's FAQ:

class Usable;

class Usable_lock {
    friend class Usable;
private:
    Usable_lock() {}
    Usable_lock(const Usable_lock&) {}
};

class Usable : public virtual Usable_lock {
    // ...
public:
    Usable();
    Usable(char*);
    // ...
};

Usable a;

class DD : public Usable { };

DD dd;  // error: DD::DD() cannot access
        // Usable_lock::Usable_lock(): private  member

In C++0x (and as an extension, in MSVC) you can actually make it pretty clean:

template <typename T>
class final
{
private:
    friend T; // C++0x, MSVC extension

    final() {}
    final(const final&) {}
};

class no_derived :
    public virtual final<no_derived> // ah, reusable
{};
like image 32
GManNickG Avatar answered Sep 29 '22 12:09

GManNickG