`
congfeng02
  • 浏览: 200029 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

在C++中实现属性

阅读更多

在C++中实现属性
原作:Emad Barsoum翻译:虞振祥

下载本文示例源代码

本文译自http://www.codeguru.com/cpp_mfc/Property.html的Implementing a Property in C++

开发测试环境:Visual C++ 7.0, Windows XP sp1, Windows 2000 sp3

摘要
本文试着在C++中不使用任何扩展技术模拟C#(或其他语言)中的属性特征。大多数在C++实现属性的库和编译器使用扩展技术,如Managed C++或C++ Builder,或者他们使用如通常函数的set和get方法,但那不是属性。

详述
我们首先看一下什么是属性。一个属性表现为一个字段或者成员变量,但它通过read和write方法或者get和set方法暗中操作变量。

例如,若存在类A和它的属性Count,我可以写如下的代码:

 A foo;
 Cout << foo.Count;
实际上Count调用它的get函数返回当前的变量值。你可以将属性定为只读(你可以读取它但不能修改它)、只写或者可读写,这就是使用属性而不直接使用变量的的一个最大好处了。好了,让我们开始来实现它:

我们需要能做如下的事:

 int i = foo.Count;  //--调用get函数得到值
 foo.Count = i;  //-- 调用set函数设定值
因此,很明显的我们需要重载''=''操作符使其能设定变量的值,同时也要重载该属性的返回值(在下面我们将会看到的)。

我们将实现一个称为property的类,它做的就像一个属性,声明如下:

template <typename Container, typename ValueType, int nPropType>
class property {}
这个模板类表示的是我们的属性。Container是我们要在其中包含属性的类变量,set和get方法以及属性的类的类型。ValueType是内部变量即要定义的属性的类型,nPropType定义属性的读写标志:只读、只写或可读写。 现在我们需要一个指向从包含属性的类Container到属性类property的set和get方法的指针,同时重载''=''操作符以使得属性能象变量起那样作用。现在我们来看property类的全部定义
#define READ_ONLY 1
#define WRITE_ONLY 2
#define READ_WRITE 3

template <typename Container, typename ValueType, int nPropType>
class property
{
public:
property()
{
  m_cObject = NULL;
  Set = NULL;
  Get = NULL;
}

//-- 将m_cObject指向包含属性的container类 --
void setContainer(Container* cObject)
{
  m_cObject = cObject;
}
//-- 设定可改变属性值的set成员函数 --
void setter(void (Container::*pSet)(ValueType value))
{
  if((nPropType == WRITE_ONLY) || (nPropType == READ_WRITE))
    Set = pSet;
  else
    Set = NULL;
}
//-- 设定可检索属性值的get成员函数 --
void getter(ValueType (Container::*pGet)())
{
  if((nPropType == READ_ONLY) || (nPropType == READ_WRITE))
    Get = pGet;
  else
    Get = NULL;
}
//-- 重载''=''号操作符使其能用set成员设定属性值--
ValueType operator =(const ValueType& value)
{
  assert(m_cObject != NULL);
  assert(Set != NULL);
  (m_cObject->*Set)(value);
  return value;
}
//-- 使属性类能转换为内部类型成为可能--
operator ValueType()
{
  assert(m_cObject != NULL);
  assert(Get != NULL);
  return (m_cObject->*Get)();
}
private:
  Container* m_cObject;  //-- 指向包含属性的类模块 --
  void (Container::*Set)(ValueType value);
                         //-- 指向set成员函数的函数指针 --
  ValueType (Container::*Get)();
                         //-- 指向get成员函数的函数指针 --
};
现在让我们来一段一段地看这些代码:
在下面的代码中,仅仅将Container指针指向一个有效的包含属性的实例。
void setContainer(Container* cObject)
{
  m_cObject = cObject;
}
下面的代码,设定指针指向包含属性的类中的set和get成员函数,其set和get成员函数度有,唯一的限制即set成员函数必须有一个ValueType型的参数并无返回值,get成员函数没有参数,但要返回ValueType型值。
//-- 设定可改变属性值的set成员函数 --
void setter(void (Container::*pSet)(ValueType value))
{
  if((nPropType == WRITE_ONLY) || (nPropType == READ_WRITE))
    Set = pSet;
  else
    Set = NULL;
}
//-- 设定可检索属性值的get成员函数 --
void getter(ValueType (Container::*pGet)())
{
  if((nPropType == READ_ONLY) || (nPropType == READ_WRITE))
    Get = pGet;
  else
    Get = NULL;
}
在如下的代码中,第一部分是''=''操作符的重载,它调用包含属性的类中的set函数设定其属性的值。第二部分则为了使整个属性类象ValueType类型一样起作用,所以它返回包含属性的类中get函数的返回值。
//-- 重载''=''号操作符使其能用set成员设定属性值--
ValueType operator =(const ValueType& value)
{
  assert(m_cObject != NULL);
  assert(Set != NULL);
  (m_cObject->*Set)(value);
  return value;
}
//-- 使属性类能转换为内部类型成为可能--
operator ValueType()
{
  assert(m_cObject != NULL);
  assert(Get != NULL);
  return (m_cObject->*Get)();
}

现在我们来看看怎样使用它:
如下所示,在PropTest类中定义了一个叫做Count的简单属性。Count的实际值将保存到或检索之在PropTest的私有成员变量"m_nCount"中,通过PropTest的get和set方法。get和set方法可以使用任何的变量名字,只需他们的地址能被传递到property类中,如下面的PropTest构造函数里面的代码般,代码行" property<PropTest, int, READ_WRITE> Count; "让我们在PropTest中得到可读写的int型的Count属性。现在你可以使用如一般的成员变量般使用使用Count属性了,但实际上你是间接地调用它set和get方法。

要使Count属性能成功工作,必须先在PropTest的构造函数里面对其进行初始化。

class PropTest
{
public:
  PropTest()
  {
    Count.setContainer(this);
    Count.setter(&PropTest::setCount);
    Count.getter(&PropTest::getCount);
  }
  int getCount()
  {
    return m_nCount;
  }
  void setCount(int nCount)
  {
    m_nCount = nCount;
  }
  property<PropTest,int,READ_WRITE> Count;


private:
  int m_nCount;
};
如下所示,你可以象使用普通变量一样使用Count属性。
int i = 5,j;
PropTest test;
test.Count = i;    //-- 调用set函数 --
j= test.Count;     //-- 调用get函数 --
要使用只读的属性,你可以创建如下的property实例:
property<PropTest,int,READ_ONLY > Count;
要使用只写的属性,你可以创建如下的property实例:
property<PropTest,int,WRITE_ONLY > Count;
注意:如果你将某一属性设为只读,当你对其赋值时,将引发assertion诊断。同理,当读取只写的属性时
也同样会引发assertion诊断。

小结
本文展示了在C++只用标准的C++特性而不使用其他任何的扩展技术来实现属性。当然,直接使用set和get函数效率
要更高些,因为本文中的方法需要为每一个属性定义一个property类实例。
分享到:
评论

相关推荐

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

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

    C++修改文件属性工具

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

    C++builder组件属性详解.doc

    在本文中,我们将对 C++Builder 组件的常见属性进行详细的解释。 一、 Caption 属性 Caption 属性是窗体和可视化控件的共有属性,用来指定窗体标题栏中的说明文字。它的默认值与控件名相同,但程序员可以在对象...

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

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

    用c++实现Canny算子

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

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

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

    C++高级属性专题

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

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

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

    属性表c++实例

    在C++编程中,属性表(Property Sheet)通常用于创建多页对话框,它允许用户在不同的页面上配置不同类型的设置。属性表是Windows GUI应用程序中常见的一种用户界面元素,可以提供良好的组织和导航功能。VC++是...

    用C++实现DBSCAN聚类算法

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

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

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

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

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

    C++属性对话框模板

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

    c++实现电梯调度模拟

    在C++实现过程中,我们需要注意以下几点: - **面向对象编程**:C++是一种面向对象的语言,我们可以创建电梯和乘客类,封装它们的行为和属性,通过成员函数来处理各种操作。 - **异常处理**:考虑到可能出现的错误...

    用c++在DEV-C++上实现的学生成绩管理系统

    在这个项目中,C++被用来定义和操作数据结构,如学生对象,以及实现各种功能,如成绩计算和存储。 2. **面向对象编程(OOP)**:在学生成绩管理系统中,面向对象编程思想是核心。可以创建一个`Student`类来表示学生...

    驾驶证管理C++实现

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

    C4.5算法C++实现

    在C++实现过程中,需要设计类来表示数据样本、属性、决策树节点等,并实现相应的函数来执行上述步骤。例如,可以定义`DataSample`类存储样本的特征和类别,`Attribute`类表示属性,`TreeNode`类表示决策树节点,其中...

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

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

    CAN_BUS c++实现 源代码

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

    C++ MFC实现五子棋游戏

    在本文中,我们将深入探讨如何使用C++编程语言和MFC(Microsoft Foundation Classes)库来实现一个五子棋游戏。MFC是微软提供的一套面向对象的类库,用于简化Windows应用程序开发,它封装了许多Win32 API,使得...

Global site tag (gtag.js) - Google Analytics