C++ 中的属性, 就像 C# 或 Delphi 一样





3.00/5 (8投票s)
两个简单的属性类,
简短描述
头文件 properties.h 包含两个模板类:property_t - 用于实现任何类型的属性,以及 property_it - 用于实现索引器属性。这两个类都具有丰富的各种方法,用于将它们与 getter 和/或 setter 方法和/或类字段绑定。上述文件还包含标准 C 类型的系列定义,例如 int 类型的 CIntProperty,以及 MFC 类型的系列定义,例如 CString 类的 CStringProperty。
使用代码
为了使用属性,你必须首先包含 properties.h 文件,并在其中定义属性的命名空间。
#include "properties.h"
using namespace properties;
在你的类文件中,你必须定义 property 类型的类字段。它可以是预定义的 property 类型之一,也可以是隐式模板声明。class SomeClass {
CIntProperty Integer; // predefined property type
CDoubleProperty Double; // predefined property type
property_t<SomeType> someType; // implicit template declaration
};
属性的语法非常简单,只需使用模板类型声明属性的类型即可。索引属性的语法类似,区别在于模板有两个类型参数,第一个是索引类型,第二个是元素类型。它看起来如下所示property_it< int, char > SomeCharIndexer;
现在你必须决定如何绑定你的属性。property_t 类能够与 getter 和/或 setter 方法以及 getter 和/或 setter 类字段绑定。在这种情况下,你必须声明属性将绑定到的字段或方法或两者。例如,你可以将属性绑定到 getter 字段和 setter 方法,或者只绑定到 getter 和 setter 字段(通常是同一个字段),或者只绑定到 getter 和 setter 方法。属性可以按以下方式绑定
- 仅 getter 方法
- 仅 setter 方法
- 仅 getter 字段
- 仅 setter 字段
- getter 方法和 setter 方法
- getter 方法和 setter 字段
- getter 字段和 setter 字段
- getter 字段和 setter 方法
- 与上述组合类似,还可以从另一个相同类型的属性进行绑定
对于非索引属性,getter 和 setter 方法始终是
TYPE getter_method_name(); // for getter
void setter_method_name(const TYPE& value); // for setter
类型,其中 TYPE 是属性类型。对于索引属性,getter 和 setter 方法始终是
TYPE getter_indexer_method_name(const INDEX& index); // for getter
void setter_indexer_method_name(const INDEX& index, const TYPE& value); // for setter
类型,其中 INDEX 是索引类型,TYPE 是索引元素的类型。现在是一个简单的示例,说明属性绑定
int m_integer;
double m_double;
char *m_array;
void set_Integer(const int& value) { m_integer = value; }
double get_Double() { return 3.1415926; }
char get_SomeCharIndexer(const int& index) { return m_array[index]; }
void set_SomeCharIndexer(const int& index, const char& value) { m_array[index] = value; }
/* ... */
BIND_PROPERTY(SomeClass, Double, get_Double, m_double);
BIND_PROPERTY(SomeClass, Integer, m_integer, set_Integer);
BIND_PROPERTY(SomeClass, SomeCharIndexer, get_SomeClassIndexer, set_SomeClassIndexer);
BIND_PROPERTIES 宏已演变为#define BIND_PROPERTY(class_name,prop_name,getter,setter) \
prop_name.bind(class_name,prop_name,&class_name::getter,&class_name::setter)
如果没有这个宏,你必须使用完整的语法,例如SomeClassIndexer.bind(offsetof(SomeClass,SomeClassIndexer), &SomeClass::get_SomeClassIndexer, &SomeClass.set_SomeClassIndexer);
现在我们假设你想要编写一个使用属性构建界面的控件类。在 Microsoft Visual Studio 环境中,你的代码可能如下所示#include "stdafx.h"
#include "properties.h"
using namespace properties;
class SomeControl
{
protected:
// getter properties methods
virtual CPoint get_Location() { /* */ }
virtual int get_Width() { /* */ }
virtual int get_Height() { /* */ }
virtual CString get_Caption() { /* */ }
virtual CWnd* get_Controls(const int& index) { /* */ }
// setter properties methods
virtual void set_Location(const CPoint& value) { /* */ }
virtual void set_Width(const int& value) { /* */ }
virtual void set_Height(const int& value) { /* */ }
virtual void set_Caption(const CString& value) { /* */ }
virtual void set_Copntrols(const int& index, CWnd* const& value) { /* */ }
public:
SomeControl() {
BIND_PROPERTY(SomeControl, Location, get_Location, set_Location);
BIND_PROPERTY(SomeControl, Width, get_Width, set_Width);
BIND_PROPERTY(SomeControl, Height, get_Height, set_Height);
BIND_PROPERTY(SomeControl, Caption, get_Caption, set_Caption);
BIND_PROPERTY(SomeControl, Controls, get_Controls, set_Controls);
}
property_t<CPoint> Location;
CIntProperty Width;
CIntProperty Height;
CStringProperty Caption;
property_it<int,CWnd*> Controls;
};
最终用法
在代码的任何地方,你都可以更改控件的标题、位置和尺寸
SomeControl sc;
/* ... */
sc.Caption = "My control with properties";
sc.Location = CPoint(100,100);
sc.Width = 300;
sc.Height = 200;
备注
你必须记住,如果一个属性没有 getter 方法并且尝试获取其值,或者没有 setter 方法并且尝试赋值,则会抛出 char* 类型的异常。
免责声明
本软件和随附的文件“按原样”分发,没有任何明示或暗示的保证。对于可能的损害甚至功能性,我们概不负责。用户必须承担使用本软件的全部风险。