C++ 创建动态属性
功能清单
-
支持属性动态添加,如:
Properties p; p.Add<int>("age", 10); // 属性名称用枚举,或者字符串 int age = p.Get<int>("age");
-
支持查看属性是不是有更新,如:
p.IsDirty<int>("age");
-
支持数据拷贝,如:
std::vector<PropertyName> propertyNames = p.GetAllPropertyNames(); for (auto& name : propertyNames) { if (p.IsDirty(name)) { p_inner.Set(p.Get(name)); } }
-
重置dirty属性,如:
p.ResetAll();
-
支持内存大小动态变化的属性。
基于模板的实现
from: https://stackoverflow.com/questions/20225392/c-dynamic-properties
#include <string>
#include <map>
using namespace std;
class Prop
{
public:
virtual ~Prop()
{
}
};
template<typename T>
class Property : public Prop
{
private:
T data;
bool isDirty;
public:
virtual ~Property()
{
}
Property(T d) : isDirty(true)
{
data = d;
}
void SetValue(T& d)
{
data = d;
}
T GetValue()
{
return data;
}
};
class Properties
{
private:
map<string, Prop*> props;
public:
~Properties()
{
map<string, Prop*>::iterator iter;
for(iter = props.begin(); iter != props.end(); ++iter)
delete (*iter).second;
props.clear();
}
template<typename T>
void Add(string name, T data)
{
if (props.count(name) != 0)
{
props[name]->SetValue(data);
}
else
{
props[name] = new Property<T>(data);
}
}
template<typename T>
T Get(string name)
{
Property<T>* p = (Property<T>*)props[name];
return p->GetValue();
}
bool IsDirty(string name)
{
if (props.count(name) == 0)
{
return false;
}
return props[name]->IsDirty();
}
};
int main()
{
Properties p;
p.Add<int>("age", 10);
int age = p.Get<int>("age");
return 0;
}
基于boost::any
参见:https://www.cnblogs.com/youxin/p/4451950.html
class Property
{
boost::any value_;
bool dirty_;
public:
property(const std::string& name,const boost::any& value)
: value_(value)
,dirty_(true)
{}
void SetValue(const boost::any& value)
{
value_ = value;
dirty_ = true;
}
boost::any& GetValue() { return value_; }
bool IsDirty()
{
return dirty_;
}
friend bool operator<(const property& lhs, const property& rhs)
{
return lhs.name_<rhs.name_;
}
};
class Properties
{
private:
map<string, Property> props;
public:
void Add(string name, boost::any data)
{
if (props.count(name) != 0)
{
props[name].SetData(data);
}
else
{
props[name] = Property(data);
}
}
template<typename T>
T& Get(string name)
{
return boost::any_cast<T>(props[name].GetValue());
}
bool IsDirty(string name)
{
if (props.count(name) == 0)
{
return false;
}
return props[name].IsDirty();
}
};
int main()
{
Properties p;
p.Add("age", 10);
int age = p.Get<int>("age");
return 0;
}
扩展
利用动态属性进行继承的时候,需要让调用者知道具体的属性是什么,因此可以构建辅助类。具体如下:
class CommonColorHelper
{
public:
typedef Vector3D ColorType;
string GetColorName();
ColorType GenerateColorValue(double r, double g, double b, double a);
string GetAmbientColorName();
ColorType GenerateAmbientColorValue(double r, double g, double b, double a);
string GetDiffuseColorName();
ColorType GenerateDiffuseColorValue(double r, double g, double b, double a);
};
int main()
{
Properties p;
CommonColorHelper colorHelper;
p.Add(colorHelper.GetColorName(), colorHelper.GenerateColorValue(1.0,1.0,1.0,1.0));
auto color = p.Get<CommonColorHelper::ColorType>(colorHelper.GetColorName());
}
VTK的实现
概念参考:VTK修炼之道82:VTK管线机制_信息对象类VTKInformation
VTK最内部的实现代码如下:
//----------------------------------------------------------------------------
class vtkInformationInternals
{
public:
typedef vtkInformationKey* KeyType;
typedef vtkObjectBase* DataType;
#ifdef VTK_INFORMATION_USE_HASH_MAP
struct HashFun
{
size_t operator()(KeyType key) const { return static_cast<size_t>(key - KeyType(nullptr)); }
};
typedef std::unordered_map<KeyType, DataType, HashFun> MapType;
#else
typedef std::map<KeyType, DataType> MapType;
#endif
MapType Map;
#ifdef VTK_INFORMATION_USE_HASH_MAP
vtkInformationInternals()
: Map(33)
{
}
#endif
~vtkInformationInternals()
{
for (MapType::iterator i = this->Map.begin(); i != this->Map.end(); ++i)
{
if (vtkObjectBase* value = i->second)
{
value->UnRegister(nullptr);
}
}
}
private:
vtkInformationInternals(vtkInformationInternals const&) = delete;
};
最后是通过一个map将KeyType和DataType关联起来。
具体KeyType都是继承vtkInformationKey实现,具体的DataType都是继承vtkObjectBase实现。
另一个关键的类是vtkInformation,这里仅截取片段:
class VTKCOMMONCORE_EXPORT vtkInformation : public vtkObject
{
public:
// 实现了很多get set一类的函数,如:
//@{
/**
* Get/Set an integer-pointer-valued entry.
*/
void Set(vtkInformationIntegerPointerKey* key, int* value, int length);
int* Get(vtkInformationIntegerPointerKey* key);
void Get(vtkInformationIntegerPointerKey* key, int* value);
int Length(vtkInformationIntegerPointerKey* key);
void Remove(vtkInformationIntegerPointerKey* key);
int Has(vtkInformationIntegerPointerKey* key)
//@}
};