C ++のプロパティ

おそらく、C#など、他の言語を使用したC ++言語のすべてのファンは驚いています:プラスにプロパティがないのはなぜですか? 結局のところ、これはクラスメンバーへのアクセスを完全に制御できる便利なツールです。 最近、私はこの問題に興味を持ちました。 考えて、Straustrupを見て、最後にグーグルで調べて、言語を使用してプロパティを実装できるという結論に達しました。 マイクロソフトなど、さまざまな実装をすでに多く見ていると思いますが、誰かにとっては、これが興味深い発見になることを願っています。

この記事には、テンプレートを使用してプロパティを実装するための可能なオプションの1つがあります。



問題の声明



そもそも、何を望むかを決めます。 ただし、書き込みと読み取りの両方で、括弧なしで、ドット(ウェル、または->)を介してオブジェクトの通常のフィールドとしてプロパティにアクセスする必要があります。 つまり、このように:



a.property = value;

MyClass var = a.property;







この場合、私たちが定義したsetterおよびgetter関数を呼び出す必要があります。 また、できるだけシンプルで明確なプロパティをクラスで定義したいと思います。



実装



a.propertyが定義したPropertyクラスのインスタンスである場合、=演算子をオーバーロードしてセッターを取得し、キャスト演算子を取得してゲッターを取得できることがわかります。 このクラス自体は、任意のタイプのプロパティの使用を許可するための定型である必要があります。

各プロパティにクラスを実装しないために、オーバーロードされた演算子は、コンストラクターでプロパティに渡されたポインターを使用して関数を呼び出す必要があります。

使用するために、型Propertyの変数をクラスのパブリックフィールドとして宣言し、テンプレートの最初のパラメーターとして必要な型と、コンストラクターのパラメーターの関数へのポインターを渡します。



これらすべてが実装されたとき、私はこのプロパティのもう1つの優れた機能を思い出しました。読み取り専用にすることができます。 これに先立ち、セッターとゲッターを持つ完全なプロパティのみが考慮されました。 また、コンパイル段階で読み取りおよび書き込み権限を確認することが重要です。 ここでは、テンプレートの専門化が役立ちます。 3つの異なるクラスを実装できます(読み取りと書き込み、読み取り専用、書き込み専用)。テンプレートパラメータが異なる同じ名前のプロパティ、いわゆる特殊化。 最終的な実装は次のようになります。

 #pragma once #define NULL 0 class ReadOnly; class WriteOnly; class ReadWrite; template <typename Type, typename Owner,typename Access> class Property { }; template<typename Type, typename Owner> class Property<typename Type, typename Owner, ReadWrite> { protected: typedef Type (Owner::*getter)(); typedef void (Owner::*setter)(Type); Owner * m_owner; getter m_getter; setter m_setter; public: //   .  . operator Type() { return (m_owner->*m_getter)(); } //  .  . void operator =(Type data) { (m_owner->*m_setter)(data); } Property() : m_owner(NULL), m_getter(NULL), m_setter(NULL) { } Property(Owner * const owner, getter getmethod, setter setmethod) : m_owner(owner), m_getter(getmethod), m_setter(setmethod) { } void init(Owner * const owner, getter getmethod, setter setmethod) { m_owner = owner; m_getter = getmethod; m_setter = setmethod; } }; template<typename Type, typename Owner> class Property<typename Type, typename Owner, ReadOnly> { protected: typedef Type (Owner::*getter)(); Owner * m_owner; getter m_getter; public: //   .  . operator Type() { return (m_owner->*m_getter)(); } Property() : m_owner(NULL), m_getter(NULL) { } Property(Owner * const owner, getter getmethod) : m_owner(owner), m_getter(getmethod) { } void init(Owner * const owner, getter getmethod) { m_owner = owner; m_getter = getmethod; } }; template<typename Type, typename Owner> class Property<typename Type, typename Owner, WriteOnly> { protected: typedef void (Owner::*setter)(Type); Owner * m_owner; setter m_setter; public: //  .  . void operator =(Type data) { (m_owner->*m_setter)(data); } Property() : m_owner(NULL), m_setter(NULL) { } Property(Owner * const owner, setter setmethod) : m_owner(owner), m_setter(setmethod) { } void init(Owner * const owner, setter setmethod) { m_owner = owner; m_setter = setmethod; } };
      
      







使用する



次のように使用できます。

ファイルTestClass.h

 #pragma once #include "Property.h" class TestClass { public: TestClass(void); ~TestClass(void); void _setterRW(int a); int _getterRW(); Property<int, TestClass, ReadWrite> testRW; int _getterRO(); Property<int, TestClass, ReadOnly> testRO; void _setterWO(int a); Property<int, TestClass, WriteOnly> testWO; private: int propRW; int propRO; int propWO; };
      
      







TestClass.cppファイル



 #include "TestClass.h" TestClass::TestClass(void) { testRW.init(this, &TestClass::_getterRW, &TestClass::_setterRW); testRO.init(this, &TestClass::_getterRO); propRO = 123; testWO.init(this, &TestClass::_setterWO); } int TestClass::_getterRW() { return propRW; } void TestClass::_setterRW(int a) { propRW = a; } int TestClass::_getterRO() { return propRO; } void TestClass::_setterWO(int a) { propWO = a; } TestClass::~TestClass(void) { }
      
      







ファイルmain.cpp

 #include "TestClass.h" #include "stdio.h" int main() { TestClass t; t.testRW = 15; int a = t.testRW; t.testWO = 34; //a = t.testWO; //:  WriteOnly property //t.testRO = 45; //:   ReadOnly property printf("RW = %d\n", int(t.testRW)); printf("RO = %d\n", int(t.testRO)); scanf("%d", a); return 0; }
      
      





おわりに



この実装は私に合っていますが、いくつかの理由で好きではありません。 1つ目は、プロパティが属するクラスを指定する必要があることです。 2つ目は、コンストラクター内、つまり実行時に各プロパティを初期化する必要があることです。 3つ目は、静的プロパティを作成できないことです。 さて、4番目の重要度は低い:ヒントはタイプPropertyを示しており、そこに書いたものではなく、最初にそれを目にした人からの質問を引き起こすかもしれません。 また、クラスメソッドへのポインターのトピックは非常に曖昧で、あまり公開されておらず、ほとんど使用されていません。 ここではよく説明されていますが、最も重要なことは、それらを非常に慎重に使用する必要があることに気づいたことです。

使用するほど直感的ではないことがわかりましたが、目標は達成されました。



使用した材料:

www.rsdn.ru/article/vcpp/props.xml-主なアイデア。

www.rsdn.ru/forum/cpp/854559.1.aspx-アクセス権を持つアイデア。

rsdn.ru/article/cpp/fastdelegate.xml-C ++のクラスの関数およびメソッドへのポインターの詳細な説明。



ここに例のあるソース。

Visual Studio 2008プロジェクトはこちら



このテキストはCC-BYライセンスの下で公開されています。



元の記事はこちらにあります トピックはhabranographyにとって興味深いものであり、記事が最初に公開されたサイトはホスティングのために訪問者のわずかな流入にも耐えることができないため、コピーペーストは意識的に行われました。



All Articles