Страница 1 из 1

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

Добавлено: 10 июн 2024, 16:03
ya

Код: Выделить всё

 for (int i = Xdata.size() - 1; i >= int(Xdata.size())-B; --i){
         // loop body
    }
Чтобы выполнить итерацию по последним N элементам в обратном порядке, используя циклы с индексированным значением for в старом стиле

Код: Выделить всё

for (size_t i = xs.size(), n = 0;   (i-- > 0) and (n < N);   ++n)
    std::cout << xs[i] << "\n";
если бы я просто явно преобразовал в int раньше

Код: Выделить всё

int size = Xdata.size();
for (int i =size - 1; i >= size-B; --i){
         // loop body
    }

Re: неявным преобразованием типа

Добавлено: 10 июн 2024, 18:15
ya
Преобразования типов
https://cplusplus.com/doc/tutorial/typecasting/

dynamic_cast <new_type> (expression)
reinterpret_cast <new_type> (expression)
static_cast <new_type> (expression)
const_cast <new_type> (expression)

dynamic_cast динамическое преобразование типов

Код: Выделить всё

// dynamic_cast
#include <iostream>
#include <exception>
using namespace std;

class Base { virtual void dummy() {} };
class Derived: public Base { int a; };

int main () {
  try {
    Base * pba = new Derived;
    Base * pbb = new Base;
    Derived * pd;

    pd = dynamic_cast<Derived*>(pba);
    if (pd==0) cout << "Null pointer on first type-cast.\n";

    pd = dynamic_cast<Derived*>(pbb);
    if (pd==0) cout << "Null pointer on second type-cast.\n";

  } catch (exception& e) {cout << "Exception: " << e.what();}
  return 0;
}
Приведенный выше код пытается выполнить два динамических приведения объектов-указателей типа Base* (pba и pbb) к объекту-указателю типа Derived*, но только первое из них является успешным. Обратите внимание на их соответствующие инициализации:

Код: Выделить всё

Base * pba = new Derived;
Base * pbb = new Base;
Когда dynamic_cast не удается привести указатель, потому что это неполный объект требуемого класса - как во втором преобразовании в предыдущем примере - он возвращает нулевой указатель, указывающий на сбой. Если dynamic_cast используется для преобразования в ссылочный тип, а преобразование невозможно, вместо этого выдается исключение типа bad_cast.

dynamic_cast может также выполнять другие неявные приведения, разрешенные для указателей: приведение нулевых указателей между типами указателей (даже между несвязанными классами) и приведение любого указателя любого типа к void* указателю.

static_cast ( статическая передача)

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

Код: Выделить всё

class Base {};
class Derived: public Base {};
Base * a = new Base;
Derived * b = static_cast<Derived*>(a);
Это был бы допустимый код, хотя b указывал бы на неполный объект класса и мог бы привести к ошибкам во время выполнения при разыменовании.

Следовательно, static_cast способен выполнять с указателями на классы не только преобразования, разрешенные неявно, но и противоположные им преобразования.

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

Кроме того, static_cast также может выполнять следующие действия:
Явно вызовите конструктор с одним аргументом или оператор преобразования.
Преобразовать в ссылки на rvalue.
Преобразуйте enum class значения в целые числа или значения с плавающей запятой.
Преобразуйте любой тип в void, оценивая и отбрасывая значение.

повторная интерпретация

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

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

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

Код: Выделить всё

class A { /* ... */ };
class B { /* ... */ };
A * a = new A;
B * b = reinterpret_cast<B*>(a);
Этот код компилируется, хотя и не имеет особого смысла, поскольку теперь b указывает на объект совершенно не связанного и, вероятно, несовместимого класса. Разыменование b небезопасно.

const_cast

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

Код: Выделить всё

// const_cast
#include <iostream>
using namespace std;

void print (char * str)
{
  cout << str << '\n';
}

int main () {
  const char * c = "sample text";
  print ( const_cast<char *> (c) );
  return 0;
}
результат:

Код: Выделить всё

sample text

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

typeid

typeid позволяет проверить тип выражения:

typeid (expression)

Этот оператор возвращает ссылку на постоянный объект типа type_info, который определен в стандартном заголовке <typeinfo>. Значение, возвращаемое typeid, может быть сравнено с другим значением, возвращаемым typeid с помощью операторов == и != или может служить для получения символьной последовательности с нулевым завершением, представляющей тип данных или имя класса, с помощью его name() члена.

Код: Выделить всё

// typeid
#include <iostream>
#include <typeinfo>
using namespace std;

int main () {
  int * a,b;
  a=0; b=0;
  if (typeid(a) != typeid(b))
  {
    cout << "a and b are of different types:\n";
    cout << "a is: " << typeid(a).name() << '\n';
    cout << "b is: " << typeid(b).name() << '\n';
  }
  return 0;
}
результат:

Код: Выделить всё

a and b are of different types:
a is: int *
b is: int  
Когда typeid применяется к классам, typeid использует RTTI для отслеживания типа динамических объектов. Когда typeid применяется к выражению, типом которого является полиморфный класс, результатом является тип наиболее производного полного объекта:

Код: Выделить всё

// typeid, polymorphic class
#include <iostream>
#include <typeinfo>
#include <exception>
using namespace std;

class Base { virtual void f(){} };
class Derived : public Base {};

int main () {
  try {
    Base* a = new Base;
    Base* b = new Derived;
    cout << "a is: " << typeid(a).name() << '\n';
    cout << "b is: " << typeid(b).name() << '\n';
    cout << "*a is: " << typeid(*a).name() << '\n';
    cout << "*b is: " << typeid(*b).name() << '\n';
  } catch (exception& e) { cout << "Exception: " << e.what() << '\n'; }
  return 0;
}
результат:

Код: Выделить всё

a is: class Base *
b is: class Base *
*a is: class Base
*b is: class Derived
Примечание: Строка, возвращаемая member name of type_info, зависит от конкретной реализации вашего компилятора и библиотеки. Это не обязательно простая строка с типичным именем типа, как в компиляторе, используемом для создания этого вывода.

Обратите внимание, что тип, который typeid рассматривается для указателей, является самим типом указателя (оба a и b имеют тип class Base *). Однако, когда typeid применяется к объектам (таким как *a и *b), typeid выдает их динамический тип (т. Е. Тип их наиболее производного полного объекта).

Если тип, typeid вычисляемый, является указателем, которому предшествует оператор разыменования (*), и этот указатель имеет нулевое значение, typeid генерируется bad_typeid исключение.