C ++ 11是否具有C#风格的属性?

时间:2011-12-03 14:59:04

标签: c# c++ class c++11

在C#中,对于具有getter和setter的字段,有一个很好的语法糖。此外,我喜欢自动实现的属性,允许我写

public Foo foo { get; private set; }

在C ++中我必须写

private:
    Foo foo;
public:
    Foo getFoo() { return foo; }

在C ++ 11中是否有一些这样的概念允许我对此有一些语法糖?

15 个答案:

答案 0 :(得分:74)

在C ++中,您可以编写自己的功能。 以下是使用未命名类的属性的示例实现。 Wiki article

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到位,如果你想持有者类成员访问,你可以扩展这个示例代码。

答案 1 :(得分:41)

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;

要实现自定义getter / setter ,只需继承:

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; }
};

您可以在中定义上述内容,以使其更简洁。

答案 2 :(得分:18)

您可以通过拥有专用类型的成员并覆盖operator(type)operator=来在某种程度上模拟getter和setter。这是一个好主意是另一个问题,我将+1 Kerrek SB回答我的意见:)

答案 3 :(得分:18)

C ++语言中没有任何内容适用于所有平台和编译器。

但是如果你愿意打破跨平台兼容性并提交给特定的编译器,你可以使用这样的语法,例如你可以做in Microsoft 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;  
}

答案 4 :(得分:17)

也许看看我在过去几小时内收集的属性类: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);

答案 5 :(得分:16)

使用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;
};

答案 6 :(得分:14)

正如其他许多人已经说过的那样,语言中没有内置的支持。但是,如果您的目标是Microsoft C ++编译器,则可以利用特定于Microsoft的属性扩展来记录here.

这是链接页面的示例:

// 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;
}

答案 7 :(得分:12)

不,C ++没有属性概念。虽然定义和调用getThis()或setThat(value)可能很尴尬,但是您正在向消费者声明某些功能可能会发生的方法。另一方面,访问C ++中的字段告诉消费者不会发生其他或意外的功能。属性会使这一点变得不那么明显,因为乍看之下的属性访问似乎像字段一样反应,但实际上反应就像一个方法。

另外,我正在尝试创建客户会员系统的.NET应用程序(一个非常着名的CMS)中工作。由于他们使用属性作为用户对象的方式,我没有预料到的操作被激活,导致我的实现以奇怪的方式执行,包括无限递归。这是因为他们的用户对象在尝试访问像StreetAddress这样的简单事物时调用了数据访问层或某个全局缓存系统。他们的整个系统建立在我称之为滥用财产的基础之上。如果他们使用方法而不是属性,我想我会更快地弄清楚出了什么问题。如果他们使用了字段(或者至少使他们的属性更像字段),我认为系统将更容易扩展和维护。

[编辑]改变了我的想法。我有一个糟糕的一天,并有点咆哮。这种清理应该更专业。

答案 8 :(得分:11)

基于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;
};

答案 9 :(得分:5)

您可能知道,但我会简单地执行以下操作:

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)是一个变异者,那么她只需要在文档中查找一次了解模式。

尽管我喜欢C#但我认为C ++根本不需要属性!

答案 10 :(得分:4)

这不是一个属性,但它以你想要的方式做到了简单的方法:

class Foo {
  int x;
public:
  const int& X;
  Foo() : X(x) {
    ...
  }
};

这里的大X在C#语法中表现得像public int X { get; private set; }。如果你想要完整的属性,我第一次实现它们here

答案 11 :(得分:4)

都能跟得上.. 但是你应该考虑它是否只是得到:set function并且在get中没有执行任何额外的任务:set方法只是让它公开。

答案 12 :(得分:1)

你的课真的需要强制执行一些不变量,还是只是成员元素的逻辑分组?如果是后者,你应该考虑将这个东西作为结构并直接访问成员。

答案 13 :(得分:1)

我从多个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

答案 14 :(得分:0)

有一组写为Here的宏。这具有用于值类型,引用类型,只读类型,强类型和弱类型的方便的属性声明。

class MyClass {

 // Use assign for value types.
 NTPropertyAssign(int, StudentId)

 public:
 ...

}