`
isiqi
  • 浏览: 16453042 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

用C++实现属性

阅读更多

Delphi和C#的类都提供了“属性”的概念,使得Getter和Setter的方法可以像访问成员一样简单,如下面的Delphi代码:
TMyClass = class
private
FValue: Integer;
funcation GetValue: Integer;
procedure SetValue(value: Integer);
public
property Value: Integer read GetValue write SetValue;
end;
红色部分就是属性的声明,以后可以直接对Value进行读写,像下面这样:
MyClass.Value := 100;
v = MyClass.Value;
属性有几个显而易见的好处:
  • 与Getter和Setter相比更加简单,就像直接访问成员一样。
  • 与直接访问成员相比,属性可以控制读写权限,并通过Getter和Setter对代码进行检验。
  • 属性对UI的所见即所得编辑很有用,可以很直观的设置某个属性,如大小,颜色等;QT似乎也大量应用属性,不过我没有去看过。
C++原生没有支持属性,但这个语言的特点就是语法强大,通过一些高级属性就可以实现其他语言的特性。要实现属性,C++当然是可以胜任了,而且实现方式有很多,我在网上就看过几种实现。不过在这里我要讲另外两种实现,一种是我想到的,另一种是编译器的扩展。
先看第一种,网上通常的实现是用“模板+操作符重载”的方式,这种方式需要在类的构造函数中初始化模板类成员,并且模板类包含了3个成员:外部类指针和读写函数指针。这个模板类成员就是“属性”,一个属性将浪费掉一些存储,如果一个类存在大量属性,则这个类的空间尺寸是可观的。
我的实现是用“本地类+操作符重载”的方式,用了3种本地类,分别实现“只读,只写,可读写”三种属性,用宏包装起来方便使用,请看下面的代码:
// 取外部类实例指针(this)
// outClass 外部类名
// localClassMem 本地类成员

#define OUTCLASS_THIS(outClass, localClassMem) ((outClass*)((unsigned char*)this - offsetof(outClass, localClassMem)))
// 属性定义宏
// cls 定义属性的类
// type 属性的类型
// propname 属性名
// getter 读函数
// setter 写函数

#define PROPERTY_R(cls, type, propname, getter) \
class property_##getter \
{ \
public: \
operator type () \
{ \
return OUTCLASS_THIS(cls, propname)->getter(); \
} \
} propname
#define PROPERTY_W(cls, type, propname, setter) \
class property_##setter \
{ \
public: \
property_##setter &operator = (const type& value) \
{ \
OUTCLASS_THIS(cls, propname)->setter(value); \
return *this; \
} \
} propname
#define PROPERTY_RW(cls, type, propname, getter, setter) \
class property_##getter_##setter \
{ \
public: \
operator type () \
{ \
return OUTCLASS_THIS(cls, propname)->getter(); \
} \
property_##getter_##setter &operator = (const type& value) \
{ \
OUTCLASS_THIS(cls, propname)->setter(value); \
return *this; \
} \
} propname
有了这几个宏,就可以写一个测试类来看看结果了:
class Test
{
public:
PROPERTY_R(Test, int, ValueR, GetValueR);
PROPERTY_W(Test, float, ValueW, SetValueW);
PROPERTY_RW(Test, bool, ValueRW, GetValueRW, SetValueRW);

Test(): mValueR(100), mValueW(0), mValueRW(false)
{
}
int GetValueR()
{
return mValueR;
}
void SetValueW(const float value)
{
mValueW = value;
}
bool GetValueRW()
{
return mValueRW;
}
void SetValueRW(bool value)
{
mValueRW = value;
}
private:
int mValueR;
float mValueW;
bool mValueRW;
};

int _tmain(int argc, _TCHAR* argv[])
{
Test test;
int v = test.ValueR;
cout<<v<<endl;
test.ValueW = 1.0f;
test.ValueRW = true;
cout<<test.ValueRW<<endl;

return 0;
}
基本上可以满足要求了,内部类没有成员,一个类只占一个字节,比之前面的要节省得多。
尽管用标准语法可以实现“属性”,但仍有一些不足之处,首先是属性若传入有可变参数的函数时会有问题,如下面:
printf("%d", test.ValueR);
编译器识别不出可变参数的具体类型,因此ValueR并没有默认转换为int,要这样写才正确:
printf("%d", (int)test.ValueR);
另外一个问题是“数组属性”如何实现,至少我没有找到更好的办法,若哪位朋友有好的办法,不访分享出来。
如果你确定你的代码只会运行在Windows上,并且只用VC作为编译器,那么就可以用第二种实现。微软提供了property关键字用来支持属性机制,编译器会自动将属性替换为Get或Set函数,这样一来属性就根本不占用任何空间,也没有任何调用开销。
下面同样包装了几个宏,不仅实现了普通属性,也实现了数组类型的属性:
#define PROPERTY_R(type, propname, getter) __declspec(property(get=getter)) type propname
#define PROPERTY_W(type, propname, setter) __declspec(property(put=setter)) type propname
#define PROPERTY_RW(type, propname, getter, setter) __declspec(property(get=getter, put=setter)) type propname
#define PROPERTY_ARRAY_R(type, propname, getter) __declspec(property(get=getter)) type propname[]
#define PROPERTY_ARRAY_W(type, propname, getter) __declspec(property(put=setter)) type propname[]
#define PROPERTY_ARRAY_RW(type, propname, getter, setter) __declspec(property(get=getter, put=setter)) type propname[]
有了编译器的支持,事情的确简单得多了。
分享到:
评论

相关推荐

    C++实现属性表单和向导生成

    本项目“C++实现属性表单和向导生成”聚焦于如何利用C++来构建用户界面(UI),特别是属性表单和向导,这对于创建用户友好的应用程序至关重要。 属性表单通常用于设置或修改对象的属性。它们展示一系列的控件,如...

    用c++实现Canny算子

    在C++中实现Canny算子通常涉及到以下几个关键步骤: 1. **噪声过滤**:首先,使用高斯滤波器来平滑图像,以减少噪声对边缘检测的影响。高斯滤波器的核大小和标准差可以根据实际图像的噪声水平来选择。 2. **计算...

    用C++实现DBSCAN聚类算法

    在C++实现中,我们可以使用如 `std::vector` 和 `std::unordered_set` 这样的容器来存储和操作数据点。`std::vector` 可用于存储数据点集合,`std::unordered_set` 可用于快速查找邻域点。计算邻域通常可以通过空间...

    粗糙集属性约简 C++实现

    在C++实现中,通常会包含以下四个类: 1. **DataSet类**:这是整个系统的基础,用于存储原始数据。它通常包含数据实例的集合以及每个实例的属性值。这个类需要提供添加、删除和访问数据实例的方法,以及获取属性...

    C++实现数据库DBMS建表插入删除属性功能

    C++实现数据库DBMS建表插入删除属性功能

    用C++实现小人跳舞

    本项目"用C++实现小人跳舞"正是这样一种实践,它利用C++语言的基本控制结构和输出功能,构建了一个简单的字符动画,模拟小人跳舞的情景。 首先,我们要理解C++语言的基础知识。C++是静态类型的、编译式的、通用的、...

    C++高级属性专题

    在C++编程语言中,高级属性是提升代码效率和可维护性的关键要素。这个资源集合涵盖了C++的一些核心概念,包括模板、继承、多态、动态内存管理以及类的高级特性。下面将对这些主题进行深入讲解。 1. **C++模板**:...

    用C++实现的简单sql数据库

    在本项目中,标题"用C++实现的简单sql数据库"揭示了我们正在讨论一个使用C++编程语言构建的轻量级SQL数据库管理系统(DBMS)。C++是一种强大的、通用的编程语言,以其效率和灵活性著称,因此是实现数据库系统底层...

    c++实现电梯调度模拟

    综上所述,"C++实现电梯调度模拟"项目涵盖了算法设计、数据结构应用、面向对象编程和系统优化等多个IT领域的知识点。通过这个项目,不仅可以提升编程技能,还能对实际生活中的问题有更深入的理解。

    用Visual C++实现的扫雷程序

    总的来说,用Visual C++实现扫雷程序是一个综合性的项目,涉及到C++语言基础、MFC框架、控件操作、事件处理、随机数生成、数据结构、算法以及图形界面设计等多个方面的知识。通过这个项目,开发者不仅可以提升编程...

    C++修改文件属性工具

    通过上述方法,我们可以在C++中实现对文件属性和时间戳的修改。这对于文件管理系统、日志记录或者任何需要控制文件状态的应用场景都十分有用。在实际开发中,应确保遵循安全编程原则,避免因误操作导致的数据丢失或...

    CAN_BUS c++实现 源代码

    在本项目中,"CAN_BUS c++实现 源代码"提供了用C++编程语言实现CAN总线功能的示例代码,这对于理解和学习CAN总线通信机制以及C++编程技巧非常有帮助。 在C++中实现CAN总线通信,通常需要使用特定的硬件接口,如CAN...

    五子棋C++实现 五子棋C++实现

    下面我们将详细探讨这个C++实现的五子棋游戏涉及的知识点。 1. **C++基础语法**:项目的实现基于C++语言,因此首先需要了解C++的基本语法,包括变量声明、数据类型、流程控制语句(如if、for、while)、函数定义与...

    驾驶证管理C++实现

    在本项目中,“驾驶证管理C++实现”是一个利用C++编程语言设计的系统,用于管理和操作驾驶员的相关信息。这个系统可能包含了对驾驶证的增删改查等基本功能,旨在提高驾驶证信息管理的效率和准确性。下面我们将深入...

    C++实现蓝牙bluetooth通讯功能

    在C++中实现蓝牙通讯,我们需要理解这些层的工作原理,并能够用C++语言来模拟它们的功能。 1. **物理层**:这是蓝牙通信的底层,定义了无线射频(RF)规范,如频率分段、调制方式和功率控制。在C++中,我们可能需要...

    图书管理系统c++实现

    《图书管理系统C++实现》是一个非常适合C++初学者学习的项目,它涵盖了基础的面向对象编程概念和实际应用。下面将详细阐述这个系统的实现细节及其涉及的C++知识点。 首先,我们从`main.cpp`开始,这是程序的入口点...

    用户权限管理模块(C++实现)

    本项目"用户权限管理模块(C++实现)"是一个用C++编程语言实现的权限管理解决方案,它包含了几个核心功能,如单例模式、用户区分、用户管理以及密码安全存储。 首先,我们来深入理解C++实现的用户权限管理模块。C++...

    QML 与 C++交互 - 01QML访问C++属性

    在Qt框架中,QML(Qt Meta Language)和C++是两种主要的编程语言,它们在构建用户界面和实现业务逻辑方面各自发挥着重要作用。QML以其声明式语法和直观的UI设计,使得构建现代、动态的应用变得简单,而C++则提供了...

    C++属性对话框模板

    在C++编程中,属性对话框模板是一种常用的技术,它允许开发者创建用户界面,这些界面可以方便地编辑和查看对象的属性。属性对话框通常由一系列控件组成,如文本框、复选框和组合框,用于显示和修改对象的各种特性。...

Global site tag (gtag.js) - Google Analytics