Click here to Skip to main content
Click here to Skip to main content

A non-inheritable class

, 30 Jun 2003 CPOL
Rate this:
Please Sign up or sign in to vote.
A class that cannot be inherited from

Introduction

It is a common question why we shouldn’t inherit classes from STL classes. The answer of this question is simple. Big three rule [CLI95]. In other words you should have virtual destructor in a class if you want to make it a base class. However there aren’t any class in STL which define virtual destructor. Even if you try to inherit a class from STL class the compiler doesn’t complain about it, but there is a high chance of resource leak in the program. It makes programmers life easy if the compiler catches as many errors as it can during compilation. So it is nice idea to make a class in such a way that you  can’t inherit class from it, in other words a Final class.

Background

One day during a  discussion with one of my friends, who is mostly working on java, we compared the object-oriented features of Java and C++. And he introduced me to one interesting concept of java called Final class, i.e. a class from which you cant inherit any further class. It was a totally new concept for me at that time and I liked it because most of the time I wish I could make a class in C++ from which others cant inherit. He asked me to do this in C++ and I start thinking about it and doing some experimentation. Before further discussion on how we can make it, it is useful to discuss why should we need it.

Why might we need a final class?

One possible scenario, which comes to my mind that would be useful for "Final class" is a class without virtual destructor. Suppose you are making a class, which doesn’t have virtual destructor, and it may contain some dynamically allocated object. Now if any one inherits a class from it and creates the object of derived class dynamically then it will clearly create resource leak although compiler will not complain about this.

class B { 
. . .
};

class D : public B {
. . .
};

B* pB = new D;
delete pB; // resource leak

Details of implementing a final class

To make a class final the first solution, which may come in mind, is to make its constructor private. And make static functions to create the objects. But there is one problem in this approach that there may be more than one constructor in the class and you have to make all of them private. There is still a chance that anyone can make another public constructor. Quick fix of this problem is to make destructor private instead of constructor because there can be only one destructor in the class.

class FinalClass
{
private:
  ~FinalClass() { }
public:
  static FinalClass* CreateInstance()
  {
    return new FinalClass;
  }
. . .
};
The one problem with this approach is that creation of object is not possible on the stack; object must be created on heap. And now it is the responsibility of the user of this class to destroy this object. Again in this case there is a chance of resource leak if user of this class forgot to delete the object of this class from the heap when it is not needed.

Lets take a look at another approach of making a class final and still make it in such a way that a client of this class can create its object on stack and not just on the heap. We all know that when we make one class friend of other then it can create object of that class even its destructor is private. So we can create one temporary class and make its constructor private. And inherit one class from it and also make the derived class friend of it base, because if we didn’t do it then we can’t inherit the class from another class whose constructor or destructor is private.

class Temp
{
private:
  ~Temp() { };
  friend class FinalClass;
};

class FinalClass : public Temp
{
. . .
};
But when you inherit any class from FinalClass this works fine. Let’s suppose you inherit derived class from FinalClass. Now when you create the object of derived class, its constructor is called, which will call the constructor of FinalClass and FinalClass’s constructor calls the constructor of Temp because FinalClass is friend of Temp. So everything is normal and our final class is still inheritable in other words, it is not final as of now.

Before going into final class in more detail, let’s discuss the famous multiple inheritance problem, or the diamond problem. In that case you solve that problem by making virtual base class and inheriting intermediate classes virtually. But what is the purpose of virtual base class? In fact the object of most derived class (whose object is created) directly call the constructor of virtual base class. So we resolve the diamond problem, because now the most derived class (Bottom in case of diamond problem) directly calls the most base class (Top in diamond problem) constructor, and now there is only single copy of Top most class.

We can apply the same technique here. We inherit our FinalClass virtually from Temp class and make Temp as a virtual base class. Now whenever anyone attempts to inherit class from FinalClass and make object of it, then its constructor tries to call the constructor of Temp. But the constructor of Temp is private so compiler complains about this and it gives error during the compilation, because your derived class is not friend of Temp. Remember friendship is not inherited in the derived class. After all your parent's friends are not your friends and your friends are not friends of your children. But when you create object of FinalClass then its constructor can call the Temp’s constructor because FinalClass is friend of Temp. So here is final version of our final class, which can also be created on stack and not just in the heap.

class Temp
{
private:
  ~Temp() { };
  friend class FinalClass;
};

class FinalClass : virtual public Temp
{
. . .
};
But what is the case when you have to make more than one final class? You have to write double the classes i.e. if you need N final classes then you have to write 2N classes because in this method we have one temp class with private constructor and your final class. So you have to write lots of same code again and again. Why not try to take advantage of a template and try to make a class in such a way that if you inherit any class from that class your class will automatically become a Final class. The code of such a class is so simple.

template <typename T>
class MakeFinal
{
private:
  ~MakeFinal() { };
  friend T;
};
Don’t forget to virtually inherit your final class from this class to make sure this class becomes virtual base class. And pass your final class name as a template parameter so your class becomes friend of this and can call the constructor of this class.

class FinalClass : virtual public MakeFinal<FinalClass>
{
};

Conclusion

Of course nothing comes without cost. You have to pay the extra bytes to store the information about virtual base class. Most of the compiler implementations uses a pointer to store the information about the virtual base class in case of virtual inheritance. Therefore the size of the object is not just the sum of all the member variable storage allocation but it is greater than you expect. Remember that this pointer i.e. pointer to virtual base class is different than the virtual pointer, which is introduced in case of virtual function [LIP96]. This is totally an implementation issue; C++ standard doesn’t say anything about the mechanism of calling virtual function, virtual pointer and virtual table [ISO98].

Adding only one small class and changing few lines of code makes your program more reliable and reduces the resource leak problems, which could be created if you didn't use  a final class.

Reference

  1. [CLI95] 1995 C++ FAQs Marshall P Cline, Greg A Lomow
  2. [ISO98] 1998 International Standard Programming Language C++
  3. [LIP96] 1996 Inside the C++ Object Model Stanley B Lippman

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Zeeshan Amjad
Software Developer (Senior) Bloomberg LP
United States United States
Working as a Sr C++ Developer at Bloomberg LP

Comments and Discussions

 
GeneralNice PinmemberKuryn22-Oct-08 20:09 
Generalbeginer Pinmemberdnqhung12-Jun-04 21:27 
GeneralIllegal code PinmemberTanveer Badar13-Mar-04 19:25 
Questionfinal ? Pinmemberguillaume alcalay27-Oct-03 0:30 
AnswerRe: final ? PinmemberAngshuman26-Mar-04 0:34 
GeneralRe-post of my extension to this idea... Pinmemberta0kira21-Oct-03 4:32 
I originally posted this on the Borland CPP builder newsgroup, but I thought I would put it here so maybe the person giving me the idea could see it (cut-and-paste of the other post at http://newsgroups.borland.com/cgi-bin/dnewsweb?cmd=article&group=borland.public.cppbuilder.language.cpp&item=21329&utag= ).   Any and all comments are appreciated...
ta0kira
 

So I was on "The Code Project" yesterday and saw something very
interesting.   Someone named Zeeshan Amjad came up with a C++
version of the java "final" modifier that prevents any other
classes from being derived from a class that uses it.   Since I
don't like to post other people's code, here is the site:
http://www.codeproject.com/cpp/finalclass.asp?print=true
 
So I went home to try this out, and I had to add a typedef to get
it to work, but it worked.   I then split it into 2 classes so
that I would not have to use "virtual" when deriving a class from
it.   I put it on a lot of classes and it worked, but I got to a
template I have that I derived 4 specialized classes from.
Instead of putting the "final" on all 4 classes I wanted to put
it on the template and allow one more derivation so that anyone
could make a specialized class for the type of template, but then
could not derive any more classes from the specialized class.
This idea actually came to me on the way to work today, so I
wrote it out first thing when I got there and compiled and tested
it at lunch.   So here it is.   Hope you like it.
Kevin P. Barry (aka ta0kira)
 

//The second-to-last class, by ta0kira
 

//A dummy class is created for use as a default parameter:
 
//Dummy class-------------------------------------------------------------------
class UNUSED
{
     ~UNUSED() {}
}; //END------------------------------------------------------------------------
 

//A pre-class is created
 
//Pre-class---------------------------------------------------------------------
template <class Type1, class Type2> class SEC_;
 
template <class Type1, class Type2> class PRE_SEC
{
     typedef Type1 TYPE1;
     typedef Type2 TYPE2;
     friend TYPE1;
     friend TYPE2;
     friend class SEC_ <TYPE1, TYPE2>;
     PRE_SEC() {}
     ~PRE_SEC() {}
}; //END------------------------------------------------------------------------
 

//The pre-class is derived virtually into the second-to-last base class
 
//Second-to-last base class=====================================================
template <class Type1, class Type2 = UNUSED> class SEC_ :
virtual private PRE_SEC <Type1, Type2>
{
     typedef Type1 TYPE1;
     typedef Type2 TYPE2;
     friend TYPE1;
     friend TYPE2;
     SEC_() {}
     ~SEC_() {}
}; //END========================================================================
 

//EXAMPLE 1.....................................................................
 

//A template is derived from the second-to-last base class
 
//Class List--------------------------------------------------------------------
//Second-to-last class
template <class Type1, class Type2 = UNUSED> class List :
public SEC_ <List <Type1, Type2>, Type2>
{
     //Type1 related template functions
}; //END------------------------------------------------------------------------
 

//Since it is second-to-last, only one depth of inheritance is allowed
 
//Class int_List----------------------------------------------------------------
//Final class
class int_List : public List <int, int_List>
{
     //int-specific List functions
}; //END------------------------------------------------------------------------
 

//No further inheritance is allowed
 
//class NUMBERS : public int_List {}; //<-- does not work
//class NUMBERS : public int_List, public SEC_ <NUMBERS, int_List> {}; //Cheat?
//class NUMBERS : public int_List, public PRE_SEC <int_List, NUMBERS> {}; //??
//class NUMBERS : public int_List, public List <NUMBERS, NUMBERS> {}; //Cheat?
//Cheating does not work
 

//EXAMPLE 2.....................................................................
 

//A regular class is derived from the second-to-last base class
 
//Class FileManager-------------------------------------------------------------
//Final class
class FileManager : public SEC_ <FileManager>
{
     //File stuff
}; //END------------------------------------------------------------------------
 

//No further inheritance is allowed
 
//class New_File : public FileManager {}; //<-- does not work
 
int main()
{
     List <int> LIST_OF_INT; //Works as base class
     int_List INT_SPECIFIC; //Works as specialized class
     FileManager FILE;
}
 

//An additional note is this can be used to finalize a class or allow one more
//class to be derived without making it a virtual base class.   This keeps you
//from forgetting 'virtual' and also reduces potential abuse of the class.
 

I think potentially you could make 3rd to last, etc., if you felt
inclined to do so...
ta0kira
 
"No-mind-no-thought"
ta0kira
GeneralRe: Re-post of my extension to this idea... PinmemberZeeshan Amjad22-Oct-03 3:46 
GeneralVirtual Destructor Pinmemberdeelaw10-Jul-03 16:49 
GeneralRe: Virtual Destructor PinmemberStephen Quattlebaum11-Jul-03 7:54 
GeneralZeshan! PinmemberKhurram Aziz2-Jul-03 1:51 
GeneralRe: Zeshan! PinmemberDavidCrow8-Jul-03 6:06 
GeneralBjarne Stroustrup's C++ Style and Technique FAQ Pinmemberv71-Jul-03 4:30 
GeneralRe: Bjarne Stroustrup's C++ Style and Technique FAQ PinmemberAlexandru Savescu1-Jul-03 5:43 
GeneralRe: Bjarne Stroustrup's C++ Style and Technique FAQ PinsussMårten R1-Jul-03 6:02 
GeneralRe: Bjarne Stroustrup's C++ Style and Technique FAQ PinmemberAlexandru Savescu1-Jul-03 6:08 
GeneralRe: Bjarne Stroustrup's C++ Style and Technique FAQ PinmemberKlaus Nowikow8-Jul-03 8:12 
GeneralRe: Bjarne Stroustrup's C++ Style and Technique FAQ PinsussAnonymous9-Jul-03 10:56 
GeneralHmmm PinmemberIan Darling1-Jul-03 3:29 
GeneralInteresting article PineditorNishant S1-Jul-03 1:52 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.141216.1 | Last Updated 1 Jul 2003
Article Copyright 2003 by Zeeshan Amjad
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid