C++ 实现反射(一)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/jcjc918/article/details/57487436

反射,就是根据一个类名,即可根据类名获取类信息,创建新对象。反射在很多语言都天然支持,然而不包括 C++,但我们肯定会经常遇到这种根据类名生成对象的场景,这就需要我们自己动手来实现了。反正 C++ 这么强大,一定没有问题 :)

version 1

我们略做思考,就可以想到一种最简单的方案:

if (class_name == "A") {
    return new A();
} else if (class_name == "B") {
    return new B();
} ...

当然,这个方案略做思考就可以否掉,这么暴力毫无美感,代码难以维护,每定义个新的类就需要添加一段新的 if,如果很多人共用和维护一定是场灾难。

Version 2

然而其实我没有放弃,看起来需要添加的代码这么相似,好像用个 template 可以解决?

#include <string>

template<typename BaseClassName, typename SubClassName>
BaseClassName* CreateObject() {
  return new SubClassName();
}

#define CLASS_OBJECT_CREATOR(base_class_name, sub_class_name) \
  CreateObject<base_class_name, sub_class_name>()

每次调用的时候只要形如 base* p = CLASS_OBJECT_CREATOR(base, A); 这样就好了,也许我们不知道传入的是哪个派生类,但都可以用基类的指针保存下来,像下面:

class base
{
  public:
    base() {}
    virtual test() { std::cout << "I'm class base!" << std::endl; }
    virtual ~base() {}
};
// 基类这里再封装一个宏,就不用每次都传入基类名
#define CreateMyClass(class_name) \
  dynamic_cast<class_name*>(CLASS_OBJECT_CREATOR(base, class_name));

class A : public base
{
  public :
    A(){ std::cout << "A constructor!" << std::endl; }
    virtual test() { std::cout << "I'm class A!" << std::endl; }
    ~A() { std::cout << "A destructor!" << std::endl; }
};

class B : public base
{
  public :
    B(){ std::cout << "B constructor!" << std::endl; }
    virtual test() { std::cout << "I'm class B!" << std::endl; }
    ~B() { std::cout << "B destructor!" << std::endl; }
};

int main()
{
    A* p1 = CreateMyClass(A);
    delete p;
    B* p2 = CreateMyClass(B);
    delete p2;
    return 0;
}

看起来好像没什么问题,只要调用 CreateMyClass(class_name) 就可以创建一个新的对象了。但总觉得哪里不对….仔细一想,如果类名是个字符串呢?CreateMyClass("A") 压根就没办法处理呀!因为 C++ 本质上无法处理 new "A" 这种语法所以才说不支持反射,像上面这样处理的话也根本没有解决这个问题,只是把 new 的语法用宏包装起来而已…囧…

还是认真想想怎么解决这个问题吧,见下篇

猜你喜欢

转载自blog.csdn.net/jcjc918/article/details/57487436