Как обычно выполняется dynamic_cast? - PullRequest
6 голосов
/ 23 июля 2010

Является ли проверка типа простым целочисленным сравнением? Или имеет смысл иметь виртуальную функцию GetTypeId для различения, которая сделает его целочисленным сравнением?

(просто не хочу, чтобы в именах классов сравнивались строки)

РЕДАКТИРОВАТЬ: Я имею в виду, что если я часто ожидаю неправильный тип, имеет ли смысл использовать что-то вроде:

struct Token
{
    enum {
        AND,
        OR,
        IF
    };
    virtual std::size_t GetTokenId() = 0;
};

struct AndToken : public Token
{
    std::size_t GetTokenId() { return AND; }
};

И используйте член GetTokenId вместо того, чтобы полагаться на dynamic_cast.

Ответы [ 4 ]

6 голосов
/ 23 июля 2010

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

В дополнение к проверке типа, dynamic_cast может выполнять приведение к void * и иерархическое перекрестное приведение. Эти типы приведений концептуально требуют некоторой способности проходить иерархию классов в обоих направлениях (вверх и вниз). Структуры данных, необходимые для поддержки таких приведений, являются более сложными, чем простой скалярный идентификатор типа. Информация, используемая dynamic_cast, является частью RTTI.

Попытка описать это здесь будет контрпродуктивной. Раньше у меня была хорошая ссылка, описывающая одну из возможных реализаций RTTI ... попробую ее найти.

1 голос
/ 27 августа 2012

Я не знаю точную реализацию, но вот идея, как бы я это сделал:

Приведение от Derived* к Base* может быть выполнено во время компиляции. Приведение между двумя несвязанными полиморфными типами может быть выполнено и во время компиляции (просто верните NULL).

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

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

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

1 голос
/ 23 июля 2010

В некоторых оригинальных компиляторах вы правы, они использовали сравнение строк.

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

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

Но это также древняя история.

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

0 голосов
/ 23 июля 2010

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

...