我正在尝试在c ++中实现一个实现一个方法的超类:
-void setValueForKey(void *value, string key);
所有这些方法都必须将与给定键关联的属性的值设置为新值。 在实现内省机制的语言中,这很容易;据我所知,C ++没有。
为了实现这个目的,我创造了另一种方法:
void registerKeyForProperty(void *propertyPtr, string key);
所有这个方法都是存储和内部映射指向与给定键关联的属性的指针,所以我的所有子类都会为它们声明的每个属性调用它,我将有一种方法来设置属性的值而没有必要使用setter。(这就是我需要的!)(我在帖子的最后解释了为什么......)
对于第二个函数,我有以下实现:
void registerKeyForProperty(void *propertyPtr, string key){
_keysDictionary->insert(pair<string,void*>(key,property));
}
其中_keysDictionary是一个stl地图。
对于第一个我有以下实现:
void ConstructableObject::setValueForKey(void* value, string key) {
map<string,void *>::iterator it=_keysDictionary->find(key);
if(it==_keysDictionary->end()){return;}//just return if there is nothing for that key
void *property=it->second;
(*property)=value;
}
问题是最后一行不是合法的C ++,因为当然我不能仅仅尊重无效*。
我的问题是:
还有其他方法可以实现所需的功能吗? 我这样做的方式是否有“合法”的方式? (我不能简单地使用reinterpret_cast因为我不知道要播放什么......)
为什么:
我需要解析包含某些对象信息的xml文件。我将使用TinyXML,因此我将拥有对象及其值的属性名称。这就是我想用它的方式:
MyClass obj();//the constructor would call setValueForKey(...,...) for every property so all are now registered
for every attribute{
obj.setValueForKey(attribute.value,attribute.name);
}
//all properties should be set now
答案 0 :(得分:1)
如果密钥存在,为什么不简单地执行
_keysDictionary[key] = value;
或者如果你想使用迭代器
it->second = value;
答案 1 :(得分:0)
使setValueForKey成为模板化函数,而不是接受void指针的函数。这样,您可以了解属性的类型信息足够长的时间来创建模板化的setter
class BaseSetter
{
public:
virtual void set(void* inValue) = 0;
}
template <typename T>
class SpecializedSetter
{
public:
SpecializedSetter(T* inMyValue)
: mValue(inValue)
{ }
virtual void set(void* inValue)
{
*mValue = *reinterpret_cast<T*>(inValue);
}
private:
T* mValue;
}
template <typename T>
void registerKeyForProperty(T* inValue, string inKey)
{
registerSetterForProperty(new SpecificSetter<T>(inValue), inKey);
}
但是,假设inValue是指向与类上的值相同类型的数据的指针。为了确保安全,请考虑boost::any
或定义包含XML文件中类型信息的其他类型并使用它而不是void *
答案 2 :(得分:0)
可以使用类型感知技术来完成,例如,Memento Pattern是其中一种选择。可以使用基于属性指针签名生成唯一键的一些宏内容扩展以下代码:
class introspection
{
public:
template <typename Class, typename Member>
void registerKey(std::string key, Member Class::*memberPointee, Class* classPointee)
{
typedef member_setter<Class, Member> hold_member_pointer;
base_setter* setter = new hold_member_pointer(memberPointee, classPointee);
keys.insert(std::make_pair(key, setter));
}
template <typename Value>
void setValue(std::string key, Value value)
{
if ( keys.count(key) > 0 )
{
keys[key]->set(value);
}
else
{
throw std::logic_error("no such key");
}
}
private:
struct base_setter
{
virtual void set(boost::any value) = 0;
}; // struct base_setter
template <typename Class, typename Member>
struct member_setter : base_setter
{
member_setter(Member Class::*memberPointee, Class* classPointee)
: memberPointee(memberPointee)
, classPointee(classPointee) {}
void set(boost::any value) override
{
Member newValue = boost::any_cast<Member>(value);
classPointee->*memberPointee = newValue;
}
Member Class::*memberPointee;
Class* classPointee;
}; // struct member_setter
std::map<std::string, base_setter*> keys;
}; // class introspection
struct Data
{
int value;
}; // struct Data
int main()
{
introspection i;
Data d;
d.value = 100;
i.registerKey("value", &Data::value, &d);
i.setValue("value", 200); // OK
i.setValue("value", "not valid"); // bad_any_cast
}
这里可以(不那么容易)改进的一件事是为setValue提供编译时类型检查,而不是运行时any_cast强制转换。