C ++ 11是否具有C#风格的属性?
在C#中,对于有getter和setter的字段,有一个很好的语法糖。 而且,我喜欢自动实现的属性,允许我写
public Foo foo { get; private set; }
在C + +我必须写
private: Foo foo; public: Foo getFoo() { return foo; }
在C ++ 11中是否有这样的概念让我在这方面有一些语法糖?
不,不。
也就是说,C ++的哲学就是促进封装 。 每当你发现你的接口只是通过成员元素(“getters和setters”),再想一想。 你的课堂应该有一个有意义的接口,而不仅仅是一个松散的容器。 成员对象应该是实现细节而不是公共接口的一部分。 如果你想要一个松散的容器,只需使用一个std::tuple
或类似的东西。
在C ++中,您可以编写自己的function。 这里是使用未命名类的属性的实现。 维基文章
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; };
在这里,您可以编写自己的Getter Setter。 如果你想持有人类成员访问,你可以扩展这个示例
你可以在某种程度上通过拥有专用types的成员和覆盖operator(type)
和operator=
来模拟getter和setter。 这是一个好主意是另一个问题,我要+1
Kerrek SB的答案来expression我的意见:)
C ++没有这个内置的,你可以定义一个模板来模仿属性的function:
template <typename T> class Property { public: virtual ~Property() {} virtual T & operator = (const T &f) { return value = f; } virtual operator T const & () const { return value; } protected: T value; };
要定义一个属性 :
Property<float> x;
要实现一个自定义的getter / setter只是inheritance:
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; };
并在课堂上使用它 :
class Owner { public: class : public ReadOnlyProperty<float> { friend class Owner; } x; Owner() { x.value = 8; } };
你可以在macros中定义一些以使其更加简洁。
也许看看我在过去几个小时里汇集的属性类: 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);
正如其他人已经说过的那样,这种语言没有内置的支持。 但是,如果您的目标是Microsoft C ++编译器,则可以利用此处logging的属性的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)会很尴尬,但是您正在向这些方法的使用者声明某些function可能发生。 另一方面,在C ++中访问字段会告诉消费者不会出现额外的或意想不到的function。 属性会使这一点变得不那么明显,因为乍看之下,财产访问似乎像一个领域一样反应,但实际上却像一个方法一样起作用。
另外,我正在一个.NET应用程序(一个非常知名的CMS)尝试创build一个客户会员系统。 由于他们为用户对象使用属性的方式,所以我没有预料到这些动作会导致我的执行以奇怪的方式执行,包括无限recursion。 这是因为他们的用户对象在尝试访问像StreetAddress这样简单的东西时,调用了数据访问层或某个全局caching系统。 他们的整个体系build立在我所称的滥用财产的基础上。 如果他们使用方法而不是属性,我想我会更快地发现出了什么问题。 如果他们已经使用了田地(或者至less使他们的财产行为更像田野),我认为这个系统本来会更容易扩展和维护。
[编辑]改变了我的想法。 我度过了一个糟糕的一天,并有点咆哮。 这个清理应该更专业。
根据https://stackoverflow.com/a/23109533/404734这里是一个公共getter和私人setter的版本:;
struct Foo { class { int value; int& operator= (const int& i) { return value = i; } friend struct Foo; public: operator int() const { return value; } } alpha; };
使用C ++ 11,你可以定义一个Property类模板并像这样使用它:
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; };
这不完全是一个属性,但它做你想要的简单的方法:
class Foo { int x; public: const int& X; Foo() : X(x) { ... } };
这里的大X的行为就像public int X { get; private set; }
public int X { get; private set; }
public int X { get; private set; }
在C#语法。 如果你想要完整的属性,我首先在这里实现它们。
你可能知道,但我会简单地做到以下几点:
class Person { public: std::string name() { return _name; } void name(std::string value) { _name = value; } private: std::string _name; };
这种方法很简单,不使用巧妙的技巧,而是完成工作!
问题是有些人不喜欢在私人领域加下划线,所以他们不能真正使用这种方法,幸好对于这些人来说,这是非常简单的。 🙂
获取和设置前缀不会增加您的API的清晰度,但使其更加详细,我不认为他们添加有用的信息的原因是因为当有人需要使用API,如果API有道理,她可能会意识到它是什么没有前缀。
还有一件事,很容易理解这些是属性,因为name
不是动词。
最糟糕的情况是,如果API是一致的,而且这个人没有意识到name()
是一个访问者,并且name(value)
是一个mutator,那么她只需要在文档中查找一次就可以理解这个模式。
就像我喜欢C#一样,我不认为C ++需要属性!
你真的需要强制执行一些不variables还是只是一个逻辑分组? 如果是后者,你应该考虑把这个东西变成一个结构并直接访问成员。