サーチ…
前書き
式は、どの型のキャストが意図されているかに応じて、 dynamic_cast<T>
、 static_cast<T>
、 static_cast<T>
reinterpret_cast<T>
、またはconst_cast<T>
を使用して明示的に変換したり、型T
キャストできます。
C ++は、関数形式のキャスト表記法T(expr)
とCスタイルキャスト表記法(T)expr
もサポートしています。
構文
- 単純型指定子
(
)
- 単純型指定子
(
式リスト)
- 単純型指定子 braced-init-list
- typename-specifier
(
)
- 型名指定子
(
式リスト)
- typename-specifier braced-init-list
-
dynamic_cast
<
type-id>
(
式)
-
static_cast
<
type-id>
(
式)
-
reinterpret_cast
<
type-id>
(
式)
-
const_cast
<
type-id>
(
式)
-
(
型-id)
キャスト式
備考
6つのキャスト記法には共通するものが1つあります。
-
dynamic_cast<Derived&>(base)
ように左辺値参照型にキャストすると、左辺値が得られます。したがって、同じオブジェクトで何かをしたいが、それを別の型として扱う場合は、左辺値参照型にキャストします。 -
static_cast<string&&>(s)
ように、static_cast<string&&>(s)
参照型にキャストすると、static_cast<string&&>(s)
れます。 -
(int)x
ように、非参照型にキャストすると、キャストされる値のコピーとして考えられるが、元のものとは異なる型のプリ評価値が生成されます。
reinterpret_cast
キーワードは、2種類の「安全でない」コンバージョンを実行します。
- 1つのタイプのメモリにアクセスするために使用できる「タイプ・ペニング」変換。異なるタイプのものです。
- どちらの方向でも、 整数型とポインタ型の間の変換。
static_cast
キーワードは、さまざまな異なるコンバージョンを実行できます。
ベースからコンバージョンへの変換
暗黙の変換と明示的なコンストラクタまたは変換関数を呼び出す変換の両方を含む、直接初期化によって実行できる変換。詳細はこちらとこちらをご覧ください。
void
の場合は、式の値を破棄します。// on some compilers, suppresses warning about x being unused static_cast<void>(x);
算術と列挙型の間、および異なる列挙型間。 列挙型変換を参照
派生クラスのメンバへのポインタから、基本クラスのメンバへのポインタへ。指定された型は一致する必要があります。 メンバーへのポインタのための派生から基底への変換を参照
-
std::move
ように、左辺値からx値に変換します。 移動セマンティクスを参照してください。
ベースから派生した変換
基本クラスへのポインタは、 static_cast
を使用して派生クラスへのポインタに変換できます。 static_cast
は実行時のチェックを行わず、ポインタが実際に必要な型を指していないときは未定義の動作につながる可能性があります。
struct Base {};
struct Derived : Base {};
Derived d;
Base* p1 = &d;
Derived* p2 = p1; // error; cast required
Derived* p3 = static_cast<Derived*>(p1); // OK; p2 now points to Derived object
Base b;
Base* p4 = &b;
Derived* p5 = static_cast<Derived*>(p4); // undefined behaviour since p4 does not
// point to a Derived object
同様に、基本クラスへの参照は、 static_cast
を使用して派生クラスへの参照に変換できます。
struct Base {};
struct Derived : Base {};
Derived d;
Base& r1 = d;
Derived& r2 = r1; // error; cast required
Derived& r3 = static_cast<Derived&>(r1); // OK; r3 now refers to Derived object
ソースタイプがdynamic_cast
フィックである場合、 dynamic_cast
を使用して、ベースから派生した変換を実行できます。ランタイムチェックを実行し、未定義の動作を生成するのではなく、障害を回復できます。ポインタの場合、失敗時にヌルポインタが返されます。参照の場合、型std::bad_cast
(またはstd::bad_cast
から派生したクラス)の失敗時に例外がスローされます。
struct Base { virtual ~Base(); }; // Base is polymorphic
struct Derived : Base {};
Base* b1 = new Derived;
Derived* d1 = dynamic_cast<Derived*>(b1); // OK; d1 points to Derived object
Base* b2 = new Base;
Derived* d2 = dynamic_cast<Derived*>(b2); // d2 is a null pointer
コンスタンスを捨てる
constオブジェクトへのポインタは、 const_cast
キーワードを使用して、非constオブジェクトへのポインタに変換できます。ここではconst_cast
を使用して、const-correctでない関数を呼び出します。それは、たとえそれがポインタを通って書き込まなくても、非const char*
引数だけを受け付けます:
void bad_strlen(char*);
const char* s = "hello, world!";
bad_strlen(s); // compile error
bad_strlen(const_cast<char*>(s)); // OK, but it's better to make bad_strlen accept const char*
const_cast
から参照型への変換は、const修飾された左辺値をconst修飾されていない値に変換するために使用できます。
const_cast
は、C ++型システムがconstオブジェクトを変更しようとするのを防ぐことができないため、危険です。そうすると、動作が未定義になります。
const int x = 123;
int& mutable_x = const_cast<int&>(x);
mutable_x = 456; // may compile, but produces *undefined behavior*
型変換のタイプ
オブジェクト型へのポインタ(それぞれ参照)を使用して、他のオブジェクト型へのポインタ(それぞれ参照)に変換することができるreinterpret_cast
。これはコンストラクタや変換関数を呼び出さない。
int x = 42;
char* p = static_cast<char*>(&x); // error: static_cast cannot perform this conversion
char* p = reinterpret_cast<char*>(&x); // OK
*p = 'z'; // maybe this modifies x (see below)
reinterpret_cast
の結果は、アドレスが宛先タイプに対して適切に整列されていれば、オペランドと同じアドレスを表します。それ以外の場合、結果は未定義です。
int x = 42;
char& r = reinterpret_cast<char&>(x);
const void* px = &x;
const void* pr = &r;
assert(px == pr); // should never fire
reinterpret_cast
の結果は指定されていませんが、デスティネーションタイプのアラインメント要件がソースタイプよりも厳密でない限り、ポインタ(参照参照)はソースタイプからデスティネーションタイプへの往復に耐えます。
int x = 123;
unsigned int& r1 = reinterpret_cast<unsigned int&>(x);
int& r2 = reinterpret_cast<int&>(r1);
r2 = 456; // sets x to 456
ほとんどの実装では、 reinterpret_cast
はアドレスを変更しませんが、この要件はC ++ 11まで標準化されていませんでした。
reinterpret_cast
は、1つのポインタからデータメンバへの型から別の型へのポインタ、または1つのメンバ関数型へのポインタから別のものへの変換にも使用できます。
使用reinterpret_cast
読み取りまたはポインタまたは参照を介して書き込みを使用して得られたので、危険であると考えられるreinterpret_cast
送信元と宛先タイプは無関係である未定義の動作をトリガすることができます。
ポインタと整数の間の変換
(含むオブジェクトポインタvoid*
)または関数ポインタを使用して整数型に変換することができるreinterpret_cast
。これは、宛先タイプが十分に長い場合にのみコンパイルされます。結果はインプリメンテーションによって定義され、通常、ポインタが指すメモリ内のバイトの数値アドレスを生成します。
通常、 long
またはunsigned long
はポインタ値を保持するのに十分なunsigned long
ですが、これは標準によって保証されていません。
std::intptr_t
型とstd::uintptr_t
が存在する場合は、 void*
(したがってオブジェクト型へのポインタ)を保持するのに十分な長さが保証されます。ただし、関数ポインタを保持するのに十分長いことは保証されていません。
同様に、 reinterpret_cast
を使って整数型をポインタ型に変換することができます。この場合も、結果はインプリメンテーション定義ですが、ポインタ型の値は整数型の往復によって変更されないことが保証されています。標準では、値ゼロがヌルポインタに変換されることは保証されません。
void register_callback(void (*fp)(void*), void* arg); // probably a C API
void my_callback(void* x) {
std::cout << "the value is: " << reinterpret_cast<long>(x); // will probably compile
}
long x;
std::cin >> x;
register_callback(my_callback,
reinterpret_cast<void*>(x)); // hopefully this doesn't lose information...
明示的なコンストラクタまたは明示的変換関数による変換
明示的なコンストラクタまたは変換関数を呼び出すことを伴う変換は、暗黙的に行うことはできません。 static_cast
を使用して明示的に変換を要求することができます。結果は一時的なものであることを除いて、直接初期化の意味と同じです。
class C {
std::unique_ptr<int> p;
public:
explicit C(int* p) : p(p) {}
};
void f(C c);
void g(int* p) {
f(p); // error: C::C(int*) is explicit
f(static_cast<C>(p)); // ok
f(C(p)); // equivalent to previous line
C c(p); f(c); // error: C is not copyable
}
暗黙の変換
static_cast
は暗黙の変換を実行できます。このようなstatic_cast
使用は、次の例のように便利な場合があります。
引数を省略記号に渡すとき、 "予想される"引数型は静的に知られていないので、暗黙の変換は行われません。
const double x = 3.14; printf("%d\n", static_cast<int>(x)); // prints 3 // printf("%d\n", x); // undefined behaviour; printf is expecting an int here // alternative: // const int y = x; printf("%d\n", y);
明示的な型変換がなければ、
double
オブジェクトが省略記号に渡され、未定義の動作が発生します。派生クラス代入演算子は、次のように基本クラス代入演算子を呼び出すことができます。
struct Base { /* ... */ }; struct Derived : Base { Derived& operator=(const Derived& other) { static_cast<Base&>(*this) = other; // alternative: // Base& this_base_ref = *this; this_base_ref = other; } };
列挙型変換
static_cast
は、整数型または浮動小数点型から列挙型(スコープまたはスコープなし)に変換できます。逆も可能です。列挙型の間で変換することもできます。
- スコープのない列挙型から算術型への変換は暗黙の変換です。
static_cast
を使用することは可能ですが、必須ではありません。
スコープ付き列挙型を算術型に変換すると、次のようになります。
- 列挙型の値が宛先タイプで正確に表現できる場合、結果はその値になります。
- そうでない場合、宛先タイプが整数型の場合、結果は未指定です。
- それ以外の場合、宛先タイプが浮動小数点タイプの場合、結果は基本タイプへの変換の結果と同じになり、次に浮動小数点タイプへの変換の結果と同じになります。
例:
enum class Format { TEXT = 0, PDF = 1000, OTHER = 2000, }; Format f = Format::PDF; int a = f; // error int b = static_cast<int>(f); // ok; b is 1000 char c = static_cast<char>(f); // unspecified, if 1000 doesn't fit into char double d = static_cast<double>(f); // d is 1000.0... probably
整数または列挙型を列挙型に変換すると、次のようになります。
- 元の値が宛先enumの範囲内にある場合、結果はその値になります。この値はすべての列挙子と等しくないかもしれないことに注意してください。
- それ以外の場合、結果は未指定(<= C ++ 14)または未定義(> = C ++ 17)になります。
例:
enum Scale { SINGLE = 1, DOUBLE = 2, QUAD = 4 }; Scale s1 = 1; // error Scale s2 = static_cast<Scale>(2); // s2 is DOUBLE Scale s3 = static_cast<Scale>(3); // s3 has value 3, and is not equal to any enumerator Scale s9 = static_cast<Scale>(9); // unspecified value in C++14; UB in C++17
浮動小数点型を列挙型に変換すると、結果は列挙型の基本型に変換された後、列挙型に変換されるのと同じ結果になります。
enum Direction { UP = 0, LEFT = 1, DOWN = 2, RIGHT = 3, }; Direction d = static_cast<Direction>(3.14); // d is RIGHT
メンバーへのポインタの変換に派生
派生クラスのメンバへのポインタは、 static_cast
を使って基本クラスのメンバへのポインタに変換できます。指定された型は一致する必要があります。
オペランドがメンバ値へのヌルポインタである場合、結果はメンバ値へのヌルポインタにもなります。
それ以外の場合、変換は、オペランドによって指されたメンバが実際にデスティネーションクラスに存在する場合、またはデスティネーションクラスが、オペランドが指すメンバを含むクラスのベースクラスまたは派生クラスである場合にのみ有効です。 static_cast
は妥当性をチェックしません。変換が有効でない場合、動作は未定義です。
struct A {};
struct B { int x; };
struct C : A, B { int y; double z; };
int B::*p1 = &B::x;
int C::*p2 = p1; // ok; implicit conversion
int B::*p3 = p2; // error
int B::*p4 = static_cast<int B::*>(p2); // ok; p4 is equal to p1
int A::*p5 = static_cast<int A::*>(p2); // undefined; p2 points to x, which is a member
// of the unrelated class B
double C::*p6 = &C::z;
double A::*p7 = static_cast<double A::*>(p6); // ok, even though A doesn't contain z
int A::*p8 = static_cast<int A::*>(p6); // error: types don't match
void *からT *
C ++では、 void*
を暗黙的にT*
に変換することはできません。ここで、 T
はオブジェクト型です。代わりにstatic_cast
を使用して明示的に変換を実行する必要があります。オペランドが実際にT
オブジェクトを指す場合、結果はそのオブジェクトを指します。それ以外の場合、結果は未定義です。
オペランドがT
オブジェクトを指していなくても、オペランドがタイプT
に対してアドレスが正しく整列されているバイトを指している限り、変換の結果は同じバイトを指します。
// allocating an array of 100 ints, the hard way
int* a = malloc(100*sizeof(*a)); // error; malloc returns void*
int* a = static_cast<int*>(malloc(100*sizeof(*a))); // ok
// int* a = new int[100]; // no cast needed
// std::vector<int> a(100); // better
const char c = '!';
const void* p1 = &c;
const char* p2 = p1; // error
const char* p3 = static_cast<const char*>(p1); // ok; p3 points to c
const int* p4 = static_cast<const int*>(p1); // unspecified in C++03;
// possibly unspecified in C++11 if
// alignof(int) > alignof(char)
char* p5 = static_cast<char*>(p1); // error: casting away constness
Cスタイルキャスティング
Cスタイルのキャスティングは「ベストエフォート」のキャスティングと見なすことができ、C言語で使用できる唯一のキャストという名前が付けられてい(NewType)variable
。このキャストの構文は(NewType)variable
。
このキャストが使用されるたびに、次のいずれかのC ++キャストが順番に使用されます。
-
const_cast<NewType>(variable)
-
static_cast<NewType>(variable)
-
const_cast<NewType>(static_cast<const NewType>(variable))
-
reinterpret_cast<const NewType>(variable)
-
const_cast<NewType>(reinterpret_cast<const NewType>(variable))
機能キャスティングは非常に似ていますが、構文の結果としていくつかの制限があります: NewType(expression)
。その結果、スペースを持たない型だけがキャストできます。
新しいC ++キャストを使用する方が良いです。なぜなら、C ++ソースコードのどこからでも読みやすく、どこでも簡単に見つけ出すことができ、ランタイムではなくコンパイル時にエラーが検出されるからです。
このキャストは意図しないreinterpret_cast
を引き起こす可能性があるため、しばしば危険とみなされます。