サーチ…


前書き

式は、どの型のキャストが意図されているかに応じて、 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種類の「安全でない」コンバージョンを実行します。

static_castキーワードは、さまざまな異なるコンバージョンを実行できます。

  • ベースからコンバージョンへの変換

  • 暗黙の変換と明示的なコンストラクタまたは変換関数を呼び出す変換の両方を含む、直接初期化によって実行できる変換。詳細はこちらこちらをご覧ください。

  • voidの場合は、式の値を破棄します。

    // on some compilers, suppresses warning about x being unused
    static_cast<void>(x);
    
  • 算術と列挙型の間、および異なる列挙型間。 列挙型変換を参照

  • 派生クラスのメンバへのポインタから、基本クラスのメンバへのポインタへ。指定された型は一致する必要があります。 メンバーへのポインタのための派生から基底への変換を参照

  • void*からT* void*

C ++ 11

ベースから派生した変換

基本クラスへのポインタは、 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)
C ++ 11

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
C ++ 11

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ですが、これは標準によって保証されていません。

C ++ 11

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を使用することは可能ですが、必須ではありません。
C ++ 11
  • スコープ付き列挙型を算術型に変換すると、次のようになります。

    • 列挙型の値が宛先タイプで正確に表現できる場合、結果はその値になります。
    • そうでない場合、宛先タイプが整数型の場合、結果は未指定です。
    • それ以外の場合、宛先タイプが浮動小数点タイプの場合、結果は基本タイプへの変換の結果と同じになり、次に浮動小数点タイプへの変換の結果と同じになります。

    例:

    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
    
C ++ 11
  • 浮動小数点型を列挙型に変換すると、結果は列挙型の基本型に変換された後、列挙型に変換されるのと同じ結果になります。

    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オブジェクトを指す場合、結果はそのオブジェクトを指します。それ以外の場合、結果は未定義です。

C ++ 11

オペランドが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を引き起こす可能性があるため、しばしば危険とみなされます。



Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow