有没有办法在运行时向一个类添加一个字段(以前不存在的字段)?像这个片段:

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 {
};

我不想在运行时创建一个类,我只想将成员/字段添加到现有的类中。

谢谢!

有帮助吗?

解决方案

使用地图和变体。

例如,使用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,我猜这是不可避免的。

其他提示

由于编译器需要在编译时解析引用,因此无法按照您描述的方式执行此操作 - 它将生成错误。

但请参阅通用设计模式

您无法使该语法有效(因为在编译时进行静态检查),但如果您愿意修改语法,则可以非常轻松地实现相同的效果。使用字符串 - > blob映射的字典成员相当容易,并且具有以下成员函数:

template< typename T > T get_member( string name );
template< typename T > void set_member( string name, T value );

如果需要,可以使语法更紧凑/更棘手(例如:使用' - &gt;'运算符覆盖)。您还可以使用一些特定于编译器的技巧(例如,MSVC支持__declspec(属性),它允许您将对成员变量的引用映射到特定格式的方法)。但是,在一天结束时,您将无法执行编译器不接受的语言并将其编译。

简短版本:无法做到。没有本机支持,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来处理你的运行时灵活性。

否 - C ++不支持对此类型系统的任何操作。即使是具有某种程度的运行时反射的语言(例如.NET)也不会完全支持这种范例。你需要一种更加动态的语言才能做到这一点。

我正在看这个,我做了一些搜索,这个代码片段来自: Michael Hammer的博客 似乎是一个很好的方法,通过使用 boost ::任何

首先定义一个定义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 ++是严格的类型检查语言,因此怪物可以用于那些弯曲规则的人。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top