Portability of Native C++ properties

前端 未结 4 453
北恋
北恋 2020-12-04 15:47

In Visual Studio, there is __declspec(property) which creates properties similar to C#. Borland C++ offers the __property keyword with the exact same functiona

4条回答
  •  -上瘾入骨i
    2020-12-04 16:28

    I like the answer of 6502. It uses both less memory and is faster than the solution i will present. Only mine will have a bit syntactic sugar.

    I wanted to be able to wite something like this (with PIMPL idiom):

    class A {
    private:
        class FImpl;
        FImpl* Impl;
    
    public:
        A();
        ~A();
    
        Property Count;
        Property Count2;
        Property Str;
        Property Readonly;
    };
    

    Here comes the completet code (I am quite sure it is standard conformant):

    template 
    class IProperty_Forward {
    public:
        virtual ~IProperty_Forward() {}
        virtual const value_t& Read() = 0;
        virtual void Set(const value_t& value) = 0;
    };
    
    template 
    class TProperty_Forwarder: public IProperty_Forward
    {
    private:
        owner_t* Owner;
        getter_t Getter;
        setter_t Setter;
    public:
        TProperty_Forwarder(owner_t* owner, getter_t& getter, setter_t& setter)
        :Owner(owner), Getter(getter), Setter(setter)
        { }
    
        const value_t& Read()
            { return (Owner->*Getter)(); }
    
        void Set(const value_t& value)
            { (Owner->*Setter)(value); }
    };
    
    template 
    class Property {
    private:
        IProperty_Forward* forward;
    public:
        Property():forward(NULL) { }
    
        template 
        Property(owner_t* owner, getter_t getter, setter_t setter)
            { Init(owner, getter, setter); }
    
        ~Property()
            { delete forward; }
    
        template 
        void Init(owner_t* owner, getter_t getter, setter_t setter)
        {
            forward = new TProperty_Forwarder(owner, getter, setter);
        }
    
        Property& operator=(const value_t& value)
        {
            forward->Set(value);
            return *this;
        }
    
        const value_t* operator->()
        { return &forward->Read(); }
    
        const value_t& operator()()
            { return forward->Read(); }
    
        const value_t& operator()(const value_t& value)
        {
            forward->Set(value);
            return forward->Read();
        }
    
        operator const value_t&()
            { return forward->Read(); }
    };    
    

    And some implementation details:

    class A::FImpl {
        public:
            FImpl():FCount(0),FCount2(0),FReadonly("Hello") { }
    
            UnicodeString FReadonly;
            const UnicodeString& getReadonly()
                { return FReadonly; }
            void setReadonly(const UnicodeString& s)
                { }
    
            int FCount;
            int getCount()
                { return FCount; }
            void setCount(int s)
                { FCount = s; }
    
            int FCount2;
            int getCount2()
                { return FCount2; }
            void setCount2(int s)
                { FCount2 = s; }
    
            UnicodeString FStr;
            const UnicodeString& getStr()
                { return FStr; }
            void setStr(const UnicodeString& s)
                { FStr = s; }
    };
    
    A::A():Impl(new FImpl)
    {
        Count.Init(Impl, &FImpl::getCount, &FImpl::setCount);
        Count2.Init(Impl, &FImpl::getCount2, &FImpl::setCount2);
        Str.Init(Impl, &FImpl::getStr, &FImpl::setStr);
        Readonly.Init(Impl, &FImpl::getReadonly, &FImpl::setReadonly);
    }
    
    A::~A()
    {
        delete Impl;
    }
    

    I am using C++ Builder for anyone who wonders about the UnicodeString class. Hope it helps others for experimentation of Standard conforming c++ Properties. The basic mechanism is the same as 6502, with the same limitations.

提交回复
热议问题