Существует ли более быстрый способ обнаружить тип объекта во времени выполнения, чем использование dynamic_cast?

Несмотря на то, что люди должны иметь возможность комментировать код, совершенно необязательно, чтобы язык непосредственно поддерживал комментирование: для большинства языков было бы тривиально написать сценарий, который удаляет однострочные комментарии (например, все строки, начинающиеся с «#» или другого символа), затем запускает компилятор.

На самом деле, однако, я удивлен и разочарован, узнав, что даже мои любимые эзотерические языки программирования поддерживают комментарии: Brainf ** k и Whitespace . Эти языки предназначены для того, чтобы их было трудно читать, поэтому кажется, что они не должны поддерживать комментирование. (В отличие от моего другого любимого эзотерического языка: LOLCode , который предназначен для самодокументирования, в речи лолкатов)

Я бы не согласился с другими ответчиками по этому вопросу: I скажем, будьте верны своему видению языка программирования клингон и не поддерживайте комментарии!

6
задан Joris Timmermans 16 June 2009 в 09:16
поделиться

8 ответов

Я всегда смотрю на использование dynamic_cast как на запах кода. Вы можете заменить его в любых обстоятельствах на полиморфное поведение и улучшить качество кода. В вашем примере я бы сделал что-то вроде этого:

class GenericClass
{
  virtual void DoStuff()
  {
    // do interesting stuff here
  }
};

class InterestingDerivedClass : public GenericClass
{
  void DoStuff()
  {
    // do nothing
  }
};

class CallbackImpl : public ICallback {
    void DoStuff( GenericClass* param ) {
        param->DoStuff();
    }
}

В вашем случае вы не можете изменять целевые классы, вы программируете на контракт, подразумеваемый объявлением типа GenericClass . Следовательно, вряд ли что-то из того, что вы можете сделать, было бы быстрее, чем dynamic_cast , поскольку что-либо еще потребует изменения кода клиента.

12
ответ дан 8 December 2019 в 05:23
поделиться

Как уже говорили другие, использование виртуальной функции является хорошей практикой. Есть еще одна причина для его использования, неприменимая в вашем случае, так как вы не можете добавить VF, но все же стоит упомянуть, я думаю - это может быть намного быстрее, чем использование динамического преобразования. В некоторых (не очень строгих) тестах, которые я провел с g ++, виртуальная функция превзошла dynamic_cast в 4 раза

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

5
ответ дан 8 December 2019 в 05:23
поделиться

Мне кажется, это довольно хакерский дизайн. (Как уже отмечали другие, использование dynamic_cast обычно является признаком того, что у вас есть проблема с дизайном.) Но если большая часть кода находится вне вашего контроля, я полагаю, вы мало что можете с этим поделать.

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

Кстати, причина того, что dynamic_cast настолько дорого, может заключаться в том, что он должен пройти всю иерархию классов. Если у вас есть глубокая иерархия, это обойдется вам дорого (другими словами, у вас нет глубокой иерархии, как правило,

2
ответ дан 8 December 2019 в 05:23
поделиться

Будет ли сравнение type_info быстрее? (вызовите typeid для параметра param )

1
ответ дан 8 December 2019 в 05:23
поделиться

Во-первых, не оптимизируйте преждевременно. Во-вторых, если вы запрашиваете объект для конкретной реализации внутри, вероятно, что-то не так с вашим дизайном (подумайте о двойной отправке).

Что касается исходного вопроса, представляем функцию GetRuntimeType () в ICallback подойдет очень хорошо: см. MFC, как это можно сделать.

1
ответ дан 8 December 2019 в 05:23
поделиться

В вашем конкретном случае ответ заключается в использовании виртуальных функций.

Однако есть ситуации, когда вам нужно динамически понижать значение. Есть несколько способов сделать эту операцию быстрее (или намного быстрее, в зависимости от того, насколько умно ваш компилятор реализует dynamic_cast ), в частности, если вы ограничиваете себя одиночным наследованием. Основная идея состоит в том, что если вы каким-то образом знаете точный тип, static_cast будет намного быстрее:

f(A* pA)
{
  if (isInstanceOfB(pA))
  {
    B* pB = static_cast<B*>(pA);
    // do B stuff...
  }
}

Конечно, теперь проблема заключается в быстрой реализации isInstanceOfB ().

См. ] boost :: type_traits , например.

1
ответ дан 8 December 2019 в 05:23
поделиться

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

Пример реализации:

// fast dynamic cast
//! Fast dynamic cast declaration
/*!
Place USE_CASTING to class that should be recnognized by dynamic casting.
Do not forget do use DEFINE_CASTING near class definition.
*\note Function dyn_cast is fast and robust when used correctly.
Each class that should be used as target for dyn_cast
must use USE_CASTING and DEFINE_CASTING macros.\n
Forgetting to do so may lead to incorrect program execution,
because class may be sharing _classId with its parent and IsClassId
will return true for both parent and derived class, making impossible'
to distinguish between them.
*/
#define USE_CASTING(baseType) \
  public: \
  static int _classId; \
  virtual size_t dyn_sizeof() const {return sizeof(*this);} \
  bool IsClassId( const int *t ) const \
  { \
    if( &_classId==t ) return true; \
    return baseType::IsClassId(t); \
  }

//! Fast dynamic cast root declaration
/*!
Place USE_CASTING_ROOT to class that should act as
root of dynamic casting hierarchy
*/

#define USE_CASTING_ROOT \
  public: \
  static int _classId; \
  virtual size_t dyn_sizeof() const {return sizeof(*this);} \
  virtual bool IsClassId( const int *t ) const { return ( &_classId==t ); }

//! Fast dynamic cast definition
#define DEFINE_CASTING(Type) \
  int Type::_classId;

template <class To,class From>
To *dyn_cast( From *from )
{
  if( !from ) return NULL;
  if( from->IsClassId(&To::_classId) )
  {
    assert(dynamic_cast<To *>(from));
    return static_cast<To *>(from);
  }
  return NULL;
}

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

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

1
ответ дан 8 December 2019 в 05:23
поделиться

Можете ли вы использовать http://www.boost.org/doc/libs/1_39_0/boost/type_traits/is_convertible.hpp и проверить производительность процессора?

Вы также можете проверить реализацию ..

Ссылка: http://www.boost.org/doc/libs/1_39_0/libs/type_traits/doc/html/boost_typetraits /reference/is_convertible.html

0
ответ дан 8 December 2019 в 05:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: