http://blog.csdn.net/torytin/article/details/7557698
以前一直是C++的coder,最近由于到了另一家公司,因此开始写Java项目,相信C++的程序员都会对java语言原生支持的动态生成很是羡慕,但是C++不支持反射(reflection),也就无法根据类名动态创建对象,MFC的做法是继承CObject并用DECLARE_DYNCREATE宏来实现,MFC这么实现是由于一些系统遗留问题,感觉用起来不是那么的friendly。今天下午坐着无聊,仿造java的结构构思了下C++的动态生成实现方法。
基本想法:
1.java的所有类都默认继承自Object类,在C++中我们也需要这么一个公用的基类。
2.java中每个类都有对应的一个Class类,用来动态创建类对象,我们也定义一个Class类
3.java中可以用Class.forName(String className)来获得相应的Class类,我们的Class类也应该支持这种方式
4.java中用Class.newInstance()动态生成类的实例,其实Class类在这里就相当于一个Factory,我们也提供这种方式
基本上,只要实现了上述4个条件,类的动态创建就跟java的方式差不多了,具体代码如下:
核心代码:
Class.h
Class.cpp
用户类: 这里为了演示的需要定义了两个用户类
Example.h
Example.cppExample1.h
Example1.cpp
How to Use:
output
这样c++就就基本实现了java的动态生成机制,相比java来说,我们继承Object的同时还需要调用Class::Register函数注册一下,上面对于Class对象的示例代码中是直接比较指针地址,用户也可以重写Class对象的operator==来根据Class的name是否相等进行比较。另外一个缺陷是无法判断一个类是否是一个类的子类实例,比如我再写一个类SubExample继承Example,但目前是无法判断一个SubExample是否是一个Example的,如果需要做到这点,可以保存整个类的继承关系图,就是Class初始化的时候再加一个父类型参数,然后把整个继承关系保存下来。可以参见完善版本:C++对象动态生成(Dynamic Create)的完善版本
-------------------------------------------------------------我是分割线--------------------------------------------------------------
对于zhouguidi 提出的模板类的动态创建问题,可能不只一个网友会遇到,这里贴出一些可能的实现思路和代码。由于C++模板类的实现机理是一个类定义应用于多个类,只有当用户指定具体的类型之后,类定义才真正完整,也就是说一个模板类可以生成无穷个类。对于动态创建模板类对象来说,我们不可能把这些无穷个类都进行注册,因此有以下两种解决方案:
1.穷举法:对于所有用到的模板类,在程序开始的某一段代码里面进行穷举注册
Class::Register<TemplateExample<int>>("TemplateExample<int>");
Class::Register<TemplateExample<float>>("TemplateExample<float>");
Class::Register<TemplateExample<double>>("TemplateExample<double>");
……
然后后续代码就可以通过Class::forName("TemplateExample<int>")等来获得对应模板类的Class对象,这种方法比较容易理解,也比较通用,不管类型参数是基本类型还是自定义类型都可以使用,但代码有点冗余繁琐。
2.自动注册:该方法的好处是不需要再写很多重复的Register语句,但需要对模板类的类型参数有一定的约定,因此只能应用于模板类的类型参数是自定义类型的情况,具体见代码
TemplateExample.h
TemplateExample.cpp
How to Use:
output
今天重新跑了下该示例程序,发现还存在一个似乎跟编译器相关的问题,如果整个代码中都没有引用到某个类的theClass变量,那么该变量是不会初始化的,也就是Class::Register函数不会被调用,该类也就没有注册。因此我在TemplateExample的初始化函数中用了一下theClass->getName()来输出类的名字,以确保会初始化该变量,我用的是elipse的g++编译器(按我原来的理解,既然类生产了,必然会初始化类的静态成员,但实际不是,只有真正代码中使用到过才会初始化该静态成员变量,这应该是g++编译器的一个优化,不知道别的编译器会不会也做同样的处理)