C++強制型変換(dynamic_cast,static_cast,const_cast,reinterpret_cast)

22477 ワード

  • 概要
  • dynamic_cast
  • 構文
  • dynamic_cast例
  • static_cast
  • 構文
  • static_cast例
  • const_cast
  • 構文
  • const_cast例
  • reinterpret_cast
  • 構文
  • reinterpret_cast例
  • dynamic_キャストとstatic_castの違い
  • 参照
  • 概要
    C++は、4つの新しい強制タイプ変換形式(通常、新しいスタイルまたはC++スタイルと呼ばれる強制変換):const_cast(expression)、dynamic_cast(expression)、 reinterpret_cast(expression)とstatic_cast(expression)は、それぞれ特定の目的に適用されます.
    dynamic_cast
    継承レベルに沿ってクラスのポインタと参照を上、下、および横に変換します.
    構文
    dynamic_cast < new_type > ( expression )    
  • new_type-完全クラスタイプへのポインタ、完全クラスタイプへの参照、または(オプションcv限定)voidへのポインタ
  • expression-若new_typeが参照の場合、完全クラスタイプの左(C++11前)汎左(C++11から)式であり、new_typeはポインタであり、完全なクラスタイプを指すポインタの純右値である.モデルチェンジが成功するとdynamic_castはnew_を返しますtypeタイプの値.モデルチェンジに失敗しnew_typeがポインタタイプである場合、そのタイプの空のポインタが返されます.モデルチェンジに失敗しnew_typeが参照タイプである場合、一致タイプstd::bad_を放出します.cast処理ブロックの異常.

  • 注意:dynamic_castは、親クラスcastを子クラスにするときに使用します.親には虚関数が必要です.たとえば、CBasicクラスのtest関数をvirtualと定義しないコードでは、コンパイラがエラーを報告します.error C 2683:dynamic_キャスト:「CBasic」はマルチステートタイプではありません
    コンパイラの要件:dynamic_cast<>はRTTIテクノロジーを使用します.そのため、VCでは「実行時タイプ情報」というオプションを起動する必要がある.Net 2003ではデフォルトでオフになっています.
    dynamic_cast例
    #include 
    using namespace std;
    
    class CBasic
    {
    public:
        virtual int test(){return 0;} //      virtual
    };
    
    class CDerived : public CBasic
    {
    public:
        virtual int test(){    return 1;}
    };
    
    int main()
    {
        CBasic        cBasic;
        CDerived    cDerived;
    
        CBasic * pB1 = new CBasic;
        CBasic * pB2 = new CDerived;
    
        //dynamic cast failed, so pD1 is null.
        CDerived * pD1 = dynamic_cast (pB1);
        std::cout << "pD1 = " << pD1 << std::endl;
    
        //dynamic cast succeeded, so pD2 points to  CDerived object
        CDerived * pD2 = dynamic_cast (pB2);
        std::cout << "pD2 = " << pD2 << std::endl;
    
        //dynamci cast failed, so throw an exception.
        //    CDerived & rD1 = dynamic_cast (*pB1);
    
        //dynamic cast succeeded, so rD2 references to CDerived object.
        CDerived & rD2 = dynamic_cast (*pB2);
    
        return 0;
    }
    

    static_cast
    暗黙的およびユーザー定義変換の組合せを使用してタイプ間で変換します.
    構文
    static_cast < new_type > ( expression )     
  • new_を返すtypeタイプの値.

  • static_castは、強制的にステルス変換(例えばnon-constオブジェクトをconstオブジェクトに変換し、intをdoubleに変換するなど)に使用することができ、このような変換の多くの逆変換(例えばvoid*ポインタをタイプポインタに変換し、ベースクラスポインタを派生クラスポインタに変換する)にも使用することができる.ただし、constオブジェクトをnon-constオブジェクト(const_castのみ)に変換することはできません.C-styleの変換に最も近いです.クラスに適用されるポインタは、子クラスタイプのポインタを親クラスタイプのポインタに変換できるようにする(これは有効な暗黙的な変換である)とともに、親を子に変換する逆の動作も実行できます.
    static_cast例
    #include 
    #include 
    
    struct B {
        int m = 0;
        void hello() const {
            std::cout << "Hello world, this is B!
    "
    ; } }; struct D : B { void hello() const { std::cout << "Hello world, this is D!
    "
    ; } }; enum class E { ONE = 1, TWO, THREE }; enum EU { ONE = 1, TWO, THREE }; int main() { // 1: int n = static_cast<int>(3.14); std::cout << "n = " << n << '
    '
    ; std::vector<int> v = static_cast<std::vector<int>>(10); std::cout << "v.size() = " << v.size() << '
    '
    ; // 2: D d; B& br = d; // br.hello(); D& another_d = static_cast(br); // another_d.hello(); // 3: std::vector<int> v2 = static_cast<std::vector<int>&&>(v); std::cout << "after move, v.size() = " << v.size() << '
    '
    ; // 4: static_cast<void>(v2.size()); // 5. void* nv = &n; int* ni = static_cast<int*>(nv); std::cout << "*ni = " << *ni << '
    '
    ; // 6. D a[10]; B* dp = static_cast(a); // 7. int float E e = E::ONE; int one = static_cast<int>(e); std::cout << one << '
    '
    ; // 8. int , E e2 = static_cast(one); EU eu = static_cast(e2); // 9. int D::*pm = &D::m; std::cout << br.*static_cast<int B::*>(pm) << '
    '
    ; // 10. void* void* voidp = &e; std::vector<int>* p = static_cast<std::vector<int>*>(voidp); }

    実行結果
    n = 3
    v.size() = 10
    Hello world, this is B!
    Hello world, this is D!
    after move, v.size() = 0
    *ni = 3
    1
    0

    const_cast
    const_castは一般に、オブジェクトの定数を強制的に除去するために使用されます.それが唯一できるC++スタイルの強制的な転換です.この変換は、オブジェクトのconstプロパティを剥離します.つまり、定数を変更できます.
    構文
    const_cast < new_type > ( expression )      
  • new_を返すtypeタイプの値.

  • const_cast例
    #include 
    
    struct type {
        int i;
    
        type(): i(3) {}
    
        void f(int v) const
        {
            // this->i = v;                 //     : this     const    
            const_cast(this)->i = v; //         const   OK
        }
    };
    
    class C
    {
    
    };
    
    int main()
    {
        int i = 3;                 //     i   const
        const int& rci = i;
        const_cast<int&>(rci) = 4; // OK :   i
        std::cout << "i = " << i << '
    '
    ; type t; // const type t , t.f(4) t.f(4); std::cout << "type::i = " << t.i << '
    '
    ; const int j = 3; // j const int* pj = const_cast<int*>(&j); // *pj = 4; // void (type::* pmf)(int) const = &type::f; // // const_cast(pmf); // : const_cast const C *a = new C; C *b = const_cast(a); }

    実行結果
    i = 4
    type::i = 4

    reinterpret_cast
    static_とcastは違いますがconst_とcast類似、reinterpret_cast式は、整数とポインタの間で変換したり、ポインタがそのタイプに依存する不明なアーキテクチャを表す場合を除き、CPU命令にコンパイルされません.コンパイラがexpressionのビットシーケンス(オブジェクト表示)をnew_と見なすことを示すコンパイル時コマンドです.typeタイプのビットシーケンス.
    構文
    reinterpret_cast < new_type > ( expression )        
  • new_を返すtypeタイプの値.

  • reinterpret_castは、特に下位層の強制的な転換に用いられ、依存(すなわち、移植不可能)を実現する結果をもたらし、例えば、ポインタを整数に転換する.このような強制タイプは、下位コード以外では極めて珍しいはずです.操作結果は,1つのポインタから別のポインタへの単純なバイナリコピーにすぎない.タイプ間で指す内容は、タイプのチェックや変換は行われません.
    reinterpret_cast例
    #include 
    #include 
    #include 
    int f() { return 42; }
    int main()
    {
        int i = 7;
    
        //         
        std::uintptr_t v1 = reinterpret_cast<:uintptr_t>(&i); // static_cast    
        std::cout << "The value of &i is 0x" << std::hex << v1 << '
    '
    ; int* p1 = reinterpret_cast<int*>(v1); assert(p1 == &i); // void(*fp1)() = reinterpret_cast<void(*)()>(f); // fp1(); int(*fp2)() = reinterpret_cast<int(*)()>(fp1); std::cout << std::dec << fp2() << '
    '
    ; // // char* p2 = reinterpret_cast<char*>(&i); if(p2[0] == '\x7') std::cout << "This system is little-endian
    "
    ; else std::cout << "This system is big-endian
    "
    ; // reinterpret_castint&>(i) = 42; std::cout << i << '
    '
    ; const int &const_iref = i; // int &iref = reinterpret_cast(const_iref); // —— const // const_cast : int &iref = const_cast(const_iref); }

    実行結果
    The value of &i is 0x61fe84
    42
    This system is little-endian
    42

    dynamic_キャストとstatic_キャストの違い
    C++でdynamic_キャストとstatic_castはいずれも変換に使用されるオペレータであり、両者の不合理な運用により、コンパイル期間に合法的なタイプの変換操作が実行期間においてもエラーを引き起こす可能性があり、変換操作がオブジェクトポインタや参照に関連する場合、エラーが発生しやすい.この二つにはどんな違いがありますか.
  • dynamic_castオペレータは、実行中に不審な移行操作をセキュリティチェックし、static_castオペレータはセキュリティチェックを行いません.
  • dynamic_castはマルチステートにのみ有効です(トランスフォームのソースタイプはマルチステートでなければなりませんが、トランスフォームのターゲットタイプがマルチステートであるかどうかは関係ありません)、static_castは任意のタイプに適用できます.
  • 派生クラスからベースクラスへのdynamic_castは行うことができ、これは向上転換と呼ばれています.
  • ベースクラスから派生クラスへのdynamic_castはできません.下への転換と呼ばれています.
  • は継承関係があり、派生クラスはdynamic_を通過することができる.castからベースクラスへの変換;
  • は関係を継承しておらずdynamic_を通過できませんcast交換;

  • 使用方法:
    dynamic_castptr、static_castptr;
    dynamic_castp、static_castp;

    次に、単純なコードを使用して、変換に関するいくつかの知識点を説明します.1つのベースクラスポインタは明確な変換操作を経ずに、ベースクラスオブジェクトまたは派生クラスオブジェクトを指すことができます.逆に、派生クラスポインタがベースクラスオブジェクトを指すのは賢明ではありません.
    class B
    {
        ...    
    };
    class D : public B 
    {
        ... 
    };
    int main( ) 
    {
        D* p;
        p = new B();                  // error
        p = static_cast(new B()); //   ,               
    }

    次のコードを見てください.
    #include 
    using namespace std;
    class B
    {
    public:
        virtual void f() { cout<< "f()" <class D : public B
    {
    public:
        void m(){cout<< "m()" <int main()
    {
        D* p = static_cast(new B);
        p -> m();   // ...
        return 0;
    }

    ここでp->m()コンパイルはパスでき、一部のコンパイラでエラーが発生しました.Pは実際にはBのオブジェクトを指しているが、Bにはメンバー関数mがないため、この変換は安全ではない(MinGW gcc-6.3.0では正しく動作し、出力:m()).
    C++提供dynamic_castオペレータは、実行中に移行動作が安全かどうかを検出できます.dynamic_キャストとstatic_castには同じ文法がありますがdynamic_castはマルチステートタイプにのみ有効です.
    #include 
    using namespace std;
    
    class C
    {
        // C      
    };
    class T : public C
    {
    };
    int main(  )
    {
        T* p = dynamic_cast(new C());  // error,        ,   static_cast    
        return 0;
    }
    

    注意:dynamic_cast操作の正しい前提は、変換のソースタイプはマルチステートである必要がありますが、変換のターゲットタイプがマルチステートであるかどうかは関係ありません.<>で指定したdynamic_castの目的タイプはポインタまたは参照でなければなりません.正しい使い方を見てみましょう.
    #include 
    using namespace std;
    
    class B
    {
    public:
        virtual void f() {cout << "f()" << endl;}
    };
    class D:public B
    {
    public:
        void m() {cout << "m()" << endl;}
    };
    int main()
    {
        D* p = dynamic_cast(new B()); //           ,    ,   B     ,    NULL。    NULL。
        B* b_p = new D();
    
        cout << "dynamic_cast1 
    "
    ; if (p) { p -> m(); } else { cout << "Error
    "
    ; } cout << "dynamic_cast2
    "
    ; p = dynamic_cast(b_p) ; if (p) { p -> m(); } else { cout << "Error
    "
    ; } return 0; }

    リファレンス
    [1] dynamic_キャストとstatic_castの違い[2]static_cast ,reinterpret_cast-夏雪冬