跟陈湾来完善C++(2), 添加属性功能

上面几篇文章中,我们添加了名称空间优化,添加事件功能。这些对我来说其实已经够了。但还可以加一个属性功能。

当我们在C++中更改一个属性时,平常都是Get函数加上Set函数,但是这样,没有直接写一个成员变量方便。例如:

a.SetValue(a.GetValue() + 1);

没有

a.Value = a.Value + 1;

方便。

但是这种方便只有在调用有属性功能的对象时才能使用。在创建属性的时候我还是用老套路,写一个Get和Set函数,该干啥还是干啥。我的属性功能其实就是在类中添加一个共有成员,读取这个数据成员的时候调用Get方法,给这个成员赋值的时候调用Set方法,当然这个成员在初始化的时候就要把Get和Set函数的指针传进来而且不能改变,因为我觉得没有必要去考虑换函数这些不可能发生的事情。

好了,思路都很明确了,现在该贴代码了。

template <typename T>
class IProperty
{
public:
    virtual const T & Get() const = 0;
    virtual T & Reference() = 0;
    virtual void Set(const T &) = 0;
};

template <typename T>
class Property : public IProperty<T>
{
public:
    using Self = Property<T>;
    using GetConstantEventHandler = Delegate<const T &>;
    using GetNotConstantEventHandler = Delegate<T &>;
    using GetValueEventHandler = Delegate<T>;
    using SetEventHandler = Delegate<void, const T &>;

public:
    Property()
    {
    }

    template <typename TClassType>
    Property(TClassType * className, const T & (TClassType::*getConstantFunction)() const, T &(TClassType::*getNotConstantFunction)(), void (TClassType::*setFunction)(const T & value))
    {
        Clear();

        mGetConstant.Add(className, getConstantFunction);
        mGetNotConstant.Add(className, getNotConstantFunction);
        mSet.Add(className, setFunction);
    }

    template <typename TClassType>
    Property(TClassType * className, const T & (TClassType::*getConstantFunction)() const, T &(TClassType::*getNotConstantFunction)())
    {
        Clear();

        mGetConstant.Add(className, getConstantFunction);
        mGetNotConstant.Add(className, getNotConstantFunction);
    }

    template <typename TClassType>
    Property(TClassType * className, const T & (TClassType::*getFunction)() const, void (TClassType::*setFunction)(const T & value))
    {
        Clear();

        mGetConstant.Add(className, getFunction);
        mSet.Add(className, setFunction);
    }

    template <typename TClassType>
    Property(TClassType * className, T & (TClassType::*getFunction)(), void (TClassType::*setFunction)(const T & value))
    {
        Clear();

        mGetNotConstant.Add(className, getFunction);
        mSet.Add(className, setFunction);
    }

    template <typename TClassType>
    Property(TClassType * className, const T & (TClassType::*getFunction)() const)
    {
        Clear();

        mGetConstant.Add(className, getFunction);
    }

    template <typename TClassType>
    Property(TClassType * className, T & (TClassType::*getFunction)())
    {
        Clear();

        mGetNotConstant.Add(className, getFunction);
    }

    template <typename TClassType>
    Property(TClassType *className, void (TClassType::*setFunction)())
    {
        Clear();

        mSet.Add(className, setFunction);
    }

public:
    void Clear()
    {
        mGetConstant.RemoveAll();
        mGetNotConstant.RemoveAll();
        mGetValue.RemoveAll();
        mSet.RemoveAll();
    }

    const T & Get() const override
    {
        if (IsConstReferenceGetable())
        {
            return mGetConstant.Invoke();
        }
        else
        {
            throw "Constant reference cannot get";
        }
    }

    T & Reference() override
    {
        if (IsReferenceGetable())
        {
            return mGetNotConstant.Invoke();
        }
        else
        {
            throw "Cannot get";
        }
    }

    void Set(const T & value) override
    {
        if (IsSetable())
        {
            mSet.Invoke(value);
        }
        else if (IsReferenceGetable())
        {
            Reference() = value;
        }
        else
        {
            throw "Cannot set";
        }
    }

    bool IsGetable() const
    {
        return IsConstReferenceGetable() || IsReferenceGetable();
    }

    bool IsConstReferenceGetable() const
    {
        return mGetConstant.GetCount() > 0;
    }

    bool IsReferenceGetable() const
    {
        return mGetNotConstant.GetCount() > 0;
    }

    bool IsSetable() const
    {
        return mSet.GetCount() > 0 || IsReferenceGetable();
    }

    operator const T & () const
    {
        return Get();
    }

    Self & operator = (const T & value)
    {
        Set(value);
        return *this;
    }

private:
    GetConstantEventHandler mGetConstant;
    GetNotConstantEventHandler mGetNotConstant;
    GetValueEventHandler mGetValue;
    SetEventHandler mSet;
};

template <typename T>
class BasicProperty : IProperty<T>
{
public:
    using Self = BasicProperty<T>;

public:
    BasicProperty()
    {
    }

    BasicProperty(const T & value) :
        mValue(value)
    {
    }

public:
    const T & Get() const override
    {
        return mValue;
    }

    T & Reference() override
    {
        return mValue;
    }

    void Set(const T & value)
    {
        mValue = value;
    }

    operator const T & () const
    {
        return Get();
    }

    Self & operator = (const T & value)
    {
        Set(value);
        return *this;
    }

private:

    T mValue;
};

代码看上去很多,其实就两个类,一个Property,在初始化时将Get和Set函数传进去(当然还可以传一些为了效率而优化的函数,可惜这些函数太反人类了,几部不用),当然还是有缺陷的,我没有重载+=,-=,*=,/=这些运算符,也算是一大硬伤吧。还有一个是BasicProperty,简单的一个数据的封装,没有Get,Set之类的方法,在我看来很常用。

唉,怎么说呢,这次我添加属性这个功能其实我觉得是多此一举。在C++中完全可以用Get,Set方法来完成,即使有了属性功能也不常用。而且并没有省多少事。但是有的语言有这个功能就当是写着玩吧。

时间: 2024-12-09 04:51:53

跟陈湾来完善C++(2), 添加属性功能的相关文章

019 添加分区功能 - bos

一.基础调整 1.删除subarea.jsp中新增窗口的分区编码一行 2.修改Subarea.hbm.xml,主键生成策略为uuid 二.easyUI - combobox下拉框的使用 1.静态页面编写(并不实用) <select class="easyui-combobox"> <option>小黑</option> <option>小白</option> <option>小红</option> &l

第四节 综合实例:使用多态完善汽车租赁系统计价功能

综合实例:使用多态完善汽车租赁系统计价功能 主讲教师:王少华      QQ群号:483773664 学习目标 在案例中应用多态; 使用父类类型作为方法的形参 一.计算一次租赁多辆汽车的总租金 (一) 需求说明 在前一章(继承)汽车租赁系统的基础上,即已经实现了汽车租赁系统的简单计价功能,客户可以租赁一辆某种型号的汽车若干天.现在要增加需求: 客户可以一次租赁多辆不同品牌的不同型号的汽车若干天,要求计算出总租赁价. 假设有一客户要租赁: 2辆宝马 1辆别克商务舱 1辆金龙(34)座 租5天共多少

跟王老师学多态(四):综合实例:使用多态完善汽车租赁系统计价功能

综合实例:使用多态完善汽车租赁系统计价功能 主讲教师:王少华      QQ群号:483773664 学习目标 在案例中应用多态; 使用父类类型作为方法的形参 一.计算一次租赁多辆汽车的总租金 (一) 需求说明 在前一章(继承)汽车租赁系统的基础上,即已经实现了汽车租赁系统的简单计价功能,客户可以租赁一辆某种型号的汽车若干天.现在要增加需求: 客户可以一次租赁多辆不同品牌的不同型号的汽车若干天,要求计算出总租赁价. 假设有一客户要租赁: 2辆宝马 1辆别克商务舱 1辆金龙(34)座 租5天共多少

【转】为Android应用添加搜索功能

为Android应用添加搜索功能 为Android应用增加搜索功能:增加搜索建议

runtime-给系统已有类添加属性

在没有接触runtime之前,我们接触到的能给类进行扩展的方法有类目(category)和延展(extension)两种.类目(category)可以给系统已有类添加扩展方法但是不能添加属性,并且被添加的方法可以被此类的子类所继承:延展(extension)为我们的自定义类添加属性和方法,但是添加的属性和方法都是私有的,在此类的子类中是无法访问的.那么问题来了,如果我们想给系统已有类添加一些方便我们使用的属性要怎么办呢?上述这两种方法中能给系统已有类添加的东西的就只有类目(category)了.

修复Bug是重点 iOS9将不注重添加新功能

苹果iOS7系统时发生了界面风格的巨大改变,目前的iOS8也在延续之前的风格,只是进行了功能补充,那么iOS9是否还会继续保持这样的风格呢?据外媒消息,iOS9的确不会再次对风格进行大修大改,而是着重改进稳定性和系统优化. iOS9将不注重添加新功能(图片来自MacWorld) 据外媒从苹果内部工程师处获知,iOS9的主要工作是修复漏洞.保持系统的稳定性,并增强系统性能,并不会特别注重对新功能的开发. 另外,近期苹果因iOS8系统固件体积过大而多次被用户告上法庭,看来是起到了一定效果.据称苹果将

PropertyGrid—添加属性Tab

零.引言 PropertyGrid用来显示和编辑对象的属性,前面已经简单介绍了如何使用该控件和提供不同的属性编辑方法.前面主要讲如何使用该控件,但有时,该控件无法满足我们的需求,就需要对其进行扩展.本文主要介绍如何在PropertyGrid中添加属性选项卡(PropertyTab).VS自带的属性框有属性和事件两个属性卡,下面简单说明如何添加自己的选项卡. 一.PropertyGrid的组成 在添加选项卡之前,先来看一看PropertyGrid的组成,分析其组成对后面设计十分有用.微软将Prop

java-第十四章-代参的方法(二)-实现MyShopping系统的添加会员功能

 package com.wxws.sms; public class Customer {  int No;  int integarl; } package com.wxws.sms; public class Customers {  Customer[] customers = new Customer[100];  public void add(Customer cust){   for (int i = 0; i <customers.length; i++) {    if (c

(译)Windsor入门教程---第五部分 添加日志功能

介绍 现在我们已经有了基础的框架了,是时候添加内容了,那么我们首先应该考虑的就是在应用程序中添加日志功能.我们会使用Windsor来配置,在这一部分,你将学习Windsor之外的其他功能. Logging Facility 在上一部分说过,Windsor有很多自带的可选的功能组件,他们扩展了Windsor的即用性.在这一部分,我们将在程序中添加日志功能. Logging Facility提供了一些常用的日志框架比如Log4net.Nlog,以及mvc内置的日志框架Trace.Logging Fa