C++のタイプ変換演算子(一)——static_castとdynamic_cast

3970 ワード

タイプ変換は、プログラマがコンパイラのオブジェクトの解釈を一時的または永続的に変更できるメカニズムです.これは、プログラマーがオブジェクト自体を変更したという意味ではなく、オブジェクトの解釈を変更しただけであることに注意してください.
多くの場合、タイプ変換は合理的なニーズであり、重要な互換性の問題を解決することができます.したがって、プログラマは、コンパイラに必要な方法でデータを解釈させ、アプリケーションが正常にコンパイルされ、実行されるようにする必要があります.
 
C++コンパイラは、残されたコードがコンパイルされることを保証するために後方互換性が必要であるため、int*pBuf=(int*)pString;
Cスタイルのタイプ変換は,実際にはプログラマの選択に基づいてターゲットオブジェクトを解釈し,コンパイラに自分の意思に従うように強制する.しかし,タイプ変換が提唱するタイプのセキュリティを破壊することを望まないC++プログラマーには受け入れられない.
 
C++は、継承の場合に特化した新しいタイプの変換演算子を提供します.この場合、C言語には存在しません.
4つのC++型演算子は次のとおりです.
static_cast
dynamic_cast
reinterpret_cast
const_cast
 
1、static_cast
①関連するタイプのポインタ間の変換
この相関タイプポインタとは、継承関係を持つクラスのポインタです.
 
static_castは基本的なコンパイルフェーズチェックを実現し、ポインタが関連タイプに変換されることを保証します.static_の使用castは、ポインタをベースクラスタイプにアップコンバートするか、派生クラスタイプにダウンコンバートすることができます.
これにより、Cスタイルのタイプ変換が改善され、C言語ではオブジェクトを指すポインタをまったく関連のないタイプに変換することができ、コンパイラはエラーを報告しません.(C言語は自由ですが、C++は用途によって異なるタイプの変換にはいくつかの制約があります)
 
注意:static_castは、実行フェーズチェックを実行せずに、ポインタタイプが関連しているかどうか(関係クラスを継承するポインタがあるかどうか)のみを検証します.(静的static変換と呼ぶ)
例:
CBase*pBase = new CBase( ) ;
CDerived*pDerived = static_cast(pBase) ;
static_castは、コンパイルフェーズでのみ変換タイプが関連しているかどうかをチェックし、実行フェーズチェックを実行しないため、上記のコードはコンパイルできますが、実行フェーズでは予期せぬ結果をもたらす可能性があります.
 
static_キャストはCスタイルのタイプ変換と似ていますが、static_castは、継承相関のあるクラスのポインタにのみ使用されます.この関係をチェックします.
したがって、
static_でcastは派生クラスを指すベースクラスポインタを派生クラスポインタに変換し,最下位の派生クラスオブジェクトは変わらず,ポインタの値も変わらず,ポインタの管轄範囲を変えただけである.すなわち,コンパイラの解釈を変えただけである.(ベースクラスポインタは実際には派生クラスのベースクラスコアのみを指す)
同じ理屈でstatic_castは派生クラスを指す派生クラスポインタをベースクラスポインタに変換し,コンパイラの解釈方式を変えただけである.(static_castペアと多重継承ポインタには、特殊な処理があります)
 
②内蔵データ型へのタイプ変換
例:
double dPi = 3.14;
int nNum =static_cast(dPi) ;
static_の使用castは、コードリーダーに、ここでタイプ変換が使用されていることに気づかせ、コンパイラがコンパイルフェーズで使用可能な情報に基づいて必要なタイプ変換を実行するために必要な調整を行ったことを指摘することができる.
 
 
2、dynamic_cast
dynamic_castダイナミックタイプ変換実行フェーズでタイプ変換を実行します.確認可能dynamic_cast操作の結果、タイプ変換が成功したかどうかを判断します.
 
dynamic_castはベースクラスポインタを派生クラスポインタに変換してもよいし、派生クラスポインタをベースクラスポインタに変換してもよい.変換後に安全に使用できる場合、変換は成功します.そうでない場合、NULLが返されます.(static_castの変換では、変換後の結果が安全に使用できるかどうかを確認できません)
 
ベースクラスポインタがベースクラスオブジェクトを指す場合はdynamic_castが派生クラスポインタである場合、変換は失敗します.これは安全ではない変換だからです.
ベースクラスポインタが派生クラスオブジェクトを指す場合はdynamic_castが派生クラスポインタであれば、変換は成功します.これは安全な変換です.(dynamic_castはstatic_castより厳しいが、使用範囲は小さい)
 
【注意】dynamic_castは虚関数のある継承で行わなければならない.(static_castではこの制限はありません)
 
ベースクラスポインタを指定すると、プログラマは現在どのタイプを指しているのか分からない場合があります.dynamic_を使用できます.castは、実行時にそのタイプを判断し、安全時に変換後のポインタを使用します.
dynamic_castという実行フェーズでオブジェクトタイプを識別するメカニズムは,実行フェーズタイプ識別RTTIとなる.
 
RTTIについて
RTTIはRuntime Type Informationの略で、文字通り実行期間のタイプ情報であり、その重要な役割は実行期間のタイプを動的に判別することである.
すなわち、ベースクラスポインタまたは参照を判断し、現在バインドされているタイプ.
識別するには2つの方法があります.
①dynamic_でcastタイプ変換がタイプを識別するのに成功したかどうか.(dynamic_castは虚関数の継承で行う必要があります)
例:
void fun(CBase* pBase)
{
    CDerived* pDerived = dynamic_cast<CDerived*>(pBase) ;
    if (pDerived != NULL)
        pDerived->funDerived ;
    else
        pDerived->funBase ;
}

②typeidでベースクラスアドレスが一致しているか否かを判断してタイプ例を識別する:
void fun(CBase* pBase)
{
    CDerived* pDerived = NULL ;
    if (typeid(*pBase) == typeid(CDerived))
    {
    pDerived = static_cast<CDerived*>(pBase) ;
    pDerived->funDerived ;
    }
    else
        pDerived->funBase ;
}

コンパイラは、クラス内の虚ポインタが指す虚関数テーブルの前のテーブル項目からtypeidの値を抽出します.(C++オブジェクトモデルの概要を参照)
 
【一般的に、虚関数で解決できる問題は「dynamic_cast」ではなく、「dynamic_cast」で解決できる問題は「typeid」ではありません.】
 
RTTIはオブジェクト向けの純潔性を破壊した.
まず抽象を破壊しましたRTTIを用いて現在のベースクラスポインタバインディングのタイプを検出し,これは虚関数が提唱する隠蔽詳細,知能実現多態とは逆である.
次に,実行時タイプの不確実性のため,プログラムをより脆弱にする.
第三に、プログラムの拡張性に欠けています.継承関係に新しいタイプを追加する場合は、RTTIに関するコードを変更する必要があります.