template <class A, class B>
struct TypeList
{
typedef A Value;
typedef B Next;
};
template <class T>
struct FriendMaker { typedef T Type; };
template <class Base, class DerivedList, int DerivedCount>
class Uninheritable;
template <class Base>
class Uninheritable<Base, void, 0>
{
friendclass FriendMaker<Base>::Type;
virtual ~Uninheritable(){}
};
template <class Base, class DerivedList>
class Uninheritable<Base, DerivedList, 1>
{
friendclass FriendMaker<Base>::Type;
friendclass FriendMaker<typename DerivedList::Value>::Type;
virtual ~Uninheritable(){}
};
template <class Base, class DerivedList>
class Uninheritable<Base, DerivedList, 2>
{
friendclass FriendMaker<Base>::Type;
friendclass FriendMaker<typename DerivedList::Value>::Type;
friendclass FriendMaker<typename DerivedList::Next::Value>::Type;
virtual ~Uninheritable(){}
};
//etc...
//======================================================================
class Color : virtualpublic Uninheritable<Color,
TypeList<class Red, TypeList<class Blue, void> >,2> {};
class Red : public Color {};
class Blue : public Color {};
class Bird : public Color {};
int main()
{
Color color;
Red red;
Blue blue;
//uncommenting the following causes a compilation error
//Bird bird;
return 0;
}
While I don't see why you need virtual inheritence or the derived count. But then again.. I don't see why you need typelists for this either. ;)
Basically its based on the "name of the class", which is indeed probably not so usefull..
Simpler version for easier understanding what principle is used here (except that my version prohibits instances of "Color" as well and that r0shi uses the destructor, I am using constructor.):
1 2 3 4 5 6 7 8 9 10 11 12
class Color
{
Color() {} // private constructor, so nobody can subclass it by default...
// ...except these guys
friendclass Red;
friendclass Blue;
};
class Red : public Color {}; // OK. Red is a friend of Color.
class Blue : public Color {}; // ditto
class Bird : public Color {}; // nope! Bird is no friend so can't call the constructor of Color.
...
Well, I want to be able to create base class objects.
I wanted to provide a generic solution that doesn't have any unwanted side-effects.
Virtual inheritance is necessary here, as it makes derived classes have to call the
Uninheritable dtor directly (not through the base class), and this is what causes
the compilation error (the Uninheritable dtor is private to them).
And since this is a generic solution, I need a way to pass the set of
allowed derived types to the Uninheritable class. That's why I need the
DerivedList template param.
I wanted to make something that iterates through the typelist and befriends types as it goes,
but this doesn't seem possible :/ That's why I need the DerivedCount template param.
It's code you write once and can use always.
The only thing you have to add to your classes when
you define them is a line like the following, next to their name:
The purpose of this question is to limited the scope of inheritance and also avoid the misuse of
inheritance. I took example color ,red ,bird classes . The intension of these classes to limit the
inheritance to its subcategory. like red can derived color class but bird does not come into
that category.
So anone whio write any class can inherit class to the respective category and get error if it tries to inherit class to diffirent category
Yet, the question is: What makes the "categories" different to each other?
The current solutions presented are based on a specific list of names of the classes allowed to inherited (whereas m4ster r0shi's version is much stricter than mine, but still its based on an explicit enumeration of all names of classes).
If you categorize your classes by other things, the solution would have to look much different. For example, you could say that: "A class which subclasses 'Color' must provide a member function 'PaintHouse' to paint a house with its own colour."
The natural solution to this categorizing would be "abstract virtual functions" (also called "pure virtual functions").
This would make much more sense to me than just restricting the subclassing by listing names of classes.
@m4ster r0shi: Ah, I got the point with the virtual inheritance. You are trying to disallow sub-sub-classes? Nice usage ;). But that works only on the constructor and not the destructor, so you have to use a private constructor, right?
About the DerivedCount... Couldn't you specialize the Uninheritable for void to mark the end of the typelist instead and then subclass from the next item in the list? This would remove the need to add a template specialization for every possible typelist length as well as the need to specify the count of your types.
Hm.. on second thought, that won't work with the private constructor.
It is probably possible by using an own inheritance hierachy template of a helper class that only holds the type of the incomplete class it has to be friend with.. somehow... maybe? Or maybe not. Can't think of a working solution right now. But then again, I doubt restricting subclasses to a named list of classes is that usefull in practice anyway.
The natural solution to this categorizing would be "abstract virtual functions"
(also called "pure virtual functions"). This would make much more sense
to me than just restricting the subclassing by listing names of classes.
Agreed.
imi wrote:
Ah, I got the point with the virtual inheritance.
Though, to be honest, it wasn't me the one who came up with that;
I saw it somewhere on the net :P The FriendMaker workaround wasn't my idea either.
imi wrote:
About the DerivedCount...
The thing is that as long as inheritance prevention relies
on friendship there's not much you can do... :S
My guess is that a really useful way to do this would require
a completely different approach to the solution core.
imi wrote:
But then again, I doubt restricting subclasses to a named list of classes is that usefull in practice anyway.