首页 > 代码库 > 跟陈湾来完善C++(2), 添加属性功能

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

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


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

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

没有

a.Value = http://www.mamicode.com/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方法来完成,即使有了属性功能也不常用。而且并没有省多少事。但是有的语言有这个功能就当是写着玩吧。


技术分享

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