2012-02-07 10 views
1

おはようございます!C++:オブジェクトのプロパティエミュレーション:思考

プロパティはC++では実装されていません。私たちが書くことはできません。

myObject.property = value; // try to set field f_ to value 

propertyは私的なデータメンバーです。パブリックデータメンバーはOOPカプセル化ルールに違反します。

代わりに、私たちは、ゲッター/セッターのコードを記述する必要があります。

myObject.setField(value); // try to set field f_ to value 

この投稿は、C++約プロパティエミュレーションです。 プロパティ呼び出しはパブリックデータメンバー呼び出しのように見えますが、カスタムUDFコードは実際のプライベートデータメンバー値を設定または取得するために使用されます。

は、単純なインターフェイス使用(関数呼び出し構文のようなパブリックデータメンバーのような)を可能にしますが、基礎となるgetter/setterは複雑です(データ割り当て/読み取りのみを行う)です。

次のコード(私の同僚が書いた)単純なプロパティの実装を提示:

#include <iostream> 

template<class C, class M> 
inline C* get_parent_this(typename M C::*member_ptr, M*const member_this) 
{ 
    //interpret 0 as address of parent object C and find address of its member 
    char* base = reinterpret_cast<char*>(nullptr); 
    char* member = reinterpret_cast<char*>(&(reinterpret_cast<typename C*>(base)->*member_ptr)); 
    //modify member_this with offset = (member - base) 
    return reinterpret_cast<typename C*>(reinterpret_cast<char*>(member_this) - (member - base)); 
} 

class Owner 
{ 
    int x,pr_y; 

    int get_y()  {return pr_y;} 
    void set_y(int v) {pr_y = v;} 
public: 
    struct 
    { 
     operator int()   { return get_parent_this(&Owner::y, this)->get_y(); } 
     void operator =(int v) { get_parent_this(&Owner::y, this)->set_y(v); } 
    } y; 
}; 

int main() 
{ 
    Owner ow; 
    ow.y = 5; 
    std::cout << ow.y; 

    if(get_parent_this(&Owner::y, &ow.y) == &ow) std::cout << "OK\n"; 
    if((char *)&ow.y != (char *)&ow) std::cout << "OK\n"; 

    return 0; 
} 

シンプルなゲッター/セッターのペアは、その上の例ではありますが、追加の仕事をしていない(例えば整合性チェックまたは境界チェック)ですが、このコードは境界チェック、完全性チェックなどの複雑な処理になる可能性があります。 これはテスト例です。

get_parent_thisヘルパーテンプレートの「奇妙な」コードは心配しないでください。最も恐ろしいことは、オフセット計算です。 nullptr(NULL、0x0)アドレスはスタブとして使用されます。私たちはこのアドレスに書いたり読んだりしません。サブオブジェクトアドレスに基づいて、オーダーオブジェクトのオフセット計算をにのみ使用します。 0x0の代わりに任意のアドレスを使用できます。だから、これは意味をなさない。


プロパティの使用:

  1. 誰かが使用している場合は、パブリックデータメンバーのプロパティは、場合に役立つかもしれない: 1.1。何かが間違っているとパブリックデータメンバーのコールを追跡する。 1.2。パブリックデータメンバーの使用に基づいた痛みを伴わないレガシーコードをアップグレードする。

  1. あなたは、C++でのプロパティのエミュレーションについてどう思いますか?活発なアイデアですか?このアイデアには欠点がありますか(ショー、どうぞ)?
  2. サブオブジェクトアドレスからオーナーオブジェクトのアドレス計算についてどう思いますか?あなたが知っている技術と潜在的な落とし穴は何ですか?

あなたのご意見をお聞かせください。

ありがとうございました!

+4

私は本当に理解していません。パブリックデータメンバーの問題は何ですか? – pmr

+1

幸運にも、慣用的なC++では、あなたが考えるかもしれないように、「プロパティ」もゲッターもセッターも全く必要でないことがよくあります。 –

+0

2度目の読書で、これは私がしばらく読んだ中で最も恐ろしいコードでなければなりません。 「悪い」ではなく、深い実在の不安を引き起こすという意味で、ただ「恐ろしい」ことを心に留めてください。 –

答えて

2

コードがいくつかの明白な理由でコンパイルに失敗します。 typenameSのほとんどは不要です。私はnullptrいくつかの自家製だと思います #define(これは確かにC++ 11 nullptrではありません)。

#include <iostream> 

template<class C, class M> 
inline C* get_parent_this(M C::*member_ptr, M* const member_this) 
{ 
    C* base = NULL; 
    // !!! this is the tricky bit !!! 
    char* member = reinterpret_cast<char*>(&(base->*member_ptr)); 
    return reinterpret_cast<C*>(reinterpret_cast<char*>(member_this) - member); 
} 

class Owner 
{ 
    int x, pr_y; 
    virtual int get_y()  {return pr_y;} 
    void set_y(int v) {pr_y = v;} 
public: 
    struct 
    { 
    operator int()   { return get_parent_this(&Owner::y, this)->get_y(); } 
    void operator =(int v) { get_parent_this(&Owner::y, this)->set_y(v); } 
    } y; 
}; 

トリッキーなビットを:これは、ヌル・ポインタの間接参照を必要とする。ここ

は、それが簡単に実際に何が起こっているか を確認することができ清書、コンパイルしたバージョンです。この は、stddef.hのマクロoffsetofが をいくつかのコンパイラで定義されているように使用しています。これは確実に一部のコンパイラ で動作しますが、未定義の動作です。ここでは、トピックに関する 議論にいくつかのリンクです:

私はそれがここでの議論を繰り返す価値があるとは思いません。私は本当に コードがあなたを購入しているのを見ていない、難読化された公開のほかに データ。 setterが本当に必要な場合は、 の代わりに書きます。あなたのコーディングスタイルが公開データ の固有の理由で禁止されている場合は、それらを定義する一連のマクロを記述します。

+0

データを公開することはできません。 – DaddyM

+0

@DaddyMそうだとしたら。私はあなたと議論するつもりはない。私はあなたが投稿した混乱のコンパイルされた、よりクリーンなバージョンを与えて、それが欠陥であることを指摘しました。足で自分を撃ってしまうのはあなた次第です。 – pmr

+0

落ち着いてください。私はあなたの助けに感謝します。 – DaddyM

1

参照オブジェクトはすでにワームの缶になっています。問題は、次のとおりです。

  • 彼らは、そのようなy = max(y, myobject.y)
  • としてあなたはoperator.をオーバーロードすることができない、型推論を妨げるので、このようなクラスをプロキシすることは、ソートswap(object1.y, object2.y)
  • 驚きかなり面倒です。

あなたの使い方にはさらなる驚きがあります。たとえば、ゲッターの副作用を呼び出す場合は、単にmyobject.y;と書いてください。実際にはintへのキャストを呼び出す必要があります。

プロパティをエミュレートする必要があると思われる理由を説明することができない限り、「do not do do」以外のアドバイスを得ることはできません。 (そして、それでもなお、アドバイスは、なぜあなたが本当にそれを必要としないのかを説明するために傾斜している可能性があります)

+0

構成的。ありがとう – DaddyM

関連する問題