static_cast、dynamic_cast、reinterpret_cast、const_cast


強制型変換の問題については多くの本で議論されており、最も詳細に書かれているのはC++の父の「C++の設計と進化」である.最善の解決策は、Cスタイルの強制タイプ変換ではなく、標準C++のタイプ変換子:static_を使用することです.cast, dynamic_cast.標準C++には4種類の変換子があります:static_cast、dynamic_cast、reinterpret_cast、const_cast.それらを一つ一つ紹介します.
 
static_cast用法:static_cast(expression)この演算子はexpressionをtype-idタイプに変換しますが、実行時タイプチェックは変換の安全性を保証しません.主に次のような使い方があります.
  • は、クラス階層内のベースクラスとサブクラス間のポインタまたは参照の変換に使用されます.上り変換(サブクラスのポインタまたは参照をベースクラス表示に変換)を行うことは安全であり、下り変換(ベースクラスポインタまたは参照をサブクラス表示に変換)を行う場合、ダイナミックタイプチェックがないため安全ではない.
  • は、intをcharに変換し、intをenumに変換するなどの基本データ型間の変換に使用される.このような転換の安全性も開発者が保証しなければならない.
  • 空ポインタをターゲットタイプの空ポインタに変換します.
  • は、任意のタイプの式をvoidタイプに変換する.

  • 注意:static_キャストはexpressionのconst、volitale、または__を変換できません.unalignedプロパティ.dynamic_cast用法:dynamic_cast(expression)この演算子はexpressionをtype-idタイプのオブジェクトに変換します.Type-idは、クラスのポインタ、クラスの参照、またはvoid*でなければなりません.type-idがクラスポインタタイプの場合、expressionもポインタでなければなりません.type-idが参照の場合、expressionも参照でなければなりません.dynamic_castは主にクラス階層間の上り変換と下り変換に用いられ,クラス間の交差変換にも用いられる.クラス階層間でアップリンク変換を行う場合、dynamic_キャストとstatic_castの効果は同じです.下り変換時にdynamic_castにはstatic_よりもタイプチェック機能があります.castの方が安全です.
    class B{
    public:
     int m_iNum;
     virtual void foo();
    };
    
    class D:public B{
     public:
     char *m_szName[100];
    };
    
    void func(B *pb){
     D *pd1 = static_cast<D *>(pb);
     D *pd2 = dynamic_cast<D *>(pb);
    }

     
    上記のコードセグメントでは、pbがDタイプのオブジェクトを指す場合、pd 1とpd 2は同じであり、この2つのポインタに対してDタイプの操作を実行することは安全である.しかし、pbがB型のオブジェクトを指す場合、pd 1はそのオブジェクトを指すポインタとなり、Dタイプの操作は安全ではありません(m_szNameへのアクセスなど).pd 2は空のポインタになります.また、Bには虚関数が必要です.そうしないとコンパイルエラーが発生します.static_castにはこの制限はありません.これは、実行時タイプチェックには実行時タイプ情報が必要で、この情報はクラスの虚関数テーブルに格納されます.(虚関数テーブルの概念については)では、虚関数を定義したクラスのみが虚関数テーブルがあり、虚関数を定義していないクラスには虚関数テーブルがありません.
    また、
    dynamic_castはクロス変換(cross cast)もサポートしています.次のコードに示します.
    class A{
    public:
     int m_iNum;
     virtual void f(){}
    };
    
    class B:public A{
    };
    
    
    class D:public A{
    };
    
    void foo(){
     B *pb = new B;
     pb->m_iNum = 100;
     D *pd1 = static_cast<D *>(pb); //copile error
     D *pd2 = dynamic_cast<D *>(pb); //pd2 is NULL
     delete pb;
    }

    関数fooで、
    static_castの変換は許可されず、コンパイル時にエラーが発生します.使用する
    dynamic_castの変換は許可され、結果は空のポインタです.
    reinpreter_cast
    使用方法:
    reinpreter_cast (expression)
    type-idは、ポインタ、参照、算術タイプ、関数ポインタ、またはメンバーポインタでなければなりません.1つのポインタを1つの整数に変換したり、1つの整数を1つのポインタに変換したりすることができます(まず1つのポインタを1つの整数に変換し、その整数を元のタイプのポインタに変換したり、元のポインタ値を得ることができます).
    この演算子の使用法は比較的多い.
    const_cast
    使用方法:
    const_cast (expression)
    この演算子は、タイプのconstまたはvolatileプロパティを変更するために使用します.constまたはvolatile修飾に加えてtype_idとexpressionのタイプは同じです.
    定数ポインタは非常量ポインタに変換され、元のオブジェクトを指します.定数参照は非常量参照に変換され、元のオブジェクトを指します.定数オブジェクトが非常量オブジェクトに変換されます.
    Voiatileとconstクラスのテスト.次の例を挙げます.
    class B{
    public:
     int m_iNum;
    }
    
    void foo(){
      const B b1;
      b1.m_iNum = 100; //comile error
      B b2 = const_cast<B>(b1);
      b2. m_iNum = 200; //fine
    }

    上のコードのコンパイル時にエラーが発生します.b 1は定数オブジェクトなので、変更できません.const_の使用castはそれを定数オブジェクトに変換し、そのデータメンバーを任意に変更することができます.注意:b 1とb 2は2つの異なるオブジェクトです.