Узнайте отношения наследования между двумя классами объектов в C ++ - PullRequest
2 голосов
/ 07 ноября 2010

У меня есть абстрактный C ++ базовый класс CPlugin.Исходя из этого, есть много классов, полученных прямо и косвенно.Теперь, учитывая CPlugin * a, * b, мне нужно выяснить, является ли реальный класс a производным от реального класса b.

Т.е. я хотел бы сделать что-то вроде этого:

void checkInheritance(CPlugin *a, CPlugin *b){
  if (getClass(a).isDerivedFrom(getClass(b)){
    std::cout << "a is a specialization from b's class" << std::endl;
  }
}

Но как мне реализовать getClass и isDerivedFrom в C ++?

Ответы [ 5 ]

5 голосов
/ 07 ноября 2010

Вы не можете сделать это в C ++. Единственный способ получить некоторую информацию о типах во время выполнения - RTTI. RTTI не достаточно мощный, чтобы делать то, что вам нужно. Пожалуйста, объясните, чего вы пытаетесь достичь, тогда вы получите лучшие ответы.

3 голосов
/ 07 ноября 2010

Целостное решение действительно сложно предоставить. То, чего вы пытаетесь достичь, - это поведение, которое зависит от конкретного типа двух параметров: это называется двойной диспетчеризацией. Этой теме посвящено несколько страниц Modern C ++ Design (Андрей Александреску).

Когда фактический конкретный тип обоих параметров известен в одной кодовой точке, на часть «isDerivedFrom» можно ответить с помощью boost type_traits: boost is_base_of .

2 голосов
/ 07 ноября 2010

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

Таким образом, вы можете добиться того же эффекта с помощью виртуальной функции, чтобы у вас был тип во время компиляции с одной стороны, а затем динамическое приведение, чтобы проверить другую сторону по отношению к этому типу:

#include <iostream>

class Plugin {
    public:
    virtual bool objectIsDerivedFromMyClass ( const Plugin & object ) const = 0;
};

template <typename T, typename BasePlugin = Plugin>
class TypedPlugin : public BasePlugin {
    public:
    virtual bool objectIsDerivedFromMyClass ( const Plugin & object ) const {
        return dynamic_cast<const T*> ( &object ) != 0;
    }

    private:
        int CheckMe(const T*) const;
};

class PluginA : public TypedPlugin<PluginA> {};
class PluginB : public TypedPlugin<PluginB, PluginA> {};
class PluginC : public TypedPlugin<PluginC> {};

int main () {
    PluginA a;
    PluginB b;
    PluginC c;

    std::cout << std::boolalpha
    << "type of a is derived from type of a " <<  a.objectIsDerivedFromMyClass ( a ) << '\n'
    << "type of a is derived from type of b " <<  b.objectIsDerivedFromMyClass ( a ) << '\n'
    << "type of b is derived from type of a " <<  a.objectIsDerivedFromMyClass ( b ) << '\n'
    << "type of c is derived from type of a " <<  a.objectIsDerivedFromMyClass ( c ) << '\n'
    ;

    return 0;
}

(Вы также можете добавить проверку, которая T расширяет TypedPlugin<T>)

Это не совсем двойная отправка, хотя dynamic_cast полиморфна во время выполнения по своему аргументу, поэтому она довольно близка.

Хотя для чего-то гораздо более сложного (или если вы хотите придерживаться своего первоначального стиля сравнения объектов, представляющих типы времени выполнения объектов, которые у вас есть), вам нужно начать создавать метаклассы или использовать существующую инфраструктуру, которая предоставляет метаклассы. Поскольку вы говорите о плагинах, возможно, у вас уже есть где-то указать свойства конфигурации или зависимости, и это тоже можно использовать для этого.

0 голосов
/ 07 ноября 2010

Я не совсем понимаю, что вам нужно, но вы всегда можете использовать виртуальные методы следующим образом:

template <typename Derived>
struct TypeChecker
{
  virtual bool ParentOf(CPlugin const& c) const
  {
    return dynamic_cast<Derived const*>(&c);
  }
};

Теперь добавьте класс CPlugin с помощью следующего чисто виртуального метода:

  virtual bool ParentOf(CPlugin const& c) const = 0;

И каждый класс, производный от CPlugin, также наследуется от TypeChecker:

class SomePlugin: public CPlugin, private TypeChecker<SomePlugin> {};

И, наконец, используйте его следующим образом:

void checkInheritance(CPlugin const& lhs, CPlugin const& rhs)
{
  if (!rhs.ParentOf(lhs)) return;

  std::cout << "lhs is derived from rhs' class\n";
}

Это не определяет, является ли это специализацией, хотя, поскольку оба могут совершенно точно принадлежать к одному и тому же классу, это можно обнаружить с помощью оператора typeid.

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

0 голосов
/ 07 ноября 2010

Typeinfo и динамическое приведение: http://www.cplusplus.com/reference/std/typeinfo/type_info/

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...