C#には、ゲッターとセッターを持つフィールド用の素晴らしい構文シュガーがあります。さらに、私は私が書くことを可能にする自動実装されたプロパティが好きです
public Foo foo { get; private set; }
C ++では私は書く必要があります
private:
Foo foo;
public:
Foo getFoo() { return foo; }
C ++ 11にはそのような概念があり、これに構文糖を付けることができますか?
C#には、ゲッターとセッターを持つフィールド用の素晴らしい構文シュガーがあります。さらに、私は私が書くことを可能にする自動実装されたプロパティが好きです
public Foo foo { get; private set; }
C ++では私は書く必要があります
private:
Foo foo;
public:
Foo getFoo() { return foo; }
C ++ 11にはそのような概念があり、これに構文糖を付けることができますか?
回答:
C ++では、独自の機能を作成できます。名前のないクラスを使用したプロパティの実装例を次に示します。ウィキペディアの記事
struct Foo
{
class {
int value;
public:
int & operator = (const int &i) { return value = i; }
operator int () const { return value; }
} alpha;
class {
float value;
public:
float & operator = (const float &f) { return value = f; }
operator float () const { return value; }
} bravo;
};
独自のゲッターとセッターを適切に作成できます。また、ホルダークラスメンバーのアクセスが必要な場合は、このサンプルコードを拡張できます。
_alpha
にはプライベート変数とalpha
参照に使用します。
sizeof(Foo)
。コンパイラ/プラットフォームによっては、拡大されます。
C ++にはこれが組み込まれていません。プロパティ機能を模倣するテンプレートを定義できます。
template <typename T>
class Property {
public:
virtual ~Property() {} //C++11: use override and =default;
virtual T& operator= (const T& f) { return value = f; }
virtual const T& operator() () const { return value; }
virtual explicit operator const T& () const { return value; }
virtual T* operator->() { return &value; }
protected:
T value;
};
プロパティを定義するには:
Property<float> x;
カスタムゲッター/セッターを実装するには、単に継承します:
class : public Property<float> {
virtual float & operator = (const float &f) { /*custom code*/ return value = f; }
virtual operator float const & () const { /*custom code*/ return value; }
} y;
読み取り専用プロパティを定義するには:
template <typename T>
class ReadOnlyProperty {
public:
virtual ~ReadOnlyProperty() {}
virtual operator T const & () const { return value; }
protected:
T value;
};
そしてそれをクラスで使うにはOwner
:
class Owner {
public:
class : public ReadOnlyProperty<float> { friend class Owner; } x;
Owner() { x.value = 8; }
};
上記のいくつかをマクロで定義して、より簡潔にすることができます。
C ++言語には、すべてのプラットフォームとコンパイラで機能するものはありません。
しかし、あなたは、クロスプラットフォームの互換性を壊し、あなたは、例えば構文を使用することができるかもしれ特定のコンパイラにコミットして喜んでいる場合は、マイクロソフトのVisual C ++にあなたが行うことができます
// declspec_property.cpp
struct S {
int i;
void putprop(int j) {
i = j;
}
int getprop() {
return i;
}
__declspec(property(get = getprop, put = putprop)) int the_prop;
};
int main() {
S s;
s.the_prop = 5;
return s.the_prop;
}
あなたは、専用のタイプの部材を有するとオーバーライドすることで、ある程度ゲッターとセッターをエミュレートすることができますoperator(type)
し、operator=
それのために。それが良いアイデアかどうかは別の質問であり、私はそれ+1
について私の意見を表明するためにKerrek SBの答えに行きます:)
friend
フィールドの所有者にa を追加するだけです。
たぶん私が最後の数時間にアセンブルしたプロパティクラスを見てください:https : //codereview.stackexchange.com/questions/7786/c11-feedback-on-my-approach-to-c-like-class-properties
これにより、次のように動作するプロパティを持つことができます。
CTestClass myClass = CTestClass();
myClass.AspectRatio = 1.4;
myClass.Left = 20;
myClass.Right = 80;
myClass.AspectRatio = myClass.AspectRatio * (myClass.Right - myClass.Left);
C ++ 11では、プロパティクラステンプレートを定義して、次のように使用できます。
class Test{
public:
Property<int, Test> Number{this,&Test::setNumber,&Test::getNumber};
private:
int itsNumber;
void setNumber(int theNumber)
{ itsNumber = theNumber; }
int getNumber() const
{ return itsNumber; }
};
そして、これがPropertyクラステンプレートです。
template<typename T, typename C>
class Property{
public:
using SetterType = void (C::*)(T);
using GetterType = T (C::*)() const;
Property(C* theObject, SetterType theSetter, GetterType theGetter)
:itsObject(theObject),
itsSetter(theSetter),
itsGetter(theGetter)
{ }
operator T() const
{ return (itsObject->*itsGetter)(); }
C& operator = (T theValue) {
(itsObject->*itsSetter)(theValue);
return *itsObject;
}
private:
C* const itsObject;
SetterType const itsSetter;
GetterType const itsGetter;
};
C::*
意味?こんなの見たことない?
C
です。これは単純な関数ポインターに似ていますが、メンバー関数を呼び出すには、関数が呼び出されるオブジェクトを提供する必要があります。これはitsObject->*itsSetter(theValue)
、上記の例の行で実現されます。この機能の詳細については、こちらをご覧ください。
他の多くの人がすでに言ったように、言語には組み込みのサポートはありません。ただし、Microsoft C ++コンパイラをターゲットにしている場合は、ここに記載されているプロパティのMicrosoft固有の拡張機能を利用できます。
これはリンクされたページの例です:
// declspec_property.cpp
struct S {
int i;
void putprop(int j) {
i = j;
}
int getprop() {
return i;
}
__declspec(property(get = getprop, put = putprop)) int the_prop;
};
int main() {
S s;
s.the_prop = 5;
return s.the_prop;
}
いいえ、C ++にはプロパティの概念はありません。getThis()またはsetThat(value)を定義して呼び出すのは面倒ですが、一部の機能が発生する可能性があることをこれらのメソッドのコンシューマーに通知しています。一方、C ++でフィールドにアクセスすると、追加のまたは予期しない機能が発生しないことがコンシューマに通知されます。一見するとプロパティアクセスはフィールドのように反応するように見えますが、実際にはメソッドのように反応するため、プロパティはこれをあまりわかりにくくします。
余談ですが、私は.NETアプリケーション(非常によく知られたCMS)で作業して、顧客のメンバーシップシステムを作成しようとしていました。ユーザーオブジェクトのプロパティの使用方法が原因で、予期しないアクションが発生し、実装が無限再帰を含む奇妙な方法で実行されました。これは、StreetAddressなどの単純なものにアクセスしようとすると、ユーザーオブジェクトがデータアクセスレイヤーまたはグローバルキャッシングシステムを呼び出したためです。彼らのシステム全体は、私がプロパティの乱用と呼ぶものに基づいています。プロパティの代わりにメソッドを使用していれば、何が問題だったのかをもっと早く理解できただろうと思います。フィールドを使用した場合(または少なくともプロパティをフィールドのように動作させる場合)、システムの拡張と保守が容易になったと思います。
[編集]私の考えを変えた。私は悪い日を過ごしたし、怒りに少し行った。このクリーンアップはより専門的なものにする必要があります。
https://stackoverflow.com/a/23109533/404734に基づいて、ここにパブリックゲッターとプライベートセッターを備えたバージョンがあります。
struct Foo
{
class
{
int value;
int& operator= (const int& i) { return value = i; }
friend struct Foo;
public:
operator int() const { return value; }
} alpha;
};
これは厳密にはプロパティではありませんが、必要なことを簡単な方法で実行します。
class Foo {
int x;
public:
const int& X;
Foo() : X(x) {
...
}
};
ここで、大きなXはpublic int X { get; private set; }
C#構文のように動作します。本格的なプロパティが必要な場合は、ここに実装するための最初のショットを作成しました。
X
、新しいオブジェクトの参照は古いオブジェクトのメンバーを指します。これは、ポインターメンバーのようにコピーされるだけだからです。これ自体は悪いですが、古いオブジェクトが削除されると、その上にメモリ破損が発生します。これを機能させるには、独自のコピーコンストラクター、代入演算子、および移動コンストラクターも実装する必要があります。
あなたはおそらくそれを知っていますが、私は単に次のようにします:
class Person {
public:
std::string name() {
return _name;
}
void name(std::string value) {
_name = value;
}
private:
std::string _name;
};
このアプローチはシンプルで、巧妙なトリックを使用せず、仕事を完了させます!
ただし、プライベートフィールドの先頭にアンダースコアを付けたくない人もいるため、この方法は実際には使用できませんが、この方法を使用する人にとっては簡単です。:)
getおよびsetプレフィックスはAPIを明確にしませんが、それらをより詳細にし、有用な情報を追加しないと思う理由は、APIが理にかなっている場合に誰かがAPIを使用する必要があるとき、彼女はおそらくそれを理解するためです接頭辞なしで行います。
もう1つname
、動詞ではないため、これらがプロパティであることを理解するのは簡単です。
最悪のシナリオ、APIが一貫していて、その人がname()
アクセサーでありname(value)
ミューテーターであることに気付かなかった場合、パターンを理解するためにドキュメントで一度だけルックアップする必要があります。
C#が大好きなのと同じくらい、C ++にはプロパティがまったく必要ないと思います!
foo(bar)
(遅いの代わりにfoo = bar
)使用する場合に意味がありますが、アクセサーはプロパティとはまったく関係ありません...
foo(bar)
代わりにfoo=bar
して達成することができるvoid foo(Bar bar)
のミューテータメソッド_foo
メンバ変数。
私は複数のC ++ソースからアイデアを集め、それをC ++のゲッター/セッターの素晴らしい、まだ非常に単純な例に入れました。
class Canvas { public:
void resize() {
cout << "resize to " << width << " " << height << endl;
}
Canvas(int w, int h) : width(*this), height(*this) {
cout << "new canvas " << w << " " << h << endl;
width.value = w;
height.value = h;
}
class Width { public:
Canvas& canvas;
int value;
Width(Canvas& canvas): canvas(canvas) {}
int & operator = (const int &i) {
value = i;
canvas.resize();
return value;
}
operator int () const {
return value;
}
} width;
class Height { public:
Canvas& canvas;
int value;
Height(Canvas& canvas): canvas(canvas) {}
int & operator = (const int &i) {
value = i;
canvas.resize();
return value;
}
operator int () const {
return value;
}
} height;
};
int main() {
Canvas canvas(256, 256);
canvas.width = 128;
canvas.height = 64;
}
出力:
new canvas 256 256
resize to 128 256
resize to 128 64
ここでオンラインでテストできます:http : //codepad.org/zosxqjTX
ここに書かれたマクロのセットがあります。THisには、値型、参照型、読み取り専用型、強い型と弱い型の便利なプロパティ宣言があります。
class MyClass {
// Use assign for value types.
NTPropertyAssign(int, StudentId)
public:
...
}