Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to find out whether a class is a direct base of another class?

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 seem to support this kind of functionality, which leads me to think that it's impossible with the current C++ standard.

The reason I want it is to do some validation checking on two macros that are used for a reflection system to specify that one class is derived from another, as in the example code below.

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 macros 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 somehow trying to figure out whether it's the size of the base class itself away or something. (Yeah, you're right, I don't know how that would work either!)

like image 997
user176168 Avatar asked Dec 23 '22 05:12

user176168


1 Answers

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’
...
like image 128
John Zwinck Avatar answered May 11 '23 00:05

John Zwinck