C+|強制型変換(回転)

7715 ワード

C+|強制型変換(回転)
目次
C+|強制型変換(回転)
1.c強制変換とc++強制変換
2. static_cast、dynamic_cast、const_cast、reinterpret_cast
2.1.static_cast
2.2.dynamic_cast
2.2.1.ポインタタイプ
2.2.2.参照ポインタのタイプ
2.3.const_cast
2.4.reinterpret_cast
3.c++強制変換の注意事項
1.c強制変換とc++強制変換
c言語強制型変換は主に基礎のデータ型間の変換に用いられ、文法は以下の通りである.
(type-id)expression//    1

type-id(expression)//    2

c++は、c言語を使用できる強制タイプ変換のほか、4つの強制タイプ変換を追加しました.
  •        static_cast
  •        dynamic_cast
  •        const_cast
  •        reinterpret_cast

  • 主に継承関係クラス間の強制転化に用いられ、文法は以下の通りである.
    //    
    static_cast      (expression)
    //    
    dynamic_cast     (expression) 
    //    
    const_cast       (expression) 
    //      
    reinterpret_cast (expression)

    備考:new_typeはターゲットデータ型、expressionは元のデータ型変数または式です.
    「Effective C++」では、c言語の強制タイプ変換を旧式変換と呼び、c++強制タイプ変換を新式変換と呼ぶ.
    2. static_cast、dynamic_cast、const_cast、reinterpret_cast
    2.1.static_キャスト(コンパイル時チェック)
           static_castは従来のC言語の強制変換に相当するが、通常のポインタデータ(空のポインタを除く)の強制変換は実現できず、この演算子はexpressionをnew_に変換するtypeタイプは、non-constオブジェクトがconstオブジェクトに変換されるなどの暗黙的な変換を強制するために使用され、コンパイル時にチェックされ、非多様な変換に使用され、ポインタやその他を変換することができますが、実行時タイプチェックは変換の安全性を保証しません.主に次のような使い方があります.
    ①クラス階層内のベースクラス(親クラス)と派生クラス(子クラス)間のポインタまたは参照の変換:
    上り変換(派生クラスのポインタや参照をベースクラス表示に変換)を行うのは安全です.
    下り変換(ベースクラスポインタや参照を派生クラス表示に変換)を行う場合、ダイナミックタイプチェックがないため安全ではありません.
    ②intをcharに変換し、intをenumに変換するなど、基本データ型間の変換に使用します.このような転換の安全性も開発者が保証しなければならない.
    ③空ポインタをターゲットタイプの空ポインタに変換します.
    ④任意のタイプの式をvoidタイプに変換します.
    ⑤通常データのconstとnon_constは変換されますが、通常のデータに対してアドレスを取ったポインタをconst追加や消去することはできません.
    ⑥継承関係のないカスタムタイプ、変換不可、クラス間クロス変換はサポートされていません.
    注意:static_キャストはexpressionのconst、volatile、または__を変換できません.unalignedプロパティ.
    基本タイプのデータ変換は次のようになります.
    char a = 'a';
    int b = static_cast(a);//  , char      int   
    
    double *c = new double;
    void *d = static_cast(c);//  , double     void  
    
    int e = 10;
    const int f = static_cast(e);//  , int      const int   
    
    const int g = 20;
    int *h = static_cast(&g);//    ,static_cast     g const  

    クラスの上下変換:
    if(Derived *dp = static_cast(bp)){//         
      //  dp   Derived    
    }
    else{
      //  bp   Base    
    }
    
    if(Base*bp = static_cast(dp)){//        
      //  bp   Derived    
    }
    else{
      //  dp   Base    
    }

    2.2.dynamic_キャスト(運転時点検)
    主にクラス階層のベースクラス(親クラス)と派生クラス(子クラス)間のポインタまたは参照の変換に使用されます.
    ①上り変換(派生クラスのポインタや参照をベースクラス表示に変換)を行うことは安全であり、変換を許可する.
    ②下り変換(ベースクラスポインタまたは参照を派生クラス表示に変換)を行う場合、ダイナミックタイプチェックがないため安全ではなく、変換が許されず、コンパイラがエラーを報告する.
    ③マルチステートが発生した場合、相互変換を許可する.
    ④継承関係のないクラス間でも相互変換が可能であり、クラス間の交差変換が可能である.
    ⑤dynamic_cast文の変換先がポインタタイプで失敗すると、結果は0になります.変換先が参照タイプで失敗した場合dynamic_cast演算子はstd::bad_を放出します.cast異常
    dynamic_cast(e)
    dynamic_cast(e)
    dynamic_cast(e)

    typeはクラスタイプでなければなりません.通常のデータは操作できません.
  • 第1の形態では、typeは有効なポインタでなければならない.
  • 第2の形態では、typeは左値でなければならない.
  • 第3の形態では、typeは右の値でなければならない.

  • 上記のすべての形式では、eのタイプは以下の3つの条件のいずれかに合致しなければならない.
  • eのタイプは、ターゲットタイプtypeの共通派生クラスである.
  • eのタイプは、ターゲットtypeの公有ベースクラスである.
  • eのタイプがターゲットtypeのタイプです.

  • dynamic_の場合cast文の変換先がポインタタイプで失敗すると、結果は0になります.変換先が参照タイプで失敗した場合dynamic_cast演算子はstd::bad_を放出します.cast例外(typeinfo標準ライブラリヘッダファイルに定義されている例外).eは、空のポインタであってもよく、結果として所望のタイプの空のポインタであってもよい.
          dynamic_castは主にクラス階層間の上り変換と下り変換に用いられ、クラス間のクロス変換(cross cast)にも用いられる.
    クラス階層間でアップリンク変換を行う場合、dynamic_キャストとstatic_castの効果は同じです.
    下り変換時にdynamic_castにはstatic_よりもタイプチェック機能があります.castの方が安全です.dynamic_castは、従来の構文では実行できない唯一の動作であり、重大な実行コストを消費する可能性のある唯一の転換動作でもあります.
    2.2.1.ポインタタイプ
    例えば、Baseは少なくとも1つの虚関数を含むベースクラスであり、DerivedはBaseの共通派生クラスであり、Baseを指すポインタbpがあれば、実行時にDerivedを指すポインタに変換することができ、コードは以下の通りである.
    if(Derived *dp = dynamic_cast(bp)){
      //  dp   Derived    
    }
    else{
      //  bp   Base    
    }

    上記のコードではif文でdpが定義されており、1つの操作でタイプ変換と条件チェックの2つのタスクを同時に完了できるという利点がある.
    2.2.2.参照ポインタのタイプ
    いわゆる空の参照は存在しないので、参照タイプのdynamic_cast変換はポインタタイプとは異なり、参照変換に失敗するとstd::bad_が投げ出されます.cast例外.この例外はヘッダファイルtypeinfoに定義されます.
    void f(const Base &b){
     try{
       const Derived &d = dynamic_cast(b);  
       //  b   Derived  
     }
     catch(std::bad_cast){
       //           
     }
    }

    2.3.const_cast
            const_cast、タイプのconstまたはvolatileプロパティを変更します. 
    この演算子は、タイプのconst(この機能を持つ唯一のC++-style変換オペレータ)またはvolatileプロパティを変更するために使用されます.constまたはvolatile修飾に加えてnew_typeとexpressionのタイプは同じです.
    1定数ポインタは、非常に量のポインタに変換され、元のオブジェクトを指す.
    ②定数参照は非常量の参照に変換され、元のオブジェクトを指す.
           ③const_castは一般的にベースポインタを変更するために使用されます.const char*p形式のようです.
    たとえば、次のように変換します.
    const int g = 20;
    int *h = const_cast(&g);//  const  const  
    
    const int g = 20;
    int &h = const_cast(g);//  const  const  
    
     const char *g = "hello";
    char *h = const_cast(g);//  const  const  

    2.4.reinterpret_cast
    最も鶏肋の変換関数は、任意のタイプを任意のタイプに変換できるため、非常に安全ではありません.変換されたタイプ値を元のタイプに変換するだけでreinterpret_が正しく使用されます.キャスト方式.
             new_typeは、ポインタ、参照、算術タイプ、関数ポインタ、またはメンバーポインタでなければなりません.1つのポインタを1つの整数に変換したり、1つの整数を1つのポインタに変換したりすることができます(まず1つのポインタを1つの整数に変換してから、その整数を元のタイプのポインタに変換したり、元のポインタ値を得ることができます).
            reinterpret_castは低レベルの移行を意図しており、実際の動作(および結果)はエディタに依存する可能性があります.これは移植できないことを示しています.
    エラーを挙げてreintepret_を使用cast例では、整数タイプを関数ポインタに変換すると、vc++は実行中に「...の0 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    #include 
    using namespace std;
    int output(int p){
        cout << p <(&p);
        fun2(p);//...         : 0xC0000005: Access violation
        return 0;
    }

    IBMのC++ガイド、C++の親Bjarne StroustrupのFAQページ、MSDNのVisual C++も、reinterpret_の誤った使用を指摘しています.castはプログラムの不安全を招きやすく、変換後のタイプ値を元のタイプに変換するだけでreinterpret_が正しく使用されます.キャスト方式.
    MSDNでも言及されていますが、実際にはreinterpret_castはハッシュ関数に適用され、以下のようになります(64ビットシステムではunsigned intをunsigned longに変更する必要があります).
    // expre_reinterpret_cast_Operator.cpp
    // compile with: /EHsc
    #include 
    
    // Returns a hash code based on an address
    unsigned short Hash( void *p ) {
       unsigned int val = reinterpret_cast( p );
       return ( unsigned short )( val ^ (val >> 16));
    }
    
    using namespace std;
    int main() {
       int a[20];
       for ( int i = 0; i < 20; i++ )
          cout << Hash( a + i ) << endl;
    }

    また、static_castとreinterpret_castの違いは主に多重継承にあり、例えば
    class A {
        public:
        int m_a;
    };
     
    class B {
        public:
        int m_b;
    };
     
    class C : public A, public B {};

    では、次のコードについて説明します.
    C c;
    printf("%p, %p, %p", &c, reinterpret_cast(&c), static_cast (&c));
     

    最初の2つの出力値は同じで、最後の2つはstatic_castは、親子ポインタ変換のオフセット量を計算し、正しいアドレス(cにはm_a,m_b、B*ポインタに変換してm_bを指す)に変換し、reinterpret_castはこのレベルの変換をしません.だからreinterpretを慎重に使う必要がありますcast.
    3.c++強制変換の注意事項
    新しい変換は古い変換よりも人気があります.理由は2つあります.
  • 1は新式の転換が識別しやすく、「タイプシステムがどこで破壊されたかを見つける」過程を簡略化することができる.
  • 第二に、各転換動作の目標が狭くなるほど、コンパイラは誤った運用を診断することができる.

  • 特にdynamic_を使用しないでください.castは、時間がかかると性能が低下し、できるだけ他の方法で代替します.
    テキストリンク:https://www.cnblogs.com/chenyangchun/p/6795923.html
    参考記事:https://www.cnblogs.com/qinguoyi/p/10303912.html