views:

417

answers:

1

Hi I'm wondering whether there is a way to find out whether a class is a direct base of another class i.e. in boost type trait terms a is_direct_base_of function. As far as I can see boost doesn't see to support this kind of functionality which leads me to think that its impossible with the current C++ standard.

The reason I want it is to do some validation checking on two macro's that are used for a reflection system to specify that one class is derived from another e.g.

header.h:

#define BASE     A
#define DERIVED  B

class A {};
class B : public A 
{
   #include <rtti.h>
};

rtti.h:

// I want to check that the two macro's are correct with a compile time assert
Rtti<BASE, DERIVED> m_rtti;

Although the macro's seem unnecessary in this simple example in my real world scenario rtti.h is a lot more complex.

One possible avenue would be to compare the size of the this pointer with the size of a this pointer cast to the base type and some how trying to figure out whether its the size of the base class itself away or something (yeah your right I don't know how that would work either! lol)

+10  A: 

I asked myself, "What C++ constructs do differentiate between direct inheritance vs. indirect?" It comes to mind that C++ constructors of derived types directly call constructors for their direct base(s) only. So code like this:

Derived::Derived() : Base() {}

Is only valid if Base is is a direct base of Derived. And since you are injecting the code of rtti.h into the body of Derived, you can tolerate the restriction that this technique is only directly visible within the derived class itself (i.e. it is not as general as a hypothetical type_traits::is_direct_base_of, but does not need to be).

So since we probably don't want to mess around with the default constructors per se, how about adding some special-purpose ones?

#define BASE     A
#define DERIVED  B

struct rtti_tag {}; // empty type

class A
{
protected:
    A(rtti_tag) { assert(false); } // never actually called
};

#include <rtti.h>
class B : public A
{
    IS_DIRECT_BASE_OF(DERIVED, BASE); // fails to compile if not true
};

rtti.h:

#define IS_DIRECT_BASE_OF(_B_, _A_) _B_(rtti_tag tag) : _A_(tag) \
    { assert(false); } // never actually called

This code compiles for me with g++ 4.2; if I insert a new class in the inheritance hierarchy, the assertion breaks and compilation fails with what I think is a reasonably descriptive diagnostic:

In constructor ‘B::B(rtti_tag)’:
error: type ‘A’ is not a direct base of ‘B’
...
John Zwinck
`Derived::Derived() : Base() {}` is also valid if `Base` is a non-direct virtual base class -- possibly that case could be eliminated with (yet another) test? +1 anyway.
j_random_hacker
Good point, j_random_hacker, that's pretty clever (or evil!). I don't know offhand how to fix this "problem," but hopefully it's enough of a pathological thing that it doesn't really need to be addressed (C++ being a language where the ill-intentioned can make a mess of almost anything).
John Zwinck
I agree, it's a pathological case that you don't need to lose sleep over. I thought of it because I once saw a trick to prevent further derivation from a class (i.e. force it to be a "leaf") that was also subverted by virtual inheritance. VI is really a bit of a language design hack -- e.g. a virtual base class's `operator=()` will be called an unspecified number of times when an object of derived class is assigned to.
j_random_hacker