Есть ли способ узнать, является ли класс прямой базой другого класса? - PullRequest
4 голосов
/ 14 февраля 2010

Мне интересно, есть ли способ выяснить, является ли класс прямой базой другого класса, т. Е. В терминах черты типа Boost функция is_direct_base_of. Насколько я могу судить, Boost, похоже, не поддерживает такую ​​функциональность, что заставляет меня думать, что это невозможно с текущим стандартом C ++.

Причина, по которой я хочу, состоит в том, чтобы выполнить некоторую проверку правильности двух макросов, которые используются для системы отражения, чтобы указать, что один класс является производным от другого, как в примере кода ниже.

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;

Хотя макросы кажутся ненужными в этом простом примере, в моем реальном сценарии rtti.h намного сложнее.

Одним из возможных способов было бы сравнить размер указателя this с размером указателя this, приведенного к базовому типу, и каким-то образом попытаться выяснить, является ли размер базового класса сам по себе или что-то в этом роде. (Да, ты прав, я тоже не знаю, как это сработает!)

1 Ответ

11 голосов
/ 14 февраля 2010

Я спросил себя: «Какие конструкции C ++ различают прямое наследование от косвенного?» Вспоминается, что конструкторы C ++ производных типов напрямую вызывают конструкторы только для их прямой базы. Так что код такой:

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

Действителен, только если Base является прямой базой Derived. И поскольку вы вводите код rtti.h в тело Derived, вы можете допустить ограничение, заключающееся в том, что этот метод виден только непосредственно в самом производном классе (т. Е. Он не такой общий, как гипотетический type_traits::is_direct_base_of, но не обязательно).

Так что, вероятно, мы не хотим возиться с конструкторами по умолчанию сами по себе, как насчет добавления некоторых специализированных?

#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

Этот код компилируется для меня с g ++ 4.2; если я добавлю новый класс в иерархию наследования, разрывы утверждения и компиляция завершатся неудачно, что, по моему мнению, является достаточно описательной диагностикой:

In constructor ‘B::B(rtti_tag)’:
error: type ‘A’ is not a direct base of ‘B’
...
...