6

この質問の議論から、フードの下でC++に実装されているプラ​​イベート変数へのアクセスはどのようになっていますか? 私はバリエーションを提示しました: プライベート データ メンバーにアクセスする代わりに、キャストとレイアウト互換性に依存してプライベート メンバー関数を呼び出すことができますか?

いくつかのコード (Herb Sutter のコラムUses and Abuses of Access Rights に触発されたもの)

#include <iostream>

class X 
{ 
public:
  X() : private_(1) { /*...*/ }

private: 
  int Value() { return private_; }
  int private_; 
};

// Nasty attempt to simulate the object layout
// (cross your fingers and toes).
//
class BaitAndSwitch
    // hopefully has the same data layout as X
{   // so we can pass him off as one
public:
  int Value() { return private_; }
private:
  int private_;
};

int f( X& x )
{
  // evil laughter here
  return (reinterpret_cast<BaitAndSwitch&>(x)).Value();
}

int main()
{
    X x;
    std::cout << f(x) << "\n"; // prints 0, not 1
    return 0;
}; 

注: これは動作します (少なくとも Ideone では)! 新しいC++11 標準が、レイアウトの互換性と reinterpret_cast / static_cast に依存することによって、アクセス制御を回避する保証された、または少なくとも実装定義の方法を提供する方法はありますか?

EDIT1 : Ideoneでの出力

EDIT2 : Sutter のコラムで、彼は上記のコードが動作することが保証されていない理由を 2 つ挙げています (実際には動作しますが)。

a) X と BaitAndSwitch のオブジェクト レイアウトが同じであるとは限りませんが、実際には常に同じである可能性があります。

b) reinterpret_cast の結果は未定義ですが、ほとんどのコンパイラでは、ハッカーが意図した方法で結果の参照を使用しようとすることができます。

新しい C++11 標準では、これらのレイアウト / reinterpret_cast の保証が提供されるようになりましたか?

4

1 に答える 1

3

はい、盗もうとしているタイプと同じレイアウトを使用するタイプを作成し、reinterpret_castそのタイプからレイアウト互換タイプに作成できます。ただし、これは、ソース タイプと宛先タイプの両方が標準レイアウト タイプである場合にのみ、標準によって保護されます (もちろん、レイアウトが同じ場合にのみ実際に機能します)。したがって、ソースに仮想関数が含まれていると、うんざりします。

これは、ここでのサッターの問題の両方を満たしているようです。標準レイアウトの規則により、同じメンバーを同じ順序で定義する両方とも標準レイアウトである 2 つのタイプがレイアウト互換性があることが保証されます (セクション 9.2、パラグラフ 17)。

2 つの標準レイアウト構造体 (条項 9) 型は、同じ数の非静的データ メンバーを持ち、対応する非静的データ メンバー (宣言順) がレイアウト互換型 (3.9) を持っている場合、レイアウト互換性があります。

reinterpret_castまた、 2 つの標準レイアウト タイプ間の変換の意味を指定するための規則(セクション 5.2.10、パラグラフ 7):

オブジェクト ポインターは、別の型のオブジェクト ポインターに明示的に変換できます。「T1 へのポインター」型の prvalue v が「cv T2 へのポインター」型に変換されるとき、結果はstatic_cast<cv T2*>(static_cast<cv void*>(v))、T1 と T2 の両方が標準レイアウト型 (3.9) であり、T2 のアライメント要件がそれらより厳密でない場合です。 T1 の、またはいずれかの型が void の場合。

于 2012-07-15T18:26:30.737 に答える