我的使用非常复杂。我有一堆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,模板等等。)
答案 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;
}