この記事は、C ++での型変換を理解したい人を対象としています。
したがって、次の継承階層があります。
#include <iostream> struct A{ A():a(0), b(0){} int a; int b; }; struct B : A{ B():g(0){} int g; }; struct D{ D():f(0){} float f; }; struct C : A, D{ C():d(0){} double d; };
この図は、継承の階層とメモリ内の相続人のデータメンバーの場所を示しています。
小さな余談:なぜ型変換がそれほど重要なのですか? 労働者と農民の観点から言えば、タイプXのオブジェクトをタイプYのオブジェクトに割り当てる場合、タイプXのオブジェクトが割り当てた後の値を決定する必要があります。
static_castを使用して始めましょう:
int main(){ C* pC = new C; A* pA = pC; D* pD = static_cast<D*> (pC); std::cout << p << " " << pD << " " << pA << std::endl; return 0; }
ポインター値を出力するとき、なぜこれが効果なのですか(ポインター値は変数があるアドレスです)? 実際、static_castはポインターシフトを生成します。
例を考えてみましょう:
D* pD = static_cast<D*> (pC);
1. C *からD *への型変換が発生します。 この結果は、タイプD *(tempDと呼びます)のポインターであり、クラスDから継承されたクラスCのオブジェクト内の部分を指します(pC自体の値は変更されません!)。
2.ここで、ポインターpDにtempDポインターの値を割り当てます(すべてが適切で、タイプは同じです)。
合理的な質問:なぜ実際にポインターを移動する必要があるのですか? 簡単に言えば、クラスD *へのポインターはクラスDの定義によって導かれます。バイアスがない場合、ポインターDを介して変数の値を変更すると、クラスDから継承した変数に属さないクラスCのオブジェクトの変数を変更します(ポインターpD pCと同じ意味を持ち、pD-> fが逆になったとき、実際に変数を操作します
a)。
結論:static_castは、クラス階層で作業する場合、ポインターを介してクラス変数にアクセスできるようにポインターの値を決定します。
static_castの欠点について話しましょう。 同じ継承の階層に戻りましょう。
次のコードを検討してください。
int main(){ C* pC = new C; A* pA = static_cast<A*>(pC); D* pD = static_cast<D*> (pC); B* pB = static_cast<B*> (pA); std::cout << &(pB->g) << " " << pD << " " << pA << std::endl; pB->g = 100; std::cout << pC->a << " " << pC->b << " " << pC->f << std::endl; return 0; }
pC-> fが0以外の値を持っているのはなぜですか? コードを1行ずつ検討します。
- ヒープでは、メモリはタイプCポインタの下に割り当てられます。
- アップコンバージョンが行われます。 ポインタpAはpCと同じ意味を持ちます。
- アップコンバージョンが行われます。 ポインターpDの値は、ポインターpCが指すクラスCのオブジェクト内の変数fのADDRESSです。
- ダウンコンバージョンがあります。 ポインターpBは、ポインターpAと同じ意味を持ちます。
危険はどこですか? 実際、この実施形態では、pBポインターは、pAが指すオブジェクトがタイプBのオブジェクトであると本当に信じていました。 はクラスA)の継承者ですが、pAが指すオブジェクトが実際にタイプBのオブジェクトであることを検証しません。
危険そのもの:
ポインターpBを介して変数gに書き込みたい場合(pBはB型のオブジェクトを指していることを完全に確信しているため)、実際にデータをクラスDから継承した変数fに書き込みます。さらに、ポインターpDは変数に書き込まれた情報を解釈しますf、フロートのように、coutを介して出力するときに表示されます。
そのような問題を解決する方法は?
これを行うには、dynamic_castを使用します。これは、クラス階層の有効性だけでなく、ポインターがキャストする型のオブジェクトを指していることも確認します。
このようなチェックを可能にするには、クラスに仮想性を追加します(dynamic_castは仮想関数テーブルを使用してチェックを行います)。
同じクラス階層での問題の解決策のデモンストレーション:
int main(){ C* pC = new C; A* pA = pC; if(D* pD = dynamic_cast<D*> (pC)) std::cout << " OK " << std::endl; else std::cout << " not OK " << std::endl; if(B* pB = dynamic_cast<B*> (pA)) std::cout << " OK " << std::endl; else std::cout << " not OK " << std::endl; return 0; }
コードを実行し、操作を確認することをお勧めします
B* pB = dynamic_cast<B*> (pA)
それは機能しません(pAがdynamic_castをチェックして判定をレンダリングしたタイプCのオブジェクトを指しているため)。
リンクは提供していません。ソースは個人的な経験です。
みんなありがとう!