首页

源码搜藏网

首页 > 安卓源码 > 技术博客 >

C#属性的快速而肮脏但外观整洁的C ++替代品

创建时间:2019-06-07 11:36  浏览

介绍

尽管我们都知道C#属性是为每个单独的成员字段编写getter / setter函数的良好替代,但实际上我们没有在C ++中使用属性的标准方法。这是C ++替代属性的快速实现。该设计旨在提供与使用C#属性时相似的感觉,尽管在实现中存在一些令人讨厌的方面。

使用代码

使用代码时,只需在代码顶部包含“ prop.h ”即可(' prop.cpp '是一个示例源代码。)设计主要遵循C#属性的原理,但是您需要遵循一些小的语法细节。

宣言

首先,如果您的属性不需要实现任何特殊的get / set函数,那么请不要。

class Test {
public:
  prop<size_t> p;     //< This is a 'size_t' property.
}

您可以像普通成员字段一样使用声明的属性。例如:

int foo() {
  Test test;
  test.p = 3;
  std::cout << test.p << std::endl;
}

其次,如果你的财产需要实现自己的getter和setter,那就给它提供这样的定义。请注意,setter函数通过reserved关键字接收调用者给定的值value

class Test {
  size_t p_org;       //< Let's assume the real value is to be stored here.

public:
  prop<size_t> p {
    __get__() { return p_org; }
    __set__(size_t) { p_org = value; }
  };
};

最后,您还可以通过仅提供getter函数并将原始类型指定为 声明来声明只读属性  const

class Test {
  size_t p_org;       //< Let's assume the real value is to be stored here.

public:
  prop<const size_t> p_readonly {
    __get__() { return p_org; }
  };
};

如果尝试使用只读属性设置任何值,则会出现以下编译时错误。

int main() {
  Test test;
  test.p_readonly = 0xdeadbeef;  //< compile error: no operator= defined.
  return 0;
}

...

test.cpp:3:19: error: no viable overloaded '='
  test.p_readonly = 0xdeadbeef;
  ~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~

以下是一些重点;

初始化

您可以使用构造函数中的属性名称直接初始化默认属性。

class Test {
public:
  prop<size_t> p;
  
  Test() : p(0) {}
};

但是,如果属性具有自己的getter / setter,则可以初始化原始数据成员而不是属性本身。

class Test {
public:
  size_t p_org;

  prop<size_t> p {
    __get__() { return p_org; }
    __set__(size_t) { p_org = value; }
  };

  Test() : p_org(0) {}
};

物业读/写

读取和写入属性就像您使用常规公共成员字段一样。它支持可用于常规变量的各种操作。请参阅附件中的“ prop.cpp ”以查看示例读/写用法。

这个怎么运作

下面是标题' prop.h ' 的简化源代码

#pragma once
#include <cassert>
#include <functional>

template <typename T>
class prop {
public:
  using Getter = std::function<T()>;
  using Setter = std::function<void(T)>;

private:  
  T __val__;
  Getter __getter__;
  Setter __setter__;

  void initialize() {
    __getter__ = [&]() { return __val__; }; 
    __setter__ = [&](T value) { __val__ = value; };
  }

  /* ... */

public:
  prop() { initialize(); }
  prop(T o) : __val__(o) { initialize(); }
  prop(Getter getter, Setter setter = readonly_setter()) :
    __getter__(getter), __setter__(setter) {}

  /* ... */

  virtual prop<T>& operator=(T o)
  { __setter__(o); return *this; }

  virtual operator T() const
  { return __getter__(); }

  /* ... */
};

template <typename T>
class prop<const T> {
public:
  using Getter = std::function<T()>;

private:
  Getter __getter__;

  prop(const prop<T>&) = delete;
  prop(prop<T>&&) = delete;

public:
  prop(Getter getter) : __getter__(getter) {}

  virtual operator T() const
  { return __getter__(); }
};


#define __get__() [&]()
#define __set__(T) , [&](T& value)

基本上,您将声明基类的实例' prop', 并可选择将其提供给您自己的getter / setter。prop类有三个成员,一(__val__)为默认的getter / setter数据变量和其它两个拉姆达变量(__getter____setter__),用于可变操纵。

您用来指定自己的getter / setter(比如说__get__()__set__())的实际上是用宏编写的辅助函数。具体来说,__get__() 宏是getter函数的lambda声明, __set__()宏也是。

这里一个令人讨厌的技巧是,宏定义的前面加上一个逗号(,这就是遵循统一初始化的语法。我只是在那里放了一个逗号,因为它可以防止程序员在getter定义之后需要添加额外逗号的混乱,也因为它可能允许属性声明看起来不那么尴尬,甚至一点点。 __set__()

最后,只读属性的基类是部分专用的prop类(prop<const T>)。更具体地说,只读prop类专门用于任何常量类型,并且从不定义值修改操作符。由于必须提供适当的getter定义,因此在这种情况下没有定义默认构造函数。

历史

上一篇:Xamarin相机控制和云:天堂与LEADTOOLS合并
下一篇:我们使std :: shared_mutex的速度提高了10倍

相关内容

热门推荐