Я совершенно запутался с dynamic_cast
ключевым словом в C ++.
struct A {
virtual void f() { }
};
struct B : public A { };
struct C { };
void f () {
A a;
B b;
A* ap = &b;
B* b1 = dynamic_cast<B*> (&a); // NULL, because 'a' is not a 'B'
B* b2 = dynamic_cast<B*> (ap); // 'b'
C* c = dynamic_cast<C*> (ap); // NULL.
A& ar = dynamic_cast<A&> (*ap); // Ok.
B& br = dynamic_cast<B&> (*ap); // Ok.
C& cr = dynamic_cast<C&> (*ap); // std::bad_cast
}
определение гласит:
dynamic_cast
Ключевое слово бросает геодезическое от одного указателя или ссылочного типа к другому, выполняя проверку выполнения для обеспечения достоверности гипса
Можем ли мы написать эквивалент dynamic_cast
C ++ в C, чтобы я мог лучше понять вещи?
c++
dynamic-cast
Виджай
источник
источник
dynamic_cast<>
работает негласно (или о том, как работает C ++), хорошей книгой (которую также довольно легко прочитать для чего-то такого технического) является книга Липпмана «Внутри объектной модели C ++». Также книги Страуструпа «Дизайн и эволюция C ++» и «Язык программирования C ++» являются хорошими источниками, но книга Липпмана посвящена тому, как C ++ работает «за кулисами».B* b2 = dynamic_cast<B*> (ap) // 'b'
?b2 is pointer to b
или что?Ответы:
Вот краткое изложение
static_cast<>
и, вdynamic_cast<>
частности, как они относятся к указателям. Это всего лишь 101-кратное изложение, оно не охватывает все тонкости.static_cast <Type *> (ptr)
Это берет указатель
ptr
и пытается безопасно привести его к указателю типаType*
. Это приведение сделано во время компиляции. Он будет выполнять приведение только в том случае, если типы типов связаны между собой. Если типы не связаны, вы получите ошибку компилятора. Например:dynamic_cast <Type *> (ptr)
Это снова пытается принять указатель
ptr
и безопасно привести его к указателю типаType*
. Но это приведение выполняется во время выполнения, а не во время компиляции. Поскольку это приведение во время выполнения, оно полезно, особенно в сочетании с полиморфными классами. Фактически, в некоторых случаях классы должны быть полиморфными, чтобы состав был законным.Приведения могут идти в одном из двух направлений: от основания к производному (B2D) или от производного к базе (D2B). Достаточно просто увидеть, как будет выполняться приведение D2B во время выполнения. Либо
ptr
было получено из,Type
либо нет. В случае D2B dynamic_cast <> правила просты. Вы можете попытаться привести что-либо к чему-либо еще, и, если оноptr
действительно было получено изType
, вы получитеType*
указатель обратноdynamic_cast
. В противном случае вы получите нулевой указатель.Но броски B2D немного сложнее. Рассмотрим следующий код:
main()
Я не могу сказать, какой тип объектаCreateRandom()
вернется, поэтому приведение в стиле CBar* bar = (Bar*)base;
определенно небезопасно. Как ты мог это исправить? Одним из способов было бы добавить функцию типа boolAreYouABar() const = 0;
в базовый класс и возвращатьсяtrue
изBar
иfalse
изFoo
. Но есть и другой способ: usedynamic_cast<>
:Приведения выполняются во время выполнения и работают путем запроса объекта (пока не нужно беспокоиться о том, как это сделать), спрашивая, соответствует ли он типу, который мы ищем. Если это так,
dynamic_cast<Type*>
возвращает указатель; в противном случае возвращается NULL.Для того, чтобы это приведение от основания к производному работало с использованием
dynamic_cast<>
, Base, Foo и Bar должны быть тем, что Стандарт называет полиморфными типами . Чтобы быть полиморфным типом, ваш класс должен иметь хотя бы однуvirtual
функцию. Если ваши классы не являются полиморфными типами, базовое-производное использованиеdynamic_cast
не будет компилироваться. Пример:Добавление виртуальной функции к базе, такой как виртуальный dtor, приведет к полиморфным типам Base и Der:
источник
Base* base = new Base;
,dynamic_cast<Foo*>(base)
будетNULL
.dynamic_cast<Foo*>(base)
в случаеBase* base = new Base;
?base
это не такFoo
.Base
Указатель может указывать наFoo
, но это по - прежнемуFoo
, так что динамическое приведение будет работать. Если вы это делаетеBase* base = new Base
,base
это aBase
, а не aFoo
, поэтому вы не можете динамически привести его к aFoo
.Если вы не реализуете свой собственный RTTI, свернутый вручную (и обходя системный), невозможно реализовать
dynamic_cast
непосредственно в коде пользовательского уровня C ++.dynamic_cast
очень сильно связан с системой RTTI реализации C ++.Но, чтобы помочь вам лучше понять RTTI (и, следовательно,
dynamic_cast
), вы должны прочитать<typeinfo>
заголовок иtypeid
оператора. Это возвращает информацию о типе, соответствующую объекту, который у вас есть, и вы можете запрашивать различные (ограниченные) вещи из этих объектов информации о типе.источник
dynamic_cast
очень скудны. :-P Просто играй с этим сам, пока не освоишься. :-)Больше, чем код на C, я думаю, что английского определения может быть достаточно:
При наличии класса Base, в котором есть производный класс Derived,
dynamic_cast
он преобразует указатель Base в указатель на производное, если и только если фактический объект, на который указывает объект, фактически является производным объектом.В этом примере вызов
test
связывает различные объекты со ссылкой наBase
. Внутренне ссылка понижается до ссылки безопасным дляDerived
типов способом: снижение будет успешным только в тех случаях, когда ссылочный объект действительно является экземпляромDerived
.источник
Следующее не совсем близко к тому, что вы получаете от C ++ с
dynamic_cast
точки зрения проверки типов, но, возможно, это поможет вам немного лучше понять его назначение:источник
A
dynamic_cast
выполняет проверку типа с использованием RTTI . Если он потерпит неудачу, он выдаст вам исключение (если вы дали ему ссылку) или NULL, если вы дали ему указатель.источник
Во-первых, чтобы описать динамическое приведение в терминах C, мы должны представить классы в C. Классы с виртуальными функциями используют «VTABLE» указателей на виртуальные функции. Комментарии C ++. Не стесняйтесь переформатировать и исправить ошибки компиляции ...
Тогда динамическое приведение выглядит примерно так:
источник
В C нет классов, поэтому невозможно написать dynamic_cast на этом языке. Структуры C не имеют методов (в результате у них нет виртуальных методов), поэтому в них нет ничего «динамического».
источник
Нет не легко Компилятор присваивает уникальную идентификацию каждому классу, на эту информацию ссылается каждый экземпляр объекта, и именно это проверяется во время выполнения, чтобы определить, допустимо ли динамическое приведение. Вы можете создать стандартный базовый класс с этой информацией и операторами для выполнения проверки времени выполнения для этого базового класса, тогда любой производный класс сообщит базовому классу о своем месте в иерархии классов, и любые экземпляры этих классов будут доступны для выполнения во время выполнения с помощью ваши операции.
редактировать
Вот реализация, которая демонстрирует одну технику. Я не утверждаю, что компилятор использует что-то подобное, но я думаю, что он демонстрирует концепции:
источник
dynamic_cast использует RTTI. Это может замедлить работу вашего приложения, вы можете использовать модификацию шаблона дизайна посетителя, чтобы добиться снижения рейтинга без RTTI http://arturx64.github.io/programming-world/2016/02/06/lazy-visitor.html
источник
static_cast< Type* >(ptr)
static_cast в C ++ может использоваться в сценариях, где все приведение типов может быть проверено во время компиляции .
dynamic_cast< Type* >(ptr)
dynamic_cast в C ++ может быть использован для выполнения безопасного приведения типов . dynamic_cast - это полиморфизм времени выполнения. Оператор dynamic_cast, который безопасно преобразует указатель (или ссылку) в базовый тип в указатель (или ссылку) в производный тип.
например, 1:
Для получения дополнительной информации нажмите здесь
например, 2:
источник