有没有办法在运行时向一个类添加一个字段(以前不存在的字段)?像这个片段:
Myobject *ob; // create an object
ob->addField("newField",44); // we add the field to the class and we assign an initial value to it
printf("%d",ob->newField); // now we can access that field
我真的不在乎它将如何完成,我不在乎它是否是一个丑陋的黑客,我想知道它是否可以完成,如果可能的话,还有一个小例子。
另一个例子:说我有一个描述这个类的XML文件:
<class name="MyClass">
<member name="field1" />
<member name="field2" />
</class>
我希望将“field1”和“field2”字段“添加”到类中(假设该类已经存在)。假设这是该类的代码:
class MyClass {
};
我不想在运行时创建一个类,我只想将成员/字段添加到现有的类中。
谢谢!
答案 0 :(得分:13)
例如,使用boost :: variant。见http://www.boost.org/doc/libs/1_36_0/doc/html/variant.html
(但是,当然,您可以创建自己的,以适应XML属性的类型。)
#include <map>
#include <boost/variant.hpp>
typedef boost::variant< int, std::string > MyValue ;
typedef std::map<std::string, MyValue> MyValueMap ;
通过将MyValueMap添加为您的类的成员,您可以根据其名称添加属性。这意味着代码:
oMyValueMap.insert(std::make_pair("newField", 44)) ;
oMyValueMap.insert(std::make_pair("newField2", "Hello World")) ;
std::cout << oMyValueMap["newField"] ;
std::cout << oMyValueMap["newField2"] ;
通过将其封装在MyObject类中,并在此MyObject类中添加正确的重载访问器,上面的代码变得更加清晰:
oMyObject.addField("newField", 44) ;
oMyObject.addField("newField2", "Hello World") ;
std::cout << oMyObject["newField"] ;
std::cout << oMyObject["newField2"] ;
但是你在某种程度上失去了C ++的类型安全性。但对于XML,我猜这是不可避免的。
答案 1 :(得分:4)
由于编译器需要在编译时解析引用,因此无法按照您描述的方式执行此操作 - 它将生成错误。
答案 2 :(得分:3)
您无法使该语法有效(因为在编译时进行静态检查),但如果您愿意修改语法,则可以非常轻松地实现相同的效果。使用字符串 - > blob映射的字典成员相当容易,并且具有以下成员函数:
template< typename T > T get_member( string name );
template< typename T > void set_member( string name, T value );
如果需要,可以使语法更紧凑/更棘手(例如:使用' - &gt;'运算符覆盖)。您还可以使用一些特定于编译器的技巧(例如,MSVC支持__declspec(属性),它允许您将对成员变量的引用映射到特定格式的方法)。但是,在一天结束时,您将无法执行编译器不接受的语言并将其编译。
答案 3 :(得分:2)
简短版本:无法做到。没有本机支持,c ++是静态类型的,编译器必须知道要操作的每个对象的结构。
建议:使用嵌入式互操作程序。并且不要编写自己的(见下文),得到一个已经工作并调试过的。
您可以做什么:根据您的需求实施足够的互操作程序。
使用像
这样的数据成员设置类很简单std::vector<void*> extra_data;
您可以在运行时附加任意数据。这样做的代价是您必须使用以下方法手动管理数据:
size_t add_data_link(void *p); // points to existing data, returns index
size_t add_data_copy(void *p, size_t s) // copies data (dispose at
// destruction time!), returns
// index
void* get_data(size_t i); //...
但这不是限制,稍加注意,你可以将任意数据与名称相关联,你可以继续详细说明这个方案(添加类型信息等等),但是这归结为实现一个interperter来处理你的运行时灵活性。
答案 4 :(得分:0)
否 - C ++不支持对此类型系统的任何操作。即使是具有某种程度的运行时反射的语言(例如.NET)也不会完全支持这种范例。你需要一种更加动态的语言才能做到这一点。
答案 5 :(得分:0)
我正在看这个,我做了一些搜索,这个代码片段来自:Michael Hammer's Blog 使用boost::any
似乎是一种很好的方法首先定义一个定义std :: map的结构,该地图包含一个键(即变量名)和值。定义一个函数以对该对进行设置,并将其与函数一起设置以获取该值。如果你问我这很简单,但在做更复杂的事情之前,这似乎是一个很好的方式。
struct AnyMap {
void addAnyPair( const std::string& key , boost::any& value );
template<typename T>
T& get( const std::string key ) {
return( boost::any_cast<T&>(map_[key]) );
}
std::map<const std::string, boost::any> map_;
};
void AnyMap::addAnyPair( const std::string& key , boost::any& value ) {
map_.insert( std::make_pair( key, value ) );
}
最重要的是,这是一个黑客行为,因为C ++是严格的类型检查语言,因此怪物可以用于那些弯曲规则的人。