Как зайти в Даркнет?!
25th January, 01:11
8
0
Как в tkinter из поля ввода Entry получить значение в одну переменную и обновить строку кнопкой, затем получить ещё одно введённое значение и затем сложить их. Ниже пример кода
21st July, 19:00
898
0
Программа, которая создает фейковые сервера в поиске игровых серверов CS 1.6 Steam
21st March, 17:43
950
0
Очень долго работает Update запрос Oracle
27th January, 09:58
916
0
не могу запустить сервер на tomcat HTTP Status 404 – Not Found
21st January, 18:02
907
0
Где можно найти фрилансера для выполнения поступающих задач, на постоянной основе?
2nd December, 09:48
940
0
Разработка мобильной кроссплатформенной военной игры
16th July, 17:57
1725
0
период по дням
25th October, 10:44
3957
0
Пишу скрипты для BAS только на запросах
16th September, 02:42
3722
0
Некорректный скрипт для закрытия блока
14th April, 18:33
4614
0
прокидывать exception в блоках try-catch JAVA
11th March, 21:11
4382
0
Помогите пожалуйста решить задачи
24th November, 23:53
6087
0
Не понимаю почему не открывается детальное описание продукта
11th November, 11:51
4352
0
Нужно решить задачу по программированию на массивы
27th October, 18:01
4398
0
Метода Крамера С++
23rd October, 11:55
4309
0
помогите решить задачу на C++
22nd October, 17:31
4002
0
Помогите решить задачу на python с codeforces
22nd October, 11:11
4492
0
Python с нуля: полное руководство для начинающих
18th June, 13:58
2599
0
Завсегдатаев и метод static_cast и динамическое приведение dynamic_cast
Я пишу код C и C++ уже почти двадцать лет, но есть один аспект этих языков, который я никогда по-настоящему не понимал. Я, очевидно, использовал обычные слепки.
MyClass *m = (MyClass *)ptr;
повсюду, но, кажется, есть еще два типа слепков, и я не знаю разницы. В чем разница между следующими строками кода?
MyClass *m = (MyClass *)ptr;
MyClass *m = static_cast<MyClass *>(ptr);
MyClass *m = dynamic_cast<MyClass *>(ptr);
метод static_cast
static_cast используется для случаев, когда вы в основном хотите отменить неявное преобразование, с несколькими ограничениями и дополнениями. static_cast не выполняет никаких проверок во время выполнения. Это следует использовать, если вы знаете, что ссылаетесь на объект определенного типа, и поэтому проверка будет ненужной. Пример:
void func(void *data) {
// Conversion from MyClass* -> void* is implicit
MyClass *c = static_cast<MyClass*>(data);
...
}
int main() {
MyClass c;
start_thread(&func, &c) // func(&c) will be called
.join();
}
В этом примере вы знаете, что передали объект MyClass , и поэтому нет никакой необходимости в проверке во время выполнения, чтобы убедиться в этом.
динамическое приведение dynamic_cast
dynamic_cast полезно, когда вы не знаете, что такое динамический тип объекта. Он возвращает указатель null, если объект, на который ссылаются, не содержит тип, приведенный к базовому классу (при приведении к ссылке в этом случае создается исключение bad_cast ).
if (JumpStm *j = dynamic_cast<JumpStm*>(&stm)) {
...
} else if (ExprStm *e = dynamic_cast<ExprStm*>(&stm)) {
...
}
Вы не можете использовать dynamic_cast , если вы понижаете (приведение к производному классу) и тип аргумента не является полиморфным. Например, следующий код недопустим, так как Base не содержит никакой виртуальной функции:
struct Base { };
struct Derived : Base { };
int main() {
Derived d; Base *b = &d;
dynamic_cast<Derived*>(b); // Invalid
}
"up-cast" (приведение к базовому классу) всегда допустимо как с static_cast , так и с dynamic_cast, а также без приведения, так как "up-cast" является неявным преобразованием.
Регулярный Бросок
Эти приведения также называются приведением в стиле C. Приведение в стиле C в основном идентично опробованию ряда последовательностей приведений C++ и взятию первого приведения C++, которое работает, даже не рассматривая dynamic_cast . Излишне говорить , что это намного мощнее , поскольку он сочетает в себе все const_cast, static_cast и reinterpret_cast, но это также небезопасно, потому что он не использует dynamic_cast .
Кроме того, приведения в стиле C не только позволяют сделать это, но и позволяют безопасно привести к закрытому базовому классу, в то время как последовательность "equivalent" static_cast даст вам ошибку времени компиляции для этого.
Некоторые люди предпочитают слепки в стиле C из-за их краткости. Я использую их только для числовых приведений и использую соответствующие приведения C++, когда используются пользовательские типы, поскольку они обеспечивают более строгую проверку.
Статическое приведение
Статическое приведение выполняет преобразования между совместимыми типами. Он похож на приведение в стиле C, но более ограничен. Например, приведение в стиле C позволит целочисленному указателю указывать на символ char.
char c = 10; // 1 byte
int *p = (int*)&c; // 4 bytes
Поскольку это приводит к 4-байтному указателю, указывающему на 1 байт выделенной памяти, запись в этот указатель либо вызовет ошибку во время выполнения, либо перезапишет некоторую соседнюю память.
*p = 5; // run-time error: stack corruption
В отличие от приведения в стиле C, статическое приведение позволит компилятору проверить совместимость типов данных pointer и pointee, что позволит программисту перехватить это неверное назначение указателя во время компиляции.
int *q = static_cast<int*>(&c); // compile-time error
Переинтерпретация литого
Для принудительного преобразования указателя, так же как и приведение в стиле C в фоновом режиме, вместо этого будет использоваться приведение reinterpret.
int *r = reinterpret_cast<int*>(&c); // forced conversion
Это приведение обрабатывает преобразования между определенными несвязанными типами, например из одного типа указателя в другой несовместимый тип указателя. Он будет просто выполнять двоичную копию данных без изменения базового битового шаблона. Обратите внимание, что результат такой низкоуровневой операции зависит от конкретной системы и поэтому не является переносимым. Его следует использовать с осторожностью, если его нельзя полностью избежать.
Динамическое приведение
Этот метод используется только для преобразования указателей объектов и ссылок на объекты в другие типы указателей или ссылок в иерархии наследования. Это единственное приведение, которое гарантирует, что объект, на который указывает указатель, может быть преобразован, выполнив проверку во время выполнения, что указатель ссылается на полный объект целевого типа. Чтобы эта проверка во время выполнения была возможной, объект должен быть полиморфным. То есть класс должен определить или наследовать хотя бы одну виртуальную функцию. Это происходит потому, что компилятор будет генерировать только необходимую информацию о типе времени выполнения Для таких объектов.
Примеры динамического приведения
В приведенном ниже примере указатель MyChild преобразуется в указатель MyBase с помощью динамического приведения. Это преобразование derived-to-base выполняется успешно, поскольку дочерний объект включает полный базовый объект.
class MyBase
{
public:
virtual void test() {}
};
class MyChild : public MyBase {};
int main()
{
MyChild *child = new MyChild();
MyBase *base = dynamic_cast<MyBase*>(child); // ok
}
В следующем примере предпринимается попытка преобразовать указатель MyBase в указатель MyChild. Поскольку базовый объект не содержит полного дочернего объекта, это преобразование указателя завершится ошибкой. Чтобы указать на это, динамическое приведение возвращает указатель null. Это дает удобный способ проверить, успешно ли выполнено преобразование во время выполнения.
MyBase *base = new MyBase();
MyChild *child = dynamic_cast<MyChild*>(base);
if (child == 0)
std::cout << "Null pointer returned";
Если ссылка преобразуется вместо указателя, то динамическое приведение завершится ошибкой, вызвав исключение bad_cast. Это должно быть обработано с помощью оператора try-catch.
#include <exception>
// …
try
{
MyChild &child = dynamic_cast<MyChild&>(*base);
}
catch(std::bad_cast &e)
{
std::cout << e.what(); // bad dynamic_cast
}
Динамический или статический бросок
Преимущество использования динамического приведения заключается в том, что оно позволяет программисту проверить, удалось ли преобразование во время выполнения. Недостатком является то, что существует высокая производительность, связанная с выполнением этой проверки. По этой причине использование статического приведения было бы предпочтительнее в первом примере, поскольку преобразование derived-to-base никогда не завершится неудачей.
MyBase *base = static_cast<MyBase*>(child); // ok
Однако во втором примере преобразование может быть либо успешным, либо неудачным. Он завершится неудачей, если объект MyBase содержит экземпляр MyBase, и завершится успешно, если он содержит экземпляр MyChild. В некоторых ситуациях это может быть известно только во время выполнения. В этом случае динамическое приведение является лучшим выбором, чем статическое приведение.
// Succeeds for a MyChild object
MyChild *child = dynamic_cast<MyChild*>(base);
Если бы преобразование base-to-derived было выполнено с использованием статического приведения, а не динамического приведения, преобразование не было бы неудачным. Он бы вернул указатель, который ссылается на неполный объект. Разыменование такого указателя может привести к ошибкам во время выполнения.
// Allowed, but invalid
MyChild *child = static_cast<MyChild*>(base);
// Incomplete MyChild object dereferenced
(*child);
Константный литой
Этот параметр в основном используется для добавления или удаления модификатора const переменной.
const int myConst = 5;
int *nonConst = const_cast<int*>(&myConst); // removes const
Хотя приведение const позволяет изменять значение константы, это все равно недопустимый код, который может вызвать ошибку во время выполнения. Это может произойти, например, если константа находится в секции памяти только для чтения.
*nonConst = 10; // potential run-time error
Вместо этого const cast используется в основном тогда, когда есть функция, которая принимает непостоянный аргумент указателя, даже если он не изменяет объект pointee.
void print(int *p)
{
std::cout << *p;
}
Затем функции можно передать постоянную переменную с помощью приведения const.
print(&myConst); // error: cannot convert
// const int* to int*
print(nonConst); // allowed
Источник и дополнительные пояснения
Вы должны посмотреть статью C++ Программирование / приведение типов .
Он содержит хорошее описание всех различных типов приведения. Следующее взято из приведенной выше ссылки:
const_cast
const_cast (выражение) const_cast<>() используется для добавления / удаления const (ness) (или volatile-Ness) переменной.
метод static_cast
static_cast (выражение) static_cast<>() используется для приведения между целочисленный тип. 'e.g.' Чара->длинный, инт-короче и т. д.
Статическое приведение также используется для приведения указателей на связанные типы, например пример приведения void* к соответствующему типу.
динамическое приведение dynamic_cast
Динамическое приведение используется для преобразования указателей и ссылок во время выполнения, обычно для приведения указателя или ссылки вверх или вниз цепочка наследования (иерархия наследования).
динамическое приведение dynamic_cast(выражение)
Целевым типом должен быть указатель или ссылочный тип, а также выражение должно вычисляться по указателю или ссылке. Динамическое приведение работ только если тип объекта, на который ссылается выражение, является совместимость с целевым типом и базовым классом имеет по крайней мере один виртуальная функция-член. Если нет, то и тип приведенного выражения является указателем, NULL возвращается, если динамическое приведение по ссылке не удается, создается исключение bad_cast. Когда он не терпит неудачу, динамичный литые возвращает указатель или ссылку на тип целевого объекта к какому выражению относится.
оператора reinterpret_cast
Переинтерпретировать приведение просто приводит один тип побитово к другому. Любой указатель или интегральный тип можно привести к любому другому с переинтерпретацией приведения, легко допускающий неправильное использование. Например, с переинтерпретацией одного из них может быть, небезопасно, привести целочисленный указатель к строковому указателю.
К вашему сведению, я считаю, что Бьярне Строструп цитируется как говорящий, что приведений в стиле C следует избегать и что вы должны использовать static_cast или dynamic_cast, если это вообще возможно.
Стиль Барна Строструпа C++ FAQ
Примите этот совет, как вам будет угодно. Я далек от того, чтобы быть гуру C++.
Приведения в стиле C объединяют const_cast, static_cast и reinterpret_cast.
Я бы хотел, чтобы C++ не было приведений в стиле C. C++ приведения выделяются должным образом (как и должно быть; приведения обычно указывают на то, что они делают что-то плохое) и правильно различают различные виды преобразования, которые выполняют приведения. Они также позволяют писать похожие функции, например boost::lexical_cast, что довольно приятно с точки зрения согласованности.
dynamic_cast имеет проверку типов среды выполнения и работает только со ссылками и указателями, в то время как static_cast не предлагает проверку типов среды выполнения. Для получения полной информации см. статью MSDN static_cast Operator .
dynamic_cast поддерживает только типы указателей и ссылок. Он возвращает NULL , если приведение невозможно, если тип является указателем, или создает исключение, если тип является ссылочным типом. Следовательно, dynamic_cast можно использовать для проверки, является ли объект заданным типом, static_cast -нет (вы просто получите недопустимое значение).
C-стиль (и другие) приведения были рассмотрены в других ответах.