像C++中的功能属性?

2 c++

我的使用非常复杂.我有一堆objs,它们都被ptr传递(不是引用或值,除非它是一个byval的枚举).在特定时间点,我想调用CheckMembers(),它将检查每个成员是否已设置或为空.默认情况下,我不能使它全部为null因为我不知道我是否将它设置为null或如果它仍然是空的bc我没有触及它自ctor.

要分配变量,我仍然需要语法为正常var = p; var->member = new Type;.我生成所有的类/成员.所以我的问题是如何实现类似属性的属性,我可以检测该值是否已设置或保留为默认值?

我想也许我可以使用C++与CLR/.NET http://msdn.microsoft.com/en-us/library/z974bes2.aspx但我以前从未使用过它并且不知道它将如何工作以及可能会有什么用在我的C++ prj中打破(它使用rtti,模板等).

e.J*_*mes 6

现实(编辑):这被证明是棘手的,但以下代码应该处理您的要求.它在基类中使用一个简单的计数器.对于要跟踪的每个属性,计数器递增一次,然后对于设置的每个属性递减一次.该checkMembers()函数只需要验证计数器是否等于零.作为奖励,你可能会报告有多少成员未初始化.

#include <iostream>

using namespace std;

class PropertyBase
{
    public:
        int * counter;
        bool is_set;
};

template <typename T>
class Property : public PropertyBase
{
    public:
        T* ptr;
        T* operator=(T* src)
        {
            ptr = src;
            if (!is_set) { (*counter)--; is_set = true; }
            return ptr;
        }
        T* operator->() { return ptr; }
        ~Property() { delete ptr; }
};

class Base
{
    private:
        int counter;
    protected:
        void TrackProperty(PropertyBase& p)
        {
            p.counter = &counter;
            counter++;
        }
    public:
        bool checkMembers() { return (counter == 0); }
};

class OtherObject : public Base { }; // just as an example

class MyObject : public Base
{
    public:
        Property<OtherObject> x;
        Property<OtherObject> y;
        MyObject();
};

MyObject::MyObject()
{
    TrackProperty(x);
    TrackProperty(y);
}

int main(int argc, char * argv[])
{
    MyObject * object1 = new MyObject();
    MyObject * object2 = new MyObject();

    object1->x = new OtherObject();
    object1->y = new OtherObject();

    cout << object1->checkMembers() << endl; // true
    cout << object2->checkMembers() << endl; // false

    delete object1;
    delete object2;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)


bdo*_*lan 6

有很多方法可以做到这一点,在空间开销方面有不同的权衡.例如,这是一个选项:

#include <iostream>

template<typename T, typename OuterClass>
class Property
{
public:
    typedef void (OuterClass::*setter)(const T &value);
    typedef T &value_type;
    typedef const T &const_type;
private:
    setter set_;
    T &ref_;
    OuterClass *parent_;
public:
    operator value_type() { return ref_; }
    operator const_type() const { return ref_; }

    Property<T, OuterClass> &operator=(const T &value)
    {
        (parent_->*set_)(value);
        return *this;
    }

    Property(T &ref, OuterClass *parent, setter setfunc)
        : set_(setfunc), ref_(ref), parent_(parent)
    { }
};


struct demo {
    private:
        int val_p;
        void set_val(const int &newval) {
            std::cout << "New value: " << newval << std::endl;
            val_p = newval;
        }

    public:
        Property<int, demo> val;

        demo()
            : val(val_p, this, &demo::set_val)
        { }
};

int main() {
    demo d;
    d.val = 42;
    std::cout << "Value is: " << d.val << std::endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

4 * sizeof(void*)使用模板访问器可以减少开销(这有很多字节开销) - 这是另一个例子:

#include <iostream>


template<typename T, typename ParentType, typename AccessTraits>
class Property
{
private:
    ParentType *get_parent()
    {
        return (ParentType *)((char *)this - AccessTraits::get_offset());
    }
public:
    operator T &() { return AccessTraits::get(get_parent()); }
    operator T() { return AccessTraits::get(get_parent()); }
    operator const T &() { return AccessTraits::get(get_parent()); }
    Property &operator =(const T &value) {
        AccessTraits::set(get_parent(), value);
        return *this;
    }
};

#define DECL_PROPERTY(ClassName, ValueType, MemberName, TraitsName) \
    struct MemberName##__Detail : public TraitsName { \
        static ptrdiff_t get_offset() { return offsetof(ClassName, MemberName); }; \
    }; \
    Property<ValueType, ClassName, MemberName##__Detail> MemberName;

struct demo {
    private:
        int val_;

        struct AccessTraits {
            static int get(demo *parent) {
                return parent->val_;
            }

            static void set(demo *parent, int newval) {
                std::cout << "New value: " << newval << std::endl;
                parent->val_ = newval;
            }
        };
    public:
        DECL_PROPERTY(demo, int, val, AccessTraits)

        demo()
        { val_ = 0; }
};

int main() {
    demo d;
    d.val = 42;
    std::cout << "Value is: " << (int)d.val << std::endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这只占用属性struct本身的一个字节; 但是,它依赖于offsetof()不可移植的行为(技术上不允许在非POD结构上使用它).对于更便携的方法,您可以this在成员变量中隐藏父类的指针.

请注意,这两个类都只是勉强够证明的技术-你要超载operator*operator->等,也是如此.

  • 是的,如果您让属性类包含支持值,则更容易实现 - 但我很享受挑战:) (2认同)