跟我学c++高级篇——反射
一、反射的概念
反射和自省,做为静态和动态时的处理的方式,导致的操作手段不尽相同。那么对c++来说,如何能够获取数据类型,在发展到今天,已经不是一个选择题,而是一个必选题。语言要想生存下去,就需要不断的创新和发展,不断的完善和迭代自己,那么做为高级语言中常见的反射,c++也在通过各种手段,在悄悄的补上这一课。直到最后c++标准的引入。
什么是反射(Reflection)?就是反映程序在动态运行时,检测、查寻和修改自身状态或者行为的一种能力。一般来说,通过反射可以获得:
1、指定对象的类型
2、获得相关对象的所有的成员变量和方法(对私有和保护不同的语言可能处理方式略有不同)。
3、动态创建对象。
4、在动态运行时调用相关对象的方法和函数及相关属性。
反射使语言的操作推进到了运行状态,但这不代表反射更加优秀,他也有不少的缺点:
1、性能,反射的过程导致整个运行时的动作会耗费更多的运行时间。
2、降低了可维护性。因为对运行状态期的理解不同,导致可能维护者对代码的理解不同。
3、反射使整体的业务逻辑变得复杂。
正所谓因人施教,因材施教,用得恰到好处,才是真得优秀的编程者。
二、反射的类别和应用场景
反射一般分为动态反射和静态反射两大类。当然在不同的语言中对反射的理解和处理都有些许的不同,需要注意。一般来说,动态语言如Python、c#等处理反射就非常容易,但对于静态语言如C,c++等这种过渡性高级语言,其实处理反射就比较麻烦。但是也不能说静态语言不能处理反射,比如c++可以通过宏或者SFINAE等技术做一些基本的反射动作。
这里要区分动态反射-静态反射和动态语言-动态语言的不同。动态反射多是指在运行期,静态反射多指在编译期,所以它也叫自省。而动态语言和静态语言则是指是否在运行期进行数据类型检查的不同。
反射的主要应用场景如下:
1、序列化和反序列化:这是最常用的场景。如果没有反射,那可麻烦大了。手动自己一个个匹配字节码吧。
2、远程方法RMI的调用,这个有过c#和Java开发经验的会非常容易理解。
3、数据库开发用的O/R Mapping,即对象关系映射。
4、设计模式中的一些应用,如工厂模式等。
5、其它,只要涉及到反射可以得到的类型处理等的情况。
在实现反射的手段中,一般有两种形式,即侵入式和非侵入式,这个通过名字就可以知道哪种效果会更优。
三、c++中的反射
从某种角度来说,c++是不支持反射的。当然,如果严格来说,c++是不支持动态反射的,但是通过一些技术手段可以实现静态反射的效果。这就包括前面学习到的元编程、模板编程(SFINAE)还有宏机制等。但是需要说明的,如果在业务逻辑上通过某种技巧实现类似反射的结果,一般来说,这不能归到反射上去。当然,这个就仁者见仁了。
在早期的c++中,最典型的其实就是MFC中通过模板和宏来生动态生成类并生成类的对象,这其实就是一种反射的应用。而在新的c++20提供了属性,这其实就是一个进步,它其实就可以说对反射的一种支持。c++这种静态语言会不会推出从标准上支持的反射,这个还不敢给出确切的说法(但有可能在c++26或29中支持)。
也就是说,当前的c++标准只是在RTTI(运行期类型识别)仅仅是一个类型的判断处理,简单到了发指。虽然c++20(reflexpr关键字)提供了一些面向未来测试的实现方式,但目前来看,也仅仅是一个结探索,并未真正实现,必须类似的老套的剧情发生过很多次,不断的更新迭代版本,甚至废弃都有可能。
四、总结
其实反射也可以放到模板元编程中来进行分析,但是为了更好的讲解一些c++的高级特性,还是把它分离了出来。c++的许多高级的特性,在国内的大多数应用场景上,其实是应用不到的。原因是,这些高级特性大多是在基础库支持或者基础软件上才用的。而这恰恰是国内的软肋。
知已知彼,百战不殆。看到有什么不足,才能更好的补齐它。共同努力!