65.9K
CodeProject 正在变化。 阅读更多。
Home

AGM::LibReflection 的更新: C++ 的反射库

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.32/5 (8投票s)

2005年3月28日

4分钟阅读

viewsIcon

116734

downloadIcon

832

本文是对原始 AGM::LibReflection 库的更新。

引言

axilmar 编写的原始 LibReflection 存在不少限制,在本版本中已得到改进或放宽。本文仅描述新旧版本之间的区别。所有现有功能和语法仍然得到支持,并且在新版本中也能正常工作。因此,升级到新版本应与重新编译代码一样简单。读者应在继续阅读之前,先阅读 原始 LibReflection 文章

新版本更改/改进了以下项目

  1. 构造函数信息现在可以捕获并存储在 Class 对象中。此外,可以通过 new 运算符调用构造函数来创建对象。当默认构造函数通过反射进入 Class 时,Class::newInstance() 方法可以作为创建实例的快捷方式。示例
    using namespace agm::reflection;
    using namespace std;
    
    class Widget
    {
        CLASS(Widget, NullClass);
    
        CONSTRUCTOR(public, Widget, ())
        {
        cout << "default constructor called" << endl;
        }
        
        CONSTRUCTOR(public, Widget, (int y) )
        {
        cout << "Widget(int) called with " << y << endl;
        }
    
    };
    
    int main()
    {
        Widget w;
        const Class & cls = w.getClass();
        Widget* wp = static_cast<Widget*>( cls.newInstance() );
        delete wp;
    }
  2. 在原始版本中,方法参数类型和返回类型未被捕获。这已得到更改。用户现在可以检索方法参数和返回类型的类型信息(以 std::type_info 的形式)。使用上面 Widget 的类定义
        const Class::ConstructorList & constructors = cls.getConstructors();
        for (Class::ConstructorList::const_iterator iter = constructors.begin();
             iter != constructors.end();
             ++iter)
        {
            const ConstructorMethod& cm = *iter;
            // we will look for Widget(int) constructor
            if (cm.getArgsCount() == 1 && *cm.getArgsTypes()[0] == typeid(int))
            {
            cout << "Found Widget(int) constructor" << endl;
            Widget *wp2;
            cm.invoke(wp2, 12);
            
            delete wp2;
            }
        }
  3. 类方法、静态方法和构造函数可以被重载。用户可以搜索并遍历所有重载的方法来选择他们想要的方法。这通常通过检查参数类型并返回方法候选项的类型来完成。构造函数重载的示例已在上面显示。静态方法和类方法的定义类似。不再需要使用不同的宏。
  4. 添加了简单的类注册表。这允许用户列出或搜索所有“已知”类的集合。使用上面的 Widget 示例
        const Class * wcls = Class::forName("Widget");
    
        if (wcls != 0)
        {
        cout << "Calling newInstance()" << endl;
        Widget* wp = static_cast<Widget*>( wcls->newInstance() );
        }
  5. 改进了对 TypeMismatchError 的描述。当一个方法(无论是构造函数、静态方法还是类成员方法)被使用不兼容类型调用时,抛出的异常将包含有关哪个参数不兼容的详细信息。以下是抛出的 TypeMismatchError 异常的示例
    terminate called after throwing an instance of 
                             'agm::reflection::TypeMismatchError'
     what():  static Label* Label::self(Label*):
    (WARN only: type castable)return type mismatched: expected 
                                     (Label*) passed (Widget*);
    Parameter 1 mismatched: expected (Label*) passed (Widget*);
  6. 完整的类名(包括命名空间)现在可以被捕获,并通过 Class::getFullName() 查询。类似地,方法(构造函数、静态、成员)现在包含一个新方法 getSignature(),它返回人类可读的类和参数类型。
  7. 自动转换兼容指针和引用类型的对象类。例如,如果一个方法(构造函数、静态方法、成员方法)接受 Base *,但传递了 Derived * 作为参数,则 Derived * 将被自动转换为 Base *。原始版本在参数类型不完全匹配时会直接抛出 TypeMismatchError 异常。这同样适用于返回值。要求是 BaseDerived 都必须使用反射进行定义。
    class Label : public Widget
    {
        CLASS(Label, Widget);
    
        CONSTRUCTOR(public, Label, ())
        {
        cout << "Label:: default constructor called" << endl;
        }
        STATIC_METHOD(public, Label *, self, (Label *that) )
        {
        cout << "The object type is " << that->getClass().getFullName() << endl;
        return that;
        }
    
    };
    
    int main()
    {
        Label l;
        Widget* wp = &l;
        Widget* wp_result;
        l.getClass().getStaticMethod("self").invoke(wp_result, &l);
        /* wp_result pointer to a Label * object */
    }

    在此示例中,self() 返回一个 Label *,但传递的返回对象是 Widget *。返回的指针已自动转换。

  8. 动态类型转换为其对象类(向下转型),适用于兼容的指针类型。当一个方法期望 Derived * 但传递的参数是 Base * 时,反射库将尝试通过 C++ 的 dynamic_cast<> 运算符将 Base * 转换为 Derived *。如果转换不成功,将抛出 TypeMismatchError 异常;否则将进行调用。使用前面的示例
        l.getClass().getStaticMethod("self").invoke(wp_result, wp);
        /* wp is of type Widget *, but the argument requires a Label * */
  9. LibReflection 库现在也适用于模板类。然而,模板化方法函数不能被反射。这是从 template.cpp 文件中的示例代码中提取的
    template <class T> class Widget
    {
        CLASS(Widget, NullClass);
    
        CONSTRUCTOR(public, Widget, ())
        : storage()
        {
        cout << "default constructor called" << endl;
        }
    
        CONSTRUCTOR(public, Widget, (const Widget& x) )
        : storage(x.storage)
        {
        cout << "copy constructor called" << endl;
        }
    
        CONSTRUCTOR(public, Widget, (const T& y) )
        : storage(y)
        {
        cout << "Widget(T) called with " << y << endl;
        }
    
        METHOD(public, void, store, (T x))
        {
        cout << "calling store with " << x << endl;
        this->storage = x;
        }
    
        virtual ~Widget() {}
    
    private:
        T storage;
    };
    
    template <class X, class Y> class Label : public Widget<X>
    {
        CLASS(Label, Widget<X>);
        CONSTRUCTOR(public, Label, ())
        : Widget<X>(), y_store()
        {
        cout << "default constructor called" << endl;
        }
    
        CONSTRUCTOR(public, Label, (const Label& x) )
        : Widget<X>(x), y_store(x.y_store)
        {
        cout << "copy constructor called" << endl;
        }
    
        CONSTRUCTOR(public, Label, (const X & x, const Y & y) )
        : Widget<X>(x), y_store(y)
        {
        cout << "Label(x,y) called with " << y << endl;
        }
    
        METHOD(public, void, store2nd, (Y y))
        {
        cout << "calling store2nd with " << y << endl;
        y_store = y;
        }
    
        
    private:
        Y y_store;
    };
  10. 添加了对无 MACRO 的动态反射的支持。任何公共类都可以使用模板类 ReflectiveClass 添加到 LibReflection 中。在 LibReflection 中定义的类与使用 MACRO 方法添加的类是相同的。这种反射方法适用于无法修改类定义的任何类(例如供应商库)。以我们喜欢的 Widget / Label 示例为例,这是使用动态反射定义的相同代码
    class Label : public Widget
    {
        public:
            Label()
        {
        cout << "Label:: default constructor called" << endl;
        }
        
        static Label * self (Label *that) 
        {
        cout << "The object type is " << that->getClass().getFullName() << endl;
        return that;
        }
    
    };
    
    // dynamic class reflection to LibReflection
    static const ReflectiveClass<Label> label_clsdef = 
                         ReflectiveClass<Label>((Widget*)0)
        .constructor()
        .static_method(&Label::self, "self");

    唯一细微的区别是,由于类未被修改,getClass()getStaticClass() 不再是 Label 类的一部分。可以通过 label_clsdef.get() 或使用类注册表 Class::forType(const std::type_info&) 静态成员函数来获取 agm::reflection::Class *

  11. 添加了自定义用户定义宏。用户可以在包含反射头文件之前定义宏 REFLECTION_TYPE_CUSTOMx,其中 x 是 1 到 4。如果定义了,该宏应计算为一个 const std::type_info& 对象。自定义类型宏在用户必须能够查找模板类中的特定类时很有用。例如,使用 boost 库的智能指针,我们可以有以下定义:#define REFLECTION_TYPE_CUSTOM1(C) typeid(boost::shared_ptr<C>)。然后我们可以通过使用 Class::findType(const std::type_info& t) 来测试相应的类型。当参数的确切类型未知时,这尤其有用。
  12. 添加了对放置实例化的支持(也称为 placement new)。ConstructorMethod 可以通过 invoke()invokePlacement() 调用,后者接受一个额外的 void * 用于对象的放置。
  13. 移植到 GCC。这可以被视为一个非改进,因为新版本尚未在 MSVC 或 VS.NET 下进行测试。

限制(与原始版本相同)

  • 在类“已知”之前必须创建该类的一个实例。
  • 仅支持单重继承,不支持虚基类。
  • 编译器最初进行的一些隐式转换将不会执行。例如:long -> intconst char * -> string 等。
© . All rights reserved.