static_cast преобразование
Преобразует типы с использованием комбинации неявных и определяемых пользователем преобразований.
Синтаксис
static_cast<тип-результата >(выражение ) |
Возвращает значение типа тип-результата.
Объяснение
Только следующие преобразования могут быть выполнены с помощью static_cast, за исключением случаев, когда такие преобразования приведут к снятию константности (или изменчивости).
D и выражение является lvalue его невиртуального базового класса B, или тип-результата является указателем на некоторый полный класс D и выражение является prvalue-указателем на его невиртуальный базовый класс B, static_cast выполняет приведение вниз. (Это приведение вниз некорректно, если B является неоднозначным, недоступным или виртуальным базовым классом (или базовым классом виртуального базового класса) D.)D, и может использоваться безопасно только в том случае, если это предварительное условие гарантировано другими средствами, например, при реализации статического полиморфизма. Безопасное приведение вниз можно выполнить с помощью dynamic_cast.D, результат ссылается на содержащий объект типа D. В противном случае поведение не определено: struct B {};
struct D : B { B b; };
D d;
B& br1 = d;
B& br2 = d.b;
static_cast<D&>(br1); // OK: lvalue denoting the original d object
static_cast<D&>(br2); // UB: the b subobject is not a base class subobject 2) Если тип-результата является типом rvalue-ссылки, а тип ссылки является совместимым со ссылкой с типом выражение, static_cast преобразует значение lvalue, prvalue класса или prvalue массива(до C++17)любого lvalue(с C++17) выражение в xvalue, ссылающееся на тот же объект, что и выражение, или на его подобъект (в зависимости от тип-результата). Если целевой тип является недоступным или неоднозначным базовым типом типа выражения, программа некорректна. Если выражение является битовым полем lvalue, оно сначала преобразуется в prvalue базового типа. Этот тип static_cast используется для реализации семантики перемещения в std::move. | (с C++11) |
static_cast<target-type >(expression ) возвращает воображаемую переменную Temp инициализированную так, как если бы это было сделано target-type Temp(expression );, что может включать неявные преобразования, вызов конструктора типа тип-результата или вызов определяемого пользователем оператора преобразования. Для нессылочного тип-результата объектом результата static_cast prvalue-выражения является то, что прямо инициализируется.(с C++17)
void (возможно, с квалификатором cv), static_cast отбрасывает значение выражение после его вычисления.static_cast может выполнить обратное неявное преобразование.static_cast. 7) Тип перечисления со сферой видимости может быть преобразован в целочисленный или тип с плавающей точкой.
| (с C++11) |
- Если базовый тип не фиксирован, поведение неопределено, если значение выражение выходит за пределы диапазона (диапазон включает все значения, возможные для самого маленького поля бит, достаточно большого, чтобы содержать все перечислители целевого перечисления).
- Если базовый тип фиксирован, результат такой же, как преобразование исходного значения сначала в базовый тип перечисления, а затем в тип перечисления.
- Результат совпадает с преобразованием исходного значения сначала в базовый тип перечисления, а затем в тип перечисления.
9) Prvalue типа с плавающей точкой может быть явно преобразован в любой другой тип с плавающей точкой.
| (с C++23) |
D может быть преобразован вверх в указатель на член его неопределённого, доступного базового класса B. Это static_cast не выполняет проверок, чтобы гарантировать, что член фактически существует в типе объекта, на который указывает указатель: если B не содержит исходный член и не является базовым классом класса, содержащего исходный член, поведение не определено.T. - Если исходное значение указателя представляет адрес байта в памяти, который не удовлетворяет требованию выравнивания
T, то результирующее значение указателя является неопределённым. - В противном случае, если исходный указатель указывает на объект
a, и существует объектbтипа аналогичного типуTи совместимого с указателем сa, результатом является указатель наb. - В противном случае значение указателя не изменяется.
void и обратно в указатель на исходный (или с более сильными квалификаторами cv) тип сохраняет его исходное значение.Как и при всех выражениях преобразования, результатом является:
- lvalue, если тип-результата является типом lvalue-ссылки или rvalue-ссылки на тип функции(с C++11);
| (с C++11) |
- prvalue в противном случае.
Совместимые с указателем объекты
Два объекта a и b являются совместимыми с указателем, если:
- они являются одним и тем же объектом, или
- один является объединяющим объектом, а другой — нестатическим членом данных этого объекта, или
- один — объектом класса со стандартной компоновкой, а другой — первым нестатическим членом данных этого объекта или любого подобъекта базового класса этого объекта, или
- существует объект
c, такой чтоaиcявляются указателями, совместимыми по типу, иcиbявляются указателями, совместимыми по типу.
union U { int a; double b; } u;
void* x = &u; // x's value is "pointer to u"
double* y = static_cast<double*>(x); // y's value is "pointer to u.b"
char* z = static_cast<char*>(x); // z's value is "pointer to u"Примечания
static_cast также может быть использован для разрешения неоднозначности перегрузки функций, выполняя преобразование функции в указатель на конкретный тип, как в
std::for_each(files.begin(), files.end(),
static_cast<std::ostream&(*)(std::ostream&)>(std::flush));Ключевые слова
Пример
#include <iostream>
#include <vector>
struct B
{
int m = 42;
const char* hello() const
{
return "Hello world, this is B!\n";
}
};
struct D : B
{
const char* hello() const
{
return "Hello world, this is D!\n";
}
};
enum class E { ONE = 1, TWO, THREE };
enum EU { ONE = 1, TWO, THREE };
int main()
{
// 1. static downcast
D d;
B& br = d; // upcast via implicit conversion
std::cout << "1) " << br.hello();
D& another_d = static_cast<D&>(br); // downcast
std::cout << "1) " << another_d.hello();
// 2. lvalue to xvalue
std::vector<int> v0{1,2,3};
std::vector<int> v2 = static_cast<std::vector<int>&&>(v0);
std::cout << "2) after move, v0.size() = " << v0.size() << '\n';
// 3. initializing conversion
int n = static_cast<int>(3.14);
std::cout << "3) n = " << n << '\n';
std::vector<int> v = static_cast<std::vector<int>>(10);
std::cout << "3) v.size() = " << v.size() << '\n';
// 4. discarded-value expression
static_cast<void>(v2.size());
// 5. inverse of implicit conversion
void* nv = &n;
int* ni = static_cast<int*>(nv);
std::cout << "5) *ni = " << *ni << '\n';
// 6. array-to-pointer followed by upcast
D a[10];
[[maybe_unused]]
B* dp = static_cast<B*>(a);
// 7. scoped enum to int
E e = E::TWO;
int two = static_cast<int>(e);
std::cout << "7) " << two << '\n';
// 8. int to enum, enum to another enum
E e2 = static_cast<E>(two);
[[maybe_unused]]
EU eu = static_cast<EU>(e2);
// 9. pointer to member upcast
int D::*pm = &D::m;
std::cout << "9) " << br.*static_cast<int B::*>(pm) << '\n';
// 10. void* to any type
void* voidp = &e;
[[maybe_unused]]
std::vector<int>* p = static_cast<std::vector<int>*>(voidp);
}Вывод:
1) Hello world, this is B! 1) Hello world, this is D! 2) after move, v0.size() = 0 3) n = 3 3) v.size() = 10 5) *ni = 3 7) 2 9) 42
Отчеты об ошибках
Следующие отчеты об ошибках, меняющие поведение, были применены ретроактивно к ранее опубликованным стандартам C++.
| DR | Применен к | Поведение при публикации | Корректное поведение |
|---|---|---|---|
| CWG 137 | C++98 | постоянство и изменчивость указателей void могли быть отброшены при приведении типов | квалификаторы cv не могут быть отброшены в таких случаях |
| CWG 439 | C++98 | при преобразовании «указателя на объект» в «указатель на void» и обратно в себя, значение сохранялось только если тип результата имел те же квалификации cv | квалификации cv могут быть другими |
| CWG 1094 | C++98 | преобразование значений с плавающей точкой в значения перечисления было неопределенным | определенное |
| CWG 1320 | C++11 | преобразование значений перечисления со scope в bool было неопределенным | определенное |
| CWG 1447 | C++11 | преобразование из битовых полей в ссылки rvalue было неопределенным (нельзя привязать ссылки к битовым полям) | определенное |
| CWG 1766 | C++98 | преобразование целочисленных или перечислительных значений в перечислительные значения давало неопределенный результат, если выражение находится вне диапазона | поведение в этом случае неопределено |
| CWG 1832 | C++98 | преобразование целочисленных или перечислительных значений в значения перечисления позволяло целевому типу быть неполным | не разрешается |
| CWG 2224 | C++98 | преобразование из члена базового типа в полный объект производного класса было допустимым | поведение в этом случае неопределено |
| CWG 2254 | C++11 | объект класса со стандартной компоновкой без членов данных был совместим по указателям с первым базовым классом | он совместим по указателям с любым из своих базовых классов |
| CWG 2284 | C++11 | объект объединения без стандартной компоновки и нестатический член данных этого объекта не были совместимы по указателям | они совместимы |
| CWG 2310 | C++98 | для преобразований указателей из базового класса в производный и преобразований указателей на члены данных из производного в базовый, тип производного класса мог быть неполным | должен быть полным |
| CWG 2338 | C++11 | преобразование в типы перечислений с фиксированным базовым типом приводило к неопределенному поведению, если выражение находится вне диапазона | сначала преобразовать в базовый тип (нет неопределённого поведения) |
| CWG 2499 | C++11 | класс со стандартной компоновкой может иметь базовый класс, не совместимый по указателям, даже если все под-объекты базового класса имеют одинаковый адрес | нет |
| CWG 2718 | C++98 | для преобразований ссылок из базового класса в производный, тип производного класса мог быть неполным | должен быть полным |
См. также
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/language/static_cast