3

私はC++のいくつかのコードを調べていました。reinterpret_cast演算子の概念に出くわした場所。

編集1:

クラスのプライベート メンバーへのアクセスはお勧めできません。 しかし、状況によっては、先に進んでそれらにアクセスする必要があります。 私の概念を明確にするために、この質問を出しました。

私が参照した例では、クラスのプライベート メンバーは、同じ変数を持つ構造体を作成するだけでアクセスされ、後で reinterpret_cast演算子を実装することによって変更されます。

reinterpret_cast演算子の使い方は理解しましたが、それが何をするかはわかっていますが、構造体を使用してプライベート クラス メンバーの値を変更する方法を理解できません。

以下は私が参照したソースコードです。

クラス:

class Student
{
public:
    explicit Student(float percent) // Cannot be used for conversion
    {
        static int nid;

        id = ++nid;
        score = percent;
    }

    int Id() const
    {
        return id;
    }

    float GetScore() const
    {
        return score;
    }

    void SetScore(float value)
    {
        score = value;
    }

    virtual ~Student(){}

private:
    int id;
    float score;
};

プライベート クラス メンバーへのアクセスと変更に使用される構造:

struct _Student
    {
        void* vptr;
        int id;
        float score;
    };

    _Student* bs3 = reinterpret_cast<_Student*>(bs2);
    bs3->id = 5;

ありがとうございます。間違っていたら訂正してください/適切な方法で質問をすることができませんでした.

4

5 に答える 5

3

$5.2.10/2 - 「整数型、列挙型、ポインター型、またはメンバーへのポインター型の式は、それ自体の型に明示的に変換できます。 そのようなキャストは、そのオペランドの値を生成します。

これは、ポインター 'bs2' と 'bs3' が同じ場所を指していることを意味します。

$9.2/16 - 「2 つの標準レイアウト構造体 (条項 9) 型は、同じ数の非静的データ メンバーを持ち、対応する非静的データ メンバー (宣言順) がレイアウト互換型 (3.9 )」

これは、クラスと構造体がレイアウト互換であることを意味します。

$9/6-

標準レイアウト クラスは、次のようなクラスです。

— 非標準レイアウト クラス (またはそのような型の配列) 型または参照型の非静的データ メンバーを持たない、

— 仮想関数 (10.3) も仮想基本クラス (10.1) もありません。

— すべての非静的データメンバーに対して同じアクセス制御 (条項 11) を持ちます。

— 非標準レイアウトの基本クラスはありません。

— 最も派生したクラスに非静的データ メンバーがなく、非静的データ メンバーを持つ基本クラスが最大 1 つないか、非静的データ メンバーを持つ基本クラスがないか、および

— 最初の非静的データ メンバーと同じ型の基底クラスを持たない.108

クラスには仮想デストラクタがあるため、クラスと構造体は標準レイアウト クラスではありません。

ただし、「vptr」を処理する可能性のある「void *」データ メンバーを追加しました (それにより、特定のコンパイラの実装に基づいてレイアウトの互換性を模倣する可能性があります)。

この場合、クラス ポインタ (bs2) を構造体ポインタ (bs3) として解釈するために reinterpret_cast が使用されます。デフォルトでは、構造体メンバーは public です。reinterpret キャストの戻り値は、クラス メンバーが配置されている同じメモリ (上記の引用を参照) を指すため、構造体メンバー (元のクラス メンバーと同じ) を変更できます。

これは不正行為です。これは非常にお勧めできません。これは、未定義の動作につながる可能性が最も高いです

于 2010-09-29T09:40:49.410 に答える
3

しかし、状況によっては、先に進んでそれらにアクセスする必要があります。

そして、祈ってください、これらの状況は何ですか?

設計ミス以外は見当たりません。プライベート メンバーへのアクセスは禁止されています。アクセスが必要な場合は、合法的な手段で提供します。つまり、メンバーをよりアクセスしやすくするか、friend修飾子を使用して制御された方法でアクセスします。

C++ の型チェック システムに違反すると、ゲーム オーバーになります。この種の未定義の動作 (つまり、プラットフォームに依存するだけでなく、正当な理由で禁止されている) を使用すると、追跡が非常に困難なバグという形でトラブルを招くだけです。

tl;dr : しないでください。これまで。

警告: 例外が 1 つあります。ソース コードにアクセス/変更できないライブラリがあり、そのインターフェイス デザインに影響を与える方法がない場合です。さらに、それが決して変わらないことを (どのように?) 確信することができます。この場合、唯一の解決策は、そのようなトリックでライブラリをハックすることです。

于 2010-09-29T10:00:55.727 に答える
2

質問の文脈を少し変えたほうがいいと思います。クラスのプライベート変数にアクセスする必要があることに気付いた場合は、安全でない型変換を使用してハッキングするのではなく、解決する必要がある設計上の問題に直面しています。それが単なる仮説であり、ここで reinterpret_cast について尋ねるためであっても.

意味のある reinterpret_cast の使用例については、ハッシュ関数内で次のように言います。

unsigned short Hash( void *p ) {

unsigned int val = reinterpret_cast<unsigned int>( p );
return ( unsigned short )( val ^ (val >> 16));

}

役立つ情報へのリンク:

static_cast、dynamic_cast、const_cast、および reinterpret_cast はいつ使用する必要がありますか?

http://advancedcppwithexamples.blogspot.com/2010/02/reinterpretcast-in-c.html

http://www.linuxtopia.org/online_books/programming_books/thinking_in_c++/Chapter03_054.html

于 2010-09-29T10:37:49.070 に答える
1

あなたが持っているのは、カプセル化に関する恐ろしいハックです。本当にプライベート変数にアクセスしたい場合は、「friend」キーワードを使用する必要があります。reinterpret_cast が機能する理由は、クラス Student のバイトを struct _Student として解釈しているためです。これには、デフォルトで変数が public として宣言されています。プライベート データにアクセスするには、さまざまな方法があります。

int* bs3 = reinterpret_cast<int*>(bs2);
++bs3;
*bs3 = 5;

それをしないでください、それは私のアドバイスです。

于 2010-09-29T10:14:49.953 に答える
1

しかし、状況によっては、先に進んでそれらにアクセスする必要があります。

どのような状況でもそれらにアクセスする必要がある場合は、そのアクセス仕様を変更してください。

または、トークン (またはいくつかの特別なアクセス許可 - 呼び出し元を検証する) を受け入れるパブリック メソッドを作成し、要求された値を返します。

于 2010-09-29T09:49:49.173 に答える