Какой смысл IsA () в C ++? - PullRequest
       3

Какой смысл IsA () в C ++?

4 голосов
/ 09 ноября 2010

Я пытаюсь выяснить, почему некоторые кодовые базы используют IsA () для определения полиморфизма объектов, если в C ++ вы уже можете безопасно повышать и понижать (используя dynamic_cast)?

Пока единственный случай, который яНасколько полезно, когда вы интегрируете среду сценариев, связанную с базой кода C ++?

Спасибо!

Ответы [ 5 ]

8 голосов
/ 09 ноября 2010

Существует несколько причин, по которым требуется IsA() функция или даже dynamic_cast<>() в C ++.Наихудшими примерами кода такого типа являются гигантские операторы if-then, использующие dynamic_cast s, или операторы switch в поле type.Они представляют собой кошмар обслуживания, где добавление класса может включать обновление десятков или сотен различных мест для поддержки нового класса.

Например:

Плохо:

// Don't do this:
void PrintName(Base *b, ostream &o)
{
   if (dynamic_cast<DerivedA *>(b) != NULL)
      o << "Derived A";
   if (dynamic_cast<DerivedB *>(b) != NULL)
      o << "Derived B";
   if (dynamic_cast<DerivedC *>(b) != NULL)
      o << "Derived C";
}

Лучше:

void PrintName(Base *b, ostream &o)
{
   o << b->GetName();
}

Это, очевидно, исключение проверки на нулевое значение, использование умных указателей и т. Д. Аналогично, если вы запрашиваете тип для выбора между различными поведениями, вам нужно спросить, почему вывы делаете что-то свое для каждого типа и переносите это решение о поведении в объект.

Плохо:

// Don't do this:
void ObjectBase::ApplyForceToObject(const Force &f)
{
    if (dynamic_cast<Wall*>(this) != NULL
        || dynamic_cast<Floor*>(b) != NULL)
    {
        // Do nothing
    }
    else
    {
        // Accelerate object
    }
}

Лучше:

void ObjectBase::ApplyForceToObject(const Force &f)
{
    if (IsFixedObject())
    {
        // Do nothing
    }
    else
    {
        // Accelerate object
    }
}
...
bool ObjectBase::IsFixedObject() { return false; }
bool Wall::IsFixedObject() { return true; }
bool Floor::IsFixedObject() { return true; }
5 голосов
/ 09 ноября 2010

В современном C ++ нет никакого смысла.

Фреймворки, созданные до стандартизации 1998 года, могут предлагать функцию IsA.

Например, насколько я помню, в MFC есть такая функциональность.

Также, как вы заметили, при работе с объектами, реализованными на других языках (с типами, не представленными в типах C ++), это может быть полезно.

Приветствия & hth.,

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

Поскольку динамическое приведение зависит от RTTI, и это может снизить производительность. Это также немного более удобно и надежно.

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

Иногда у вас нет RTTI (возможно, вы работаете в системе с ограничением памяти / процессора, и отключение RTTI является обязательным решением). В этом случае вам не доступен dynamic_cast. Если вы хотите использовать что-то похожее на RTTI, вы обычно получаете решения IsA () со static_cast.

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

handleInstance( Instance * i )
{
  //libs has been filled through loading dynamic libraries.
  for( auto it = libs.begin() ; it!=libs.end() ; ++it )
  {
     if( i->IsA( it->type_key ) )
     {
        it->process( i );
     }
  }
}

Хотя в этом случае я могу вывернуть тестовое условие наизнанку, как

if( it->can_process( i ) )

и can_process могут свободно использовать dynamic_cast.

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

Пример поиска информации о типе времени выполнения без RTTI

MFC использует функцию IsKindOf () для получения информации о типе времени выполнения.Метод, используемый MFC для поиска информации о типе, похож на пример, приведенный ниже.

#define RUNTIME_CLASS(class_name) (class_name::GetThisClass())
#define RUNTIME_OBJ(class_name) (class##class_name)
struct RunTimeClass
{
    string name;
};
class base
{
    static RunTimeClass RUNTIME_OBJ(base); //watch the naming 
public:

    bool IsExactKind(RunTimeClass* pRTclass)
    {
        if(pRTclass == GetRunTimeClass())
        {
            return true;
        }
        return false;

    }

    static RunTimeClass* GetThisClass()
    {
        return &RUNTIME_OBJ(base);      
    }

    virtual RunTimeClass* GetRunTimeClass()
    {
        return &RUNTIME_OBJ(base);
    }
    virtual ~base() = 0;
};

class derived: public base
{
    static RunTimeClass RUNTIME_OBJ(derived); //watch the naming
public:
    RunTimeClass* GetRunTimeClass()
    {
        return &RUNTIME_OBJ(derived);       
    }

    static RunTimeClass* GetThisClass()
    {
        return &RUNTIME_OBJ(derived);       
    }

};

class derived2: public derived
{
    static RunTimeClass RUNTIME_OBJ(derived2); //watch the naming
public:
    RunTimeClass* GetRunTimeClass()
    {
        return &RUNTIME_OBJ(derived2);      
    }

    static RunTimeClass* GetThisClass()
    {
        return &RUNTIME_OBJ(derived2);      
    }

};

В файле cpp

RunTimeClass base::classbase = {"base"}; //not using the macro RUNTIME_OBJ
RunTimeClass derived::classderived = {"derived"}; //not using the macro RUNTIME_OBJ
RunTimeClass derived2::classderived2 = {"derived2"}; //not using the macro RUNTIME_OBJ
base::~base() {}
void main()
{
    derived *ptrDer = new derived();
    bool isder = ptrDer->IsExactKind(RUNTIME_CLASS(derived));

    derived2 *ptrDer2 = new derived2();
    isder = ptrDer2->IsExactKind(RUNTIME_CLASS(derived2));

    delete ptrDer;
    delete ptrDer2;
}

Обратите внимание, что это можно найти только в том случае, если объект имеет точныйтип класса.Чтобы добавить информацию о типе, вам просто нужно наследовать от базы и добавить переменную Runtimeclass и реализовать две функции getthisclass (), getruntimeclass ().MFC использует CObject в качестве базового класса, который обеспечивает аналогичную функциональность.Кроме того, есть больше макросов, чтобы сделать вашу жизнь проще.Функция IsKindOF () в MFC обходит всю иерархию и обнаруживает, что объект «является» типом класса (которого нет в моей уменьшенной версии).Вы можете видеть, что это немного похоже на RTTI, поэтому я думаю, что нет разницы в производительности.Он есть в MFC, потому что он был там до RTTI.

Итак, если есть функция IsA (), которая работает лучше, чем RTTI, я бы хотел увидеть реализацию.

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