自学内容网 自学内容网

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的实现依赖于两个关键操作符:typeiddynamic_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)!