像C ++中的功能属性?

时间:2011-05-21 01:38:15

标签: c++

我的使用非常复杂。我有一堆objs,它们都被ptr传递(不是引用或值,除非它是一个byval的枚举)。在特定时间点,我想调用CheckMembers(),它将检查每个成员是否已设置或为空。默认情况下我不能使它全部为null因为我不知道我是否将它设置为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,模板等等。)

3 个答案:

答案 0 :(得分: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;
}

答案 1 :(得分: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;
}

使用模板访问器可以减少开销(这需要高达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;
}

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

请注意,这两个类仅仅足以演示该技术 - 您还需要重载operator*operator->等。

答案 2 :(得分:2)

这是我的临时替代方案。一个不要求构造函数参数。

#include <iostream>
#include <cassert>

using namespace std;

template <class T>
class Property
{
    bool isSet;
    T v;
    Property(Property&p) { }
public:
    Property() { isSet=0; }
    T operator=(T src) { v = src; isSet = 1; return v; }
    operator T() const { assert(isSet); return v; }
    bool is_set() { return isSet; }
};

class SomeType  {};
enum  SomeType2 { none, a, b};
class MyObject
{
public:
    Property<SomeType*> x;
    Property<SomeType2> y;
    //This should be generated. //Consider generating ((T)x)->checkMembers() when type is a pointer
    bool checkMembers() { return x.is_set() && y.is_set(); }
};

int main(int argc, char * argv[])
{
    MyObject* p = new MyObject();
    p->x = new SomeType;
    cout << p->checkMembers() << endl; // false
    p->y = a;
    cout << p->checkMembers() << endl; // true
    delete p->x;
    delete p;
}