UE 反射
类型检查
静态类型检查
静态类型检查 是在 编译时 对程序中的所有变量和表达式进行类型检查,以确保每个操作数、变量、函数调用等的类型都是一致和兼容的。
类型声明和定义
在静态类型语言中,每个变量、函数参数和返回值等的类型在代码编写时就已经明确指定。这些类型信息是编译器进行类型检查的基础。
符号表(Symbol Table)
编译器在编译过程中维护一个符号表,用于存储所有变量、函数及其类型信息。符号表在语法分析阶段创建,并在语义分析阶段进行扩展和检查。
类型推导
有些静态类型语言支持类型推导,编译器可以根据上下文自动推导出变量的类型(如C++中的auto
关键字)
类型检查
编译器在编译过程中对所有表达式和语句进行类型检查,以确保类型一致性。例如,变量赋值时检查类型兼容性,函数调用时检查参数类型匹配,运算符操作时检查操作数类型。
类型转换
静态类型语言通常支持显式类型转换和隐式类型转换。编译器在类型转换时进行检查,确保转换是合法的。
编译器的工作流程
编译器的工作流程通常分为以下几个阶段,每个阶段都会涉及类型检查:
词法分析(Lexical Analysis)
将源代码转换为一系列标记(tokens),这些标记代表代码中的基本元素,如关键字、标识符、操作符等。
语法分析(Syntax Analysis)
根据语法规则将标记组织成语法树(parse tree 或 AST, Abstract Syntax Tree),表示程序的结构。
语义分析(Semantic Analysis)
进行类型检查,确保每个操作符和操作数的类型一致。建立和维护符号表,跟踪变量和函数的类型信息。
中间代码生成(Intermediate Code Generation)
将语法树转换为中间表示(IR, Intermediate Representation),这种表示比源代码更接近机器代码,但仍然与具体机器无关。
优化(Optimization)
对中间代码进行各种优化,提高程序执行效率。
目标代码生成(Code Generation)
将优化后的中间代码转换为目标机器代码。
静态检查的优缺点
优点:
- 提高性能: 静态类型检查消除了运行时类型检查的开销,生成的代码更高效。
- 早期错误检测: 类型错误在编译时被捕捉,减少了运行时错误的发生。
- 代码可维护性: 明确的类型定义提高了代码的可读性和可维护性。
缺点:
- 灵活性较低: 类型必须在编译时确定,减少了代码的灵活性和动态性。
- 开发速度较慢: 需要显式地声明类型,增加了编码工作量。
RTTI
虚函数表(vtable)
当一个类包含虚函数时,编译器会为这个类生成一个虚函数表(vtable),其中包含了所有虚函数的指针。每个包含虚函数的类实例都有一个指向这个虚函数表的指针(称为vptr)。
RTTI数据
RTTI信息也会存储在虚函数表中。具体来说,编译器会在虚函数表中加入指向类型信息(如std::type_info对象)的指针。这个指针通常在虚函数表的某个固定位置。
RTTI的实现
RTTI的实现依赖于两个关键操作符:typeid
和dynamic_cast
。
typeid
操作符用于获取对象的类型信息。它返回一个std::type_info
对象,该对象包含类型的信息。type_info
对象的实际内容由编译器生成和维护。
#include <iostream>
#include <typeinfo>
class Base {
public:
virtual ~Base() = default;
};
class Derived : public Base {};
int main() {
Base* base = new Derived();
std::cout << "Type of base: " << typeid(*base).name() << std::endl;
delete base;
return 0;
}
RTTI的工作流程
编译时:
编译器为每个包含虚函数的类生成虚函数表,并在虚函数表中添加指向类型信息的指针。
编译器生成type_info对象,用于表示每个类型的信息。
运行时:
typeid操作符通过访问虚函数表中的类型信息指针,获取对象的类型信息。
dynamic_cast操作符通过检查虚函数表中的类型信息,确定是否可以进行安全的类型转换。
RTTI的限制
性能开销:
RTTI会增加一些运行时开销,因为它需要在虚函数表中存储类型信息,并在运行时进行检查。
仅适用于多态类:
RTTI依赖于虚函数表,因此只适用于包含虚函数的类(多态类)。对于非多态类,RTTI无法使用。
可移植性:
不同编译器和平台对RTTI的实现可能有所不同,因此在某些情况下,RTTI可能会有可移植性问题。
动态类型检查
运行时动态类型检查是在程序运行时进行类型检查,以确保操作数和表达式的类型是有效和兼容的。与静态类型检查不同,动态类型检查是在程序执行过程中进行的,这意味着类型信息在运行时确定。
运行时确定类型: 变量和表达式的类型在运行时确定,允许更灵活的编程方式。
高灵活性: 由于类型信息在运行时可用,可以方便地进行类型转换、动态类型检查和反射。
潜在的性能开销: 运行时类型检查增加了程序的运行时开销,可能会影响性能。
延迟错误检测: 类型错误在运行时被捕获,这可能导致运行时错误,增加调试和维护的复杂性。
反射机制:
反射是指程序在 运行时 能够检查和修改自身结构的能力,包括检查类,方法,属性等信息
UE 反射机制
- UClass。存储类信息,用于反射。把它当成C#的Type来理解。
- GetClass()。获得一个UObject实例的UClass,是UObject成员函数。
- GetStaticClass()。不需要有实例就能获得UClass。是静态的,每次调用返回相同结果。
- ClassDefaultObject。类默认对象,可以获得UObject初始化时的值。注意GetClass()->GetDefaultObject()和T::StaticClass()->GetDefaultObject()不一样。
参考:【UE·底层篇】一文搞懂StaticClass、GetClass和ClassDefaultObject_ue staticclass-CSDN博客
【UE 反射】反射的原理是什么?如何使用机制?-CSDN博客
原文地址:https://blog.csdn.net/zaizai1007/article/details/140600647
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!