2017-09-15 6 views
-1

私はポインタの助けを借りてプライベートメンバーにアクセスしようとしています。私はdtypeをなぜ(int *)& tの前に記述するのか知りたいですか?C++でクラスのプライベートメンバーにアクセスするために、オブジェクトのアドレスの前にデータ型を記述する必要があるのはなぜですか?

class Test 
{ 
private: 
    int data; 
public: 
    Test() { data = 0; } 
    int getData() { return data; } 
}; 

int main() 
{ 
    Test t; 
    int* ptr = (int*)&t; 
    *ptr = 10; 
    cout << t.getData(); 
    return 0; 
} 
+0

*** int * ptr =(int *)&t; *** –

+0

値に直接アクセスする必要がある場合は、 'data'をpublicにしてください。クラスには、 'data'にアクセスして操作するメソッドを作成することができます。独自のスコープの外部にあるクラスのメンバーを直接操作しないようにする必要があります。 –

答えて

0

(int*)&tは:

int* ptr = (int*)&t;を整数へのポインタであることへのポインタをキャスト:それはアクセス制御システムは、に適用PTR

3

におけるTのポインタを格納します。変数dataはプライベートであり、変数または関連する記憶領域ではありません。つまり、dataという名前を使用しない限り、他の方法で変数にアクセスできます。

アクセス制御の目的は、コードが誤って壊れるのを防ぐことです。encapsulation

C++は「あなた自身を吊るすに十分なロープを与える」、あるいは「Murphyを保護するがMacchiavelliは保護しない」と言われることがあります。つまり、実際にはアクセス制御をバイパスできます。 Link to related article - GotW #76

もちろん、アクセス制御をバイパスする必要がないようにコードを設計してください。


この場合、コードは明確に定義されています。 Teststandard layout classであるため、最初のデータメンバーの前にパディングがないことが保証され、also guaranteedは、このキャストが前記変数にアクセスするために使用できるt.dataへのポインタを生成することを保証します。

複雑なクラスの場合、問題のデータメンバーがオブジェクトの記憶領域の先頭から開始しないと、コードが機能しないことがあります。

0

これは偶然に始まるだけです。

Testは、継承を伴わないプリミティブクラス、RTTIサポートなしでコンパイルされた仮想メソッド、またはメモリ表現を拡張する可能性があるその他のものです。

この単純な例では、メンバー変数はオブジェクト全体と同じアドレスにあります。それはもっと複雑な何かのための未定義の振舞いなので、依存することは非常に危険です。

今すぐ継承と仮想メソッドをテストに持ち込みます。突然、あなたのオブジェクトの最初の数バイトはもはや最初のメンバ変数ではなくなります(これはコンパイラが通常VPTRを置く場所です)、ひどくクラッシュをテストします。

代わりにメンバー変数を静的変数にすると、オブジェクト自体が実際に空になり、代わりにヒープ制御構造にアクセスするため、即時クラッシュは発生しませんが、ひどいヒープ破損が発生します。この場合、tはスタックが割り当てられていたため、代わりにスタックが壊れていました(少し悪化しています)が、ヒープが割り当てられていれば、これは重要になるはずです。

関連する問題