【问题标题】:C++ dynamic class ( dynamic hack )C++动态类(动态破解)
【发布时间】:2010-09-19 02:53:45
【问题描述】:

有没有办法在运行时向类添加字段(以前不存在的字段)?像这样的 sn-p :

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

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

谢谢!

【问题讨论】:

  • 编辑了您的问题以正确显示内容... :-) ...

标签: c++ dynamic


【解决方案1】:

使用地图和变体。

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

【讨论】:

  • 谢谢paercebal!能不能重载->达到我说的效果?
  • 不,抱歉,因为您添加的“newField”尚未编译,仅在运行时创建,因此它不能用于代码符号,只能用于字符串(那里,尽管有一些缺点,operator[] 是一个闪亮的语法糖)。
  • @vhaerun 你会在 -> 后面输入什么?如果你知道答案,你就不需要在运行时添加变量!
  • @paercebal:我不明白你为什么认为后者会失去类型安全性。它的安全性不亚于使用变体开始是吗?
  • @Mooing Duck :当我写“你失去了 C++ 的类型安全”时,我确实是在暗示:“[通过使用变体] 你失去了 C++ 的类型安全”
【解决方案2】:

没有办法按照您描述的方式进行,因为编译器需要在编译时解析引用 - 它会产生错误。

但请参阅The Universal Design Pattern

【讨论】:

    【解决方案3】:

    您无法使该语法工作(因为在编译时进行静态检查),但是如果您愿意修改语法,则可以很容易地达到相同的效果。拥有一个带有 string->blob 映射的字典成员会相当容易,并且具有如下成员函数:

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

    如果您愿意,您可以使语法更紧凑/更复杂(例如:使用“->”运算符覆盖)。您还可以利用一些特定于编译器的技巧(例如,MSVC 支持 __declspec(property),它允许您将对成员变量的引用映射到特定格式的方法)。但是,归根结底,您将无法做编译器在该语言中不接受的事情并让它编译。

    【讨论】:

    • 我以为模板在编​​译后就完成了。因此,我看不到这段代码如何在类中生成运行时成员,例如给定输入,向类添加一个变量。这不是通过模板可以完成的事情。也许,我没有得到你的解决方案,因此我不会投反对票。我只是好奇你的想法。
    • @G24l:我假设这是一个包含变体映射的类,在这种情况下它编译得很好
    【解决方案4】:

    短版:做不到。对此没有本机支持,c++ 是静态类型的,编译器必须知道要操作的每个对象的结构。

    建议:使用嵌入式解释器。并且不要自己编写(见下文),获得一个已经可以工作和调试的。


    您可以做什么:实施刚好满足您需求的interperter。

    使用像这样的数据成员设置类很简单

    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 来照顾您的运行时灵活性。

    【讨论】:

    • paercebal 的回答与此类似,并且使用了更多的 c++ 习语。我的看起来很像一个塞进一个班级的解决方案,因为它就是这样......
    【解决方案5】:

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

    【讨论】:

      【解决方案6】:

      我正在看这个,我做了一些搜索,这个代码 sn-p 来自: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 ) );
      }
      

      归根结底,这是一个 hack,因为 C++ 是严格的类型检查语言,因此对于那些违反规则的人来说是个怪物。

      【讨论】:

        猜你喜欢
        • 2014-02-23
        • 1970-01-01
        • 1970-01-01
        • 2020-07-03
        • 2013-05-05
        • 1970-01-01
        • 1970-01-01
        • 2014-10-24
        • 1970-01-01
        相关资源
        最近更新 更多