Как поменять тип переменной в c
Перейти к содержимому

Как поменять тип переменной в c

  • автор:

Руководство по программированию на C#. Приведение и преобразование типов

Поскольку код C# является статически типизированным во время компиляции, после объявления переменной ее нельзя объявить повторно или назначить ей значения другого типа, если этот тип невозможно неявно преобразовать в тип переменной. Например, string невозможно неявно преобразовать в int . Поэтому после объявления i как int нельзя назначить ей строку «Hello», как показано в следующем коде:

int i; // error CS0029: Cannot implicitly convert type 'string' to 'int' i = "Hello"; 

Тем не менее иногда может потребоваться скопировать значение в переменную или параметр метода другого типа. Например, может потребоваться передать целочисленную переменную в метод, параметр которого имеет тип double . Или может понадобиться присвоить переменную класса переменной типа интерфейса. Такого рода операции называются преобразованиями типа. В C# можно выполнять следующие виды преобразований.

  • Неявные преобразования. Специальный синтаксис не требуется, так как преобразование всегда завершается успешно и данные не будут потеряны. Примеры включают преобразования из меньших в большие целочисленные типы и преобразования из производных классов в базовые классы.
  • Явные преобразования (приведения) . Для явных преобразований требуется выражение приведения. Приведение требуется, если в ходе преобразования данные могут быть утрачены или преобразование может завершиться сбоем по другим причинам. Типичными примерами являются числовое преобразование в тип с меньшей точностью или меньшим диапазоном и преобразование экземпляра базового класса в производный класс.
  • Пользовательские преобразования. Такие преобразования выполняются специальными методами, которые можно определить для включения явных и неявных преобразований между пользовательскими типами без связи «базовый класс — производный класс». Дополнительные сведения см. в разделе Операторы пользовательского преобразования.
  • Преобразования с использованием вспомогательных классов. Чтобы выполнить преобразование между несовместимыми типами, например целыми числами и объектами System.DateTime или шестнадцатеричными строками и массивами байтов, можно использовать классы System.BitConverter и System.Convert, а также методы Parse встроенных числовых типов, такие как Int32.Parse. Дополнительные сведения см. в руководствах по преобразованию массива байтов в значение типа int, преобразованию строки в число и преобразованию из шестнадцатеричных строк в числовые типы.

Неявные преобразования

Для встроенных числовых типов неявное преобразование можно выполнить, если сохраняемое значение может уместиться в переменной без усечения или округления. При использовании целочисленных типов это означает, что диапазон исходного типа является надлежащим подмножеством диапазона для целевого типа. Например, переменная типа long (64-разрядное целое число) может хранить любое значение, которое может хранить переменная int (32-разрядное целое число). В следующем примере компилятор неявно преобразует значение num справа в тип long перед назначением bigNum .

// Implicit conversion. A long can // hold any value an int can hold, and more! int num = 2147483647; long bigNum = num; 

Полный список всех неявных числовых преобразований см. в разделе Таблица неявных числовых преобразований в статье Встроенные числовые преобразования.

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

Derived d = new Derived(); // Always OK. Base b = d; 

Явные преобразования

Тем не менее если преобразование нельзя выполнить без риска потери данных, компилятор требует выполнения явного преобразования, которое называется приведением. Приведение — это способ явно указать компилятору, что необходимо выполнить преобразование и что вам известно, что может произойти потеря данных или приведение может завершиться сбоем во время выполнения. Чтобы выполнить приведение, укажите тип, в который производится приведение, в круглых скобках перед преобразуемым значением или переменной. В следующей программе выполняется приведение типа double в int. Программа не будет компилироваться без приведения.

class Test < static void Main() < double x = 1234.7; int a; // Cast double to int. a = (int)x; System.Console.WriteLine(a); >> // Output: 1234 

Полный список всех поддерживаемых явных числовых преобразований см. в разделе Таблица явных числовых преобразований в статье Встроенные числовые преобразования.

Для ссылочных типов явное приведение является обязательным, если необходимо преобразовать базовый тип в производный тип:

// Create a new derived type. Giraffe g = new Giraffe(); // Implicit conversion to base type is safe. Animal a = g; // Explicit conversion is required to cast back // to derived type. Note: This will compile but will // throw an exception at run time if the right-side // object is not in fact a Giraffe. Giraffe g2 = (Giraffe)a; 

Операция приведения между ссылочными типами не меняет тип времени выполнения базового объекта; изменяется только тип значения, который используется в качестве ссылки на этот объект. Дополнительные сведения см. в разделе Полиморфизм.

Исключения преобразования типов во время выполнения

В некоторых преобразованиях ссылочных типов компилятор не может определить, будет ли приведение допустимым. Есть вероятность, что правильно скомпилированная операция приведения завершится сбоем во время выполнения. Как показано в следующем примере, приведение типа, завершившееся сбоем во время выполнения, вызывает исключение InvalidCastException.

class Animal < public void Eat() =>System.Console.WriteLine("Eating."); public override string ToString() => "I am an animal."; > class Reptile : Animal < >class Mammal : Animal < >class UnSafeCast < static void Main() < Test(new Mammal()); // Keep the console window open in debug mode. System.Console.WriteLine("Press any key to exit."); System.Console.ReadKey(); >static void Test(Animal a) < // System.InvalidCastException at run time // Unable to cast object of type 'Mammal' to type 'Reptile' Reptile r = (Reptile)a; >> 

Метод Test имеет параметр Animal , поэтому явное приведение a аргумента к Reptile формирует опасное допущение. Более безопасно будет не делать допущений, а проверить тип. C# предоставляет оператор is, чтобы можно было проверить совместимость перед фактическим выполнением приведения. Дополнительные сведения см. в статье Практическое руководство. Безопасное приведение с помощью сопоставления шаблонов, а также операторов is и as.

Спецификация языка C#

См. также

  • Руководство по программированию на C#
  • Типы
  • Выражение приведения
  • Операторы пользовательского преобразования
  • Обобщенное преобразование типов
  • Практическое руководство. Преобразование строки в число

Совместная работа с нами на GitHub

Источник этого содержимого можно найти на GitHub, где также можно создавать и просматривать проблемы и запросы на вытягивание. Дополнительные сведения см. в нашем руководстве для участников.

Преобразования типов и безопасность типов

Этот документ определяет распространенные проблемы преобразования типов и описывает, как их можно избежать в коде C++.

При написании программы C++ важно убедиться, что она является типобезопасной. Это означает, что каждое значение переменной, аргумента функции и возвращаемого функции сохраняет приемлемый тип данных, и что операции, включающие значения различных типов», «имеют смысл» и не вызывают потери данных, неправильной интерпретации битовых шаблонов или повреждения памяти. Программа, которая никогда явно или неявно преобразовывает значения из одного типа в другой является типобезопасной по определению. Однако иногда требуются преобразования типов, даже небезопасные преобразования. Например, может потребоваться сохранить результат операции с плавающей запятой в переменной типа int или передать значение в unsigned int функцию, которая принимает значение signed int . Оба примера иллюстрируют небезопасные преобразования, так как они могут привести к потере данных или повторной интерпретации значения.

Когда компилятор обнаруживает небезопасное преобразование, он выдает ошибку или предупреждение. Ошибка останавливает компиляцию; Предупреждение позволяет продолжить компиляцию, но указывает на возможную ошибку в коде. Однако даже если программа компилируется без предупреждений, она по-прежнему может содержать код, который приводит к неявным преобразованиям типов, которые создают неправильные результаты. Ошибки типа также могут быть представлены явными преобразованиями или приведениями в коде.

Неявные преобразования типов

Если выражение содержит операнды различных встроенных типов и нет явных приведения, компилятор использует встроенные стандартные преобразования для преобразования одного из операндов таким образом, чтобы типы соответствовали. Компилятор пытается выполнить преобразования в четко определенной последовательности, пока не завершится успешно. Если выбранное преобразование является повышением, компилятор не выдает предупреждения. Если преобразование является сужающим, компилятор выдает предупреждение о возможной потере данных. Указывает, происходит ли фактическая потеря данных, зависит от фактических значений, но рекомендуется рассматривать это предупреждение как ошибку. Если используется определяемый пользователем тип, компилятор пытается использовать преобразования, указанные в определении класса. Если не удается найти допустимое преобразование, компилятор выдает ошибку и не компилирует программу. Дополнительные сведения о правилах, которые управляют стандартными преобразованиями, см. в разделе «Стандартные преобразования». Дополнительные сведения о пользовательских преобразованиях см. в разделе «Определяемые пользователем преобразования» (C++/CLI).

Расширение преобразований (повышение уровня)

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

С дт. Кому
Любой signed или unsigned целочисленный тип, кроме long long или __int64 double
bool или char Любой другой встроенный тип
short или wchar_t int , long , long long
int , long long long
float double

Сужение преобразований (приведение)

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

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

В следующем примере кода показаны некоторые неявные сужающие преобразования и предупреждения о проблемах компилятора.

int i = INT_MAX + 1; //warning C4307:'+':integral constant overflow wchar_t wch = 'A'; //OK char c = wch; // warning C4244:'initializing':conversion from 'wchar_t' // to 'char', possible loss of data unsigned char c2 = 0xfffe; //warning C4305:'initializing':truncation from // 'int' to 'unsigned char' int j = 1.9f; // warning C4244:'initializing':conversion from 'float' to // 'int', possible loss of data int k = 7.7; // warning C4244:'initializing':conversion from 'double' to // 'int', possible loss of data 

Подписанные — незаписанные преобразования

Подписанный целочисленный тип и его неподписанный аналог всегда одинаковый, но они отличаются в том, как битовый шаблон интерпретируется для преобразования значений. В следующем примере кода показано, что происходит, когда тот же битовый шаблон интерпретируется как подписанное значение и как неподписаемое значение. Битовый шаблон, хранящийся в обоих num и num2 никогда не изменяется от того, что показано на предыдущем рисунке.

using namespace std; unsigned short num = numeric_limits::max(); // #include short num2 = num; cout  

Обратите внимание, что значения переосмыслены в обоих направлениях. Если программа создает нечетные результаты, в которых знак значения по-видимому, повернут из ожидаемого значения, найдите неявные преобразования между подписанными и неподписанными целочисленными типами. В следующем примере результат выражения (0 – 1) неявно преобразуется из int unsigned int того, когда он хранится. num Это приводит к повторному интерпретации битового шаблона.

unsigned int u3 = 0 - 1; cout  

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

Преобразования указателей

Во многих выражениях массив стилей C неявно преобразуется в указатель на первый элемент в массиве, а преобразования констант могут выполняться автоматически. Хотя это удобно, это также потенциально подвержено ошибкам. Например, следующий плохо разработанный пример кода кажется нечувствичным, но он компилирует и создает результат p. Во-первых, константный литерал строки help преобразуется char* в тот, который указывает на первый элемент массива. Затем указатель увеличивается тремя элементами, чтобы он указывал на последний элемент p.

char* s = "Help" + 3; 

Явные преобразования (приведение)

С помощью операции приведения можно указать компилятору преобразовать значение одного типа в другой тип. Компилятор вызовет ошибку в некоторых случаях, если два типа полностью не связаны, но в других случаях это не приведет к возникновению ошибки, даже если операция не является типобезопасной. Используйте приведение с разреженным способом, так как любое преобразование из одного типа в другой является потенциальным источником ошибки программы. Однако литья иногда требуются, и не все литые одинаково опасны. Одно эффективное использование приведения заключается в том, что код выполняет сужение преобразования, и вы знаете, что преобразование не приводит к неправильному результату программы. В действительности это сообщает компилятору, что вы знаете, что вы делаете, и прекратить беспокоить вас с предупреждениями об этом. Другим способом является приведение от класса указателя на производный от указателя к базовому классу. Другое использование заключается в том, чтобы отбросить константу переменной, чтобы передать ее в функцию, требующую аргумента, отличного от константа. Большинство этих операций приведения включают некоторый риск.

В программировании в стиле C один и тот же оператор приведения в стиле C используется для всех видов приведения.

(int) x; // old-style cast, old-style syntax int(x); // old-style cast, functional syntax 

Оператор приведения в стиле C идентичен оператору вызова () и поэтому неудобен в коде и легко упускать из виду. Оба плохо, потому что они трудно распознать на первый взгляд или найти, и они достаточно разрозненные, чтобы вызвать любое сочетание static , const и reinterpret_cast . Определение того, что на самом деле делает старый стиль, может быть трудным и подверженным ошибкам. По всем этим причинам, если требуется приведение, рекомендуется использовать один из следующих операторов приведения C++, которые в некоторых случаях значительно более типобезопасны, и которые выражают гораздо более явно намерение программирования:

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

double d = 1.58947; int i = d; // warning C4244 possible loss of data int j = static_cast(d); // No warning. string s = static_cast(d); // Error C2440:cannot convert from // double to std:string // No error but not necessarily safe. Base* b = new Base(); Derived* d2 = static_cast(b); 
Base* b = new Base(); // Run-time check to determine whether b is actually a Derived* Derived* d3 = dynamic_cast(b); // If b was originally a Derived*, then d3 is a valid pointer. if(d3) < // Safe to call Derived method. cout DoSomethingMore() else < // Run-time check failed. cout << "d3 is null" //Output: d3 is null; 
void Func(double& d) < . >void ConstCast() < const double pi = 3.14; Func(const_cast(pi)); //No error. > 

Примечание. Этот оператор приведения не используется так часто, как и другие, и он не гарантируется переносимым к другим компиляторам.

В следующем примере показано, как reinterpret_cast отличается от static_cast .

const char* str = "hello"; int i = static_cast(str);//error C2440: 'static_cast' : cannot // convert from 'const char *' to 'int' int j = (int)str; // C-style cast. Did the programmer really intend // to do this? int k = reinterpret_cast(str);// Programming intent is clear. // However, it is not 64-bit safe. 

Преобразование типов в стиле С

Когда, мы что-либо делаем, нам, несомненно, важно знать каков будет результат. Вполне очевидно, что из тех ингредиентов из которых, скажем вариться суп харчо, вряд ли можно приготовить торт со взбитыми сливками. Следовательно, результат напрямую зависит, от составных частей. То же самое происходит с переменными. Если, скажем, складывается два числа типа int, вполне понятно, что результат так же будет иметь тип int. А вот как быть, если данные имеют разные типы? Именно об этом мы и поговорим в текущем разделе данного урока.

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

bool,char,short-int-unsigned int-long-unsigned long-float-double-long double

Несмотря на то, что некоторые типы имеют одинаковый размер, в них помещается разный диапазон значений, например, unsigned int в отличие от int может поместить в себя в два раза больше положительных значений, и потому является старше по иерархии, при этом оба типа имеют размер 4 байта. Кроме того, следует отметить, очень важную особенность, отраженную здесь, если в преобразовании типов участвуют такие типы, как bool,char,short, они автоматически преобразовываются к типу int.

Теперь, давайте рассмотрим, различные классификации преобразований.

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

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

int A=23.5; cout

Как видите, такое преобразование от double к int, ведет к грубому обрезанию вещественного числа, без математического округления, результатом которого являлось бы число 24.

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

unsigned int a=3000000000; cout

В данном случае 3000000000 - это литерал типа int, который благопоучно расширяется до unsigned int, что и позволяет нам увидеть на экране именно 3000000000, а не что-то другое. Тогда, как в обычный int такое число не поместиться.

Классификация по способу осуществления преобразования

Вне зависимости от направления преобразования, оно может быть осуществлено одним из двух способов.

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

float A=23,5; - double стал float без каких-либо дополнительных действий

Явное преобразование. (второе название – приведение типов). В данном случае, преобразование производится программистом, тогда, когда это необходимо. Давайте рассмотрим простой пример такого действия:

double z=37.4; float y=(int) z; cout<

(int)z – есть явное сужающее преобразование от типа double к типу int. В этой же строке происходит расширяющее неявное преобразование от полученного типа int к типу float. Следует запомнить, что любое преобразование носит временный характер и действует только в пределах текущей строки. То есть переменная z как была double, так и останется на протяжении всей программы, а ее преобразование в int носило временный характер.

Преобразование типов в выражении

И, вот, мы наконец-то подошли к тому, о чем говорили в самом начале данного раздела урока, как выяснить какого типа будет результат какого-то выражения. Давайте попробуем это вычислить, пользуясь полученными знаниями. Предположим у нас есть следующие переменные:

int I=27; short S=2; float F=22.3; bool B=false;

Пользуясь этими переменными, мы собираемся составить такое выражение:

I-F+S*B

В переменную какого типа данных нам следует записать результат? Решить это просто, если представить выражение в виде типов данных:

int-float+short*bool

Напоминаем, что short и bool сразу же примут тип int, так что выражение будет выглядеть так:

int-float+int*int, при этом false станет 0

Умножение int на int даст, несомненно, результат типа int. А вот сложение float с int, даст на выходе float, так как, здесь вступает в игру новое правило: Если в каком-либо выражении используются разные типы данных, то результат, приводится к большему из этих типов. Ну и, наконец – вычитание из int типа float, согласно только что упомянутому правилу снова даст float. Таким образом, результат выражения будет иметь тип float.

float res= I-F+S*B; // 27-22.3+2*0 cout

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

Примечание: Будьте очень внимательны также и при сочетании переменных с одинаковыми типами данных. Например, помните, если целое делится на целое, то и получиться целое. То есть, int A=3; int B=2; cout«A/B; на экране 1, так как результат - int и дробная часть утеряна. cout«(float)A/B; на экране 1.5, так как результат - float.

Пример, использующий преобразование типов

Теперь давайте закрепим знания на практике. Создадим проект и напишем нижеследующий код.

# include using namespace std; void main()< // объявление переменных и запрос на ввод данных float digit; cout>digit; /* Даже, если пользователь ввел число с вещественной частью, результат выражения запишется в int и вещественная часть будет утеряна, разделив число на 100 мы получим количество сотен в нем. */ int res=digit/100; cout

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

Преобразование типов в стиле С++

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

(тип) выражение Например, double d; d=(double) 10/3;

Операторы приведения типа в языке С++

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

const_cast <тип>(объект)
dynamic_cast <тип>(объект) проверяет законность выполнения заданной операции приведения типа

reinterpret_cast<тип>(объект) следует использовать для перевода типов указателей, которые несовместимы по своей природе

static_cast <тип>(объект) Фактически, static_cast - это аналог стандартной операции преобразования в стиле С.

const_cast используется для явного переопределения модификаторов const и/или volatile. Новый тип должен совпадать с исходным типом, за исключением изменения его атрибутов const или volatile. Чаще всего оператор const_cast используется для снятия атрибута const. Например:

Следует помнить, что только оператор const_cast может освободить от "обета постоянства", т.е. ни один из остальных операторов этой группы не может "снять" с объекта атрибут const.

#include using namespace std; // указатель на объект является константным, // следовательно, через него изменить значение // объекта нельзя void test_pow(const int* v)< int*temp; // снимаем модификатор const // и теперь можем изменять объект temp=const_cast(v); // изменение объекта *temp= *v * *v; > void main()< int x=10; // на экране - 10 cout<<"Before - "<Примечание: Кстати, стоит упомянуть о том, что такое volatile. Данный модификатор даёт компилятору понять, что значение переменной, может быть изменено неявным образом. Например, есть некая глобальная переменная, её адрес передаётся встроенному таймеру операционной системы. В дальнейшем эта конструкция может использоваться для отсчёта реального времени. Естественно, что значение этой переменной изменяется автоматически без участия операторов присваивания. Так вот такая переменная должна быть объявлена с использованием ключевого слова volatile. Это связано с тем, что многие компиляторы не обнаружив ни одного изменения переменной с помощью какого-либо присваивания, считают, что она не изменяется и оптимизируют выражения с ней, подставляя на её место конкретное значение. При этом компилятор переменную не перепроверяет. Действительно, зачем, если переменная для него имеет характер "неизменяемой"?! volatile - будет блокировать подобные действия компиляторов.

dynamic_cast проверяет законность выполнения заданной операции приведения типа. Если такую операцию выполнить нельзя, то выражение устанавливается равным нулю. Этот оператор в основном используется для полиморфных типов. Например, если даны два полиморфных класса, B и D, причем класс D выведен из класса B, то оператор dynamic_cast всегда может преобразовать указатель D* в указатель B*. Оператор dynamic_cast может преобразовать указатель B* в указатель D* только в том случае, если адресуемым объектом является объект D. И вообще, оператор dynamic_cast будет успешно выполнен только при условии, что разрешено полиморфное приведение типов (т.е. если новый тип можно законно применять к типу объекта, который подвергается этой операции). Рассмотрим пример, демонстрирующий всё вышесказанное:

#include using namespace std; // базовый класс class B < public: // виртуальная функция для // последующего переопределения в потомке virtual void Test()< cout>; // класс-потомок class D:public B < public: // переопределение виртуальной функции void Test()< cout>; void main() < // указатель на класс-родитель // и объект класса-родителя B *ptr_b, obj_b; // указатель на класс-потомок // и объект класса-потомка D *ptr_d, obj_d; // приводим адрес объекта (D*) к указателю типа D* ptr_d= dynamic_cast(&obj_d); // если все прошло успешно - вернулся !0 // произошло приведение if(ptr_d)< coutTest(); > // если произошла ошибка - вернулся 0 else cout (&obj_d); // если все прошло успешно - вернулся !0 // произошло приведение if(ptr_b)< coutTest(); > // если произошла ошибка - вернулся 0 else cout(&obj_b); // если все прошло успешно - вернулся !0 // произошло приведение if(ptr_b)< coutTest(); > // если произошла ошибка - вернулся 0 else cout <<"Error work. \n\n"; // ВНИМАНИЕ. ЭТО НЕВОЗМОЖНО // попытка привести адрес объекта (B*) к указателю типа D* ptr_d= dynamic_cast(&obj_b); // если все прошло успешно - вернулся !0 // произошло приведение if(ptr_d) cout Результат работы программы: Good work - Test D Good work - Test D Good work - Test B Error work.

static_cast выполняет неполиморфное приведение типов. Его можно использовать для любого стандартного преобразования. При этом никакие проверки во время работы программы не выполняются. Фактически, static_cast - это аналог стандартной операции преобразования в стиле С. Например, так:

#include using namespace std; void main()< int i; for(i=0;i<10;i++) // приведение переменной i к типу double // результаты деления на экране, естественно // вещественные cout<(i)/3

reinterpret_cast переводит один тип в совершенно другой. Например, его можно использовать для перевода указателя в целый тип и наоборот. Оператор reinterpret_cast следует использовать для перевода типов указателей, которые несовместимы по своей природе. Рассмотрим пример:

#include using namespace std; void main()< // целочисленная переменная int x; // строка (указатель типа char) char*str="This is string. "; // демонстрируем строку на экран cout(str); // демонстрируем результат cout

RTTI

В C++ для динамической идентификации типов применяются операторы dynamic_cast и typeid (определён в файле typeinfo.h), для использования которых информацию о типах во время выполнения обычно необходимо добавить через опции компилятора при компиляции модуля.

Оператор dynamic_cast пытается выполнить приведение к указанному типу с проверкой. Целевой тип операции должен быть типом указателя, ссылки или void*.

Оператор typeid возвращает ссылку на структуру type_info, которая содержит поля, позволяющие получить информацию о типе.

Как поменять тип переменной в c

Преобразование типов данных, это приведение одного типа к другому. Например, приведение целочисленной переменной к числу с плавающей точной, или преобразование числа в строку. В C# выделяют два варианта преобразования типов:

  • Неявное преобразование типов. Это, так называемое безопасное преобразование типов в C#. Например, преобразование из типа float (более «маленький» тип) в тип double (более «большой» тип). При таком преобразовании никакая информация не «потеряется», что при обратном преобразовании вполне возможно.
  • Явное преобразование типов. Такое преобразование выполняется программистом с прямым указанием типа, к которому нужно привести переменную. Для такого преобразования требуется наличие оператора преобразования.

А теперь, я покажу как можно использовать явное преобразование типов в C#:

using System; namespace TypesConvertion < class Program < static void Main(string[] args) < //Число с плавающей точкой double doubleData = 245.45; //Вывод этого числа Console.WriteLine(doubleData); //А теперь, мы сделаем на основе этого числа, цело число int intData = (int)doubleData; //Вывод целого числа Console.WriteLine(intData); //Чтобы окно не закрылось раньше времени Console.ReadKey(); >> >

Преобразование типа double в тип int выполнялось в выделенной строке (строке с номером 16). Если вы соберете данный пример и запустите его, то увидите, что преобразование типов прошло, т.е. из числа с плавающей точкой мы получили целое число.

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

Название метода Целевой тип
ToBoolean bool
ToByte byte
ToChar char
ToDouble double
ToSingle float
ToInt32 int
ToInt64 long
ToString string

А теперь, пример использования класса Convert и его методов:

using System; namespace TypesConvertion < class Program < static void Main(string[] args) < //Число с плавающей точкой double doubleData = 245.45; //Вывод этого числа Console.WriteLine(doubleData); //А теперь, мы сделаем на основе этого числа, цело число int intData = Convert.ToInt32(doubleData); //Вывод целого числа Console.WriteLine(intData); //Чтобы окно не закрылось раньше времени Console.ReadKey(); >> >

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

И обратите внимание на еще одни момент, если один тип нельзя преобразовать в другой, а вы это попытаетесь сделать, то получите ошибку в программе!

Пользоваться возможность преобразования типов вам придется довольно часто!

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *