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

C++;11是否具有C#风格的属性?,c#,c++,class,c++11,C#,C++,Class,C++11,在C#中,对于带有getter和setter的字段,有一个很好的语法。此外,我喜欢自动实现的属性,它允许我编写 public Foo foo { get; private set; } private: Foo foo; public: Foo getFoo() { return foo; } 在C++中,我必须写< /P> public Foo foo { get; private set; } private: Foo foo; public: Foo

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

public Foo foo { get; private set; }
private:
    Foo foo;
public:
    Foo getFoo() { return foo; }
在C++中,我必须写< /P>
public Foo foo { get; private set; }
private:
    Foo foo;
public:
    Foo getFoo() { return foo; }

C++11中是否有这样的概念允许我在这方面使用一些语法糖?

您可以在某种程度上模拟getter和setter,方法是使用专用类型的成员,并为其重写
操作符(type)
操作符=
。这是否是一个好主意是另一个问题,我将用Kerrek SB的答案来表达我的观点:)

类是否真的需要强制一些不变量,或者它只是成员元素的逻辑分组?如果是后者,您应该考虑将其构造为一个结构并直接访问成员。

可能查看一下我在最近几个小时组装的属性类:

它允许您具有如下行为的属性:

CTestClass myClass = CTestClass();

myClass.AspectRatio = 1.4;
myClass.Left = 20;
myClass.Right = 80;
myClass.AspectRatio = myClass.AspectRatio * (myClass.Right - myClass.Left);
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; }
};

<>不,C++没有属性概念。尽管定义和调用getThis()或setThat(value)可能会很尴尬,但您正在向这些方法的使用者声明可能会出现某些功能。另一方面,访问C++中的字段告诉消费者不会出现额外或意外的功能。属性会使这一点变得不那么明显,因为属性访问乍看起来像是字段,但实际上像是方法

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


[编辑]改变了我的想法。我度过了糟糕的一天,有点大发雷霆。这个清理应该更专业。在C++中,你可以编写自己的特性。 下面是使用未命名类实现属性的示例

您可以编写自己的getter和setter,如果您想要holder类成员访问权限,可以扩展此示例代码。

基于此,这里有一个带有公共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;
};

这不完全是一个属性,但它可以通过简单的方式实现您想要的功能:

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

在这里,大X的行为类似于C#语法中的
public int X{get;private set;}
。如果您想要完整的属性,我首先尝试实现它们。

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

您可以在宏中定义上述部分,使其更加简洁。

正如许多其他人所说,该语言中没有内置支持。但是,如果您瞄准的是微软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;
}

你可能知道,但我只想做以下几件事:

class Person {
public:
    std::string name() {
        return _name;
    }
    void name(std::string value) {
        _name = value;
    }
private:
    std::string _name;
};
这种方法很简单,不使用任何巧妙的技巧,而且可以完成任务

但问题是,有些人不喜欢在他们的私有字段前面加下划线,因此他们不能真正使用这种方法,但幸运的是,对于这样做的人来说,这种方法非常简单。:)

get和set前缀并没有为API增加清晰度,但会使它们更加冗长。我认为它们没有添加有用信息的原因是,当有人需要使用API时,如果API有意义,她可能会意识到没有前缀它会做什么

还有一件事,很容易理解这些属性,因为
name
不是动词

最坏的情况是,如果API是一致的,并且该人员没有意识到
name()
是一个访问器,
name(value)
是一个变异器,那么她只需在文档中查找一次就可以理解该模式


<> P>正如我爱C一样,我认为C++根本不需要属性! 使用C++11,您可以定义属性类模板,并按如下方式使用它:

CTestClass myClass = CTestClass();

myClass.AspectRatio = 1.4;
myClass.Left = 20;
myClass.Right = 80;
myClass.AspectRatio = myClass.AspectRatio * (myClass.Right - myClass.Left);
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; }
};
类测试{
公众:
属性号{this,&Test::setNumber,&Test::getNumber};
私人:
整数;
无效集合编号(整数编号)
{itsNumber=theNumber;}
int getNumber()常量
{返回其编号;}
};
这里是属性类模板

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;
};
模板
类属性{
公众:
使用SetterType=void(C::*)(T);
使用GetterType=T(C::*)()常量;
属性(C*theObject,SetterType theSetter,GetterType theGetter)
:其对象(对象),
它的设定者(设定者),
itsGetter(theGetter)
{ }
运算符T()常量
{return(itsObject->*itsGetter)(;}
C&运算符=(T值){
(其对象->*其设置者)(值);
返回*其对象;
}
私人:
C*常量对象;
SetterType常量及其setter;
GetterType常量及其getter;
};
不。。
但是,你应该考虑,如果它只是Get:set函数,而不是在GET中预先生成的附加任务:SET方法只是让它公开。在所有的平台和编译器中,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;  
}

<>我从多个C++源收集了这些想法,并把它放进了GETE的一个很好的,很简单的例子。
// 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;  
}
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
class MyClass {

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

 public:
 ...

}