UE_C++ —— 数据类型

UE_C++ —— 数据类型

目录

一,基本数据类型

二,字符串类型

三,容器类型

四,向量及变换类型

五,枚举类型

六,对象指针


一,基本数据类型

UE对C++基本数据类型进行了深度重定义,并禁止使用原生的C++基本数据类型,以保证引擎的跨平台特性;

布尔类型(bool,代表布尔值,即true或false;

字符类型(TCHAR,代表字符型,用于支持宽字符(如Unicode字符集),以保证跨平台兼容性;

短整形(short,2个字节;

无符号和有符号整数类型

  • int,标准整形,根据系统架构(32位或64位)的不同,其大小可能有所不同(32位4字节、64位8字节);
  • uint8(1字节)、uint16(2字节)、uint32(4字节)、uint64(8字节)
  • int8(1字节)、int16(2字节)、int32(4字节)、int64(8字节)

长整形(long),4个字节;

长长整形(long long),8个字节;

浮点类型

  • float(单精度浮点型,4字节),在值后加f以提升效率和精度,如3.14f;
  • double(双精度浮点型,8字节);
// 基础类型 bool bool_val = 1; uint8 byte_val = 255; int32 int32_val = -32; int64 int64_val = -64; double double_val = 3.14; // UE_LOG 的第 3 个参数(Format)必须是格式化字符串字面量,便于编译时检查及节省运行时开销; UE_LOG(LogTemp, Error, TEXT("%d"), bool_val); UE_LOG(LogTemp, Warning, TEXT("%d"), byte_val); UE_LOG(LogTemp, Warning, TEXT("%d"), int32_val); UE_LOG(LogTemp, Display, TEXT("%d"), int64_val); UE_LOG(LogTemp, Display, TEXT("%f"), double_val);

二,字符串类型

FString,动态字符数组;

  • 用于存储可变的字符串,必须用TEXT宏包裹字符串;
  • 开销大于其他类字符串类型,是处理字符串的主要类型;
  • 适用于存储临时数据,如文件路径、日志信息、调试文本、配置文件内容等;

FName,资源命名字符串;

  • 存储不可变的字符串,必须用TEXT宏包裹字符串;
  • 相对轻量级的字符串类型,散列存储,速度快;
  • 大小通常为8byte,只进行一次字符串哈希映射,在比较字符串时不区分大小写且只读;
  • 主要用于表示引擎中的名称,如对象名、资源名、类名等,以提高性能;

FText,支持本地化的文本字符串;

  • 不可变,不提供修改函数,无法进行内容修改;
  • 处理用户的显式文本,提供了对字符串进行格式化、本地化等操作的功能;
  • 提供了对文本的多语言支持,可以根据不同的语言和文化设置提供不同的显示内容;
  • 大小为40bytes,核心实质是一个TSharedRef<ITextData>,即实际文本数据的智能引用;拷贝成本非常低,只需拷贝指针而不是整个字符串数据;
  • 主要用于用户界面(UI)上显示的文本,如对话框、按钮文字、任务提示等需要翻译的文本;
//FString类 //构造与赋值 FString str1; // 创建一个空的FString对象 FString str2(TEXT("Hello")); // 使用TEXT宏创建一个包含"Hello"的FString对象 FString str3 = str2; // 通过拷贝构造函数赋值 FString str4 = TEXT("World"); // 直接使用TEXT宏进行赋值 //追加 FString str = TEXT("Hello, "); str.Append(TEXT("World!")); // 使用Append函数追加字符串,结果str为"Hello, World!" str += TEXT(" Again!"); // 使用+=运算符追加字符串,结果str为"Hello, World! Again!" //插入 FString str = TEXT("Hello"); str.InsertAt(5, TEXT(" World")); // 在索引5的位置插入字符串" World",结果str为"Hello World" //替换 FString str = TEXT("Hello World"); str = str.Replace(TEXT("World"), TEXT("UE")); // 将"World"替换为"UE",结果str为"Hello UE" //查询 FString str = TEXT("Hello World"); bool containsHello = str.Contains(TEXT("Hello")); // 判断是否包含子字符串"Hello",结果为true int32 index = str.Find(TEXT("World")); // 查找子字符串"World"的索引,结果为6 bool startsWithHello = str.StartsWith(TEXT("Hello")); // 判断是否以"Hello"开头,结果为true bool endsWithWorld = str.EndsWith(TEXT("World")); // 判断是否以"World"结尾,结果为true //格式化 FString playerName = TEXT("John"); FString greeting = FString::Printf(TEXT("Hello, %s!"), *playerName); // 使用Printf函数格式化字符串,结果greeting为"Hello, John!" //路径拼接 FString basePath = TEXT("C:/Users/Documents/"); FString fileName = TEXT("example.txt"); FString fullPath = basePath / fileName; // 使用/运算符进行路径拼接,结果fullPath为"C:/Users/Documents/example.txt" FString fullPath; fullPath.PathAppend(fileName, TEXT("example.txt").Length()); // 将文件名追加到基路径上,注意需要传递文件名的长度
//FName //创建 FName myFName(TEXT("MyObjectName")); //比较 if (myFName == FName(TEXT("MyObjectName")));
//FText FText myText = TEXT("Hello, World!"); FText formattedText = FText::Format(TEXT("Hello, {0}!"), TEXT("World"));
// 字符串类型 FString str = TEXT("FString!"); //内部是TArray<TCHAR>的封装,并重载了operator*() FName name = TEXT("FName!"); FText text = FText::FromString(TEXT("FText!")); UE_LOG(LogTemp, Display, TEXT("%s"), *str); UE_LOG(LogTemp, Display, TEXT("%s"), *name.ToString()); UE_LOG(LogTemp, Display, TEXT("%s"), *text.ToString());

三,容器类型

TArray<T>,UE定义的增强数组容器;

  • 是一个同质容器,即其所有元素均完全为相同类型;
  • 与std::vector类似,可动态扩充内存;当容量满了,会额外分配一个更大的内存,并将数据拷到新内存上,之后再释放旧的内存;
  • 提供了比标准C++数组更丰富的功能,如动态扩展、排序、查找等;
  • 具有速度快、内存消耗小、安全性高等特点;

TSet<T>,存储值本身的松散的集合;

  • 默认不允许元素重复,存储唯一元素;
  • 基于哈希表实现,提供了快速的查找、插入和删除操作;
  • UE使用两个数组HashArray和ElementArray来实现TSet(HashArray中存放着ElementArray的Index,而ElementArray中存放着具体的值),使用拉链法解决冲突;

TMap<k, T>,key-value类型容器;

  • 允许通过键来快速查找对应的值,适用于需要快速访问数据的场景;
  • 基于哈希表实现,提供了高效的查找性能;
  • 键必须是唯一的,而值可以是任何类型;
//TArray #include "Containers/Array.h" TArray<int32> IntArray; //初始化一个空的TArray //添加元素 IntArray.Add(10); IntArray.Add(20); IntArray.Add(30); IntArray.AddUnique(30); //使用索引访问元素 UE_LOG(LogTemp, Warning, TEXT("Element at index 1: %d"), IntArray[1]); //输出: Element at index 1: 20 //使用范围for循环迭代元素 for (int32 i : IntArray) { UE_LOG(LogTemp, Warning, TEXT("Element: %d"), i); } IntArray.RemoveAt(1); //移除索引为1的元素,即20 IntArray.Empty(); //清空数组
//TSet #include "Containers/Set.h" TSet<int32> IntSet; //声明一个存储int32的TSet TSet<FString> StringSet = { TEXT("Hello"), TEXT("World") }; //使用初始化列表 IntSet.Add(10); IntSet.Add(20); IntSet.Add(10); //这个不会被添加,因为10已经存在 IntSet.Contains(20); //检查TSet中是否包含某个元素 IntSet.Remove(10); IntSet.Empty();
//TMap #include "Containers/Map.h" TMap<FString, int32> StringToIntMap; // 声明一个存储FString到int32映射的TMap // 初始化通常是通过Add方法 StringToIntMap.Add(TEXT("One"), 1); StringToIntMap.Add(TEXT("Two"), 2); StringToIntMap.Add(TEXT("Three"), 3); StringToIntMap.Add(TEXT("One"), 10); // 这会覆盖键为"One"的值,新的值为10 //查找元素 if (StringToIntMap.Contains(TEXT("Two"))) { int32 value = StringToIntMap[TEXT("Two")]; // 更常见的查找方式,但如果键不存在会触发断言(在开发构建中) // 或者使用Find来避免断言 int32* valuePtr = StringToIntMap.Find(TEXT("Two")); if (valuePtr) { int32 value = *valuePtr; } } StringToIntMap.Remove(TEXT("One")); StringToIntMap.Empty();
// 容器类型 TArray<int32> arr = { 1,2,3,4,5 }; TSet<int32> set = { 10,20,30,40,50 }; TMap<int32, FString> map = { {1, TEXT("one")}, {2, TEXT("two")} }; FString arr_ret; for (auto num : arr) arr_ret += FString::FromInt(num) + TEXT(" "); GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Blue, arr_ret); FString set_ret; for (auto num : set) set_ret += FString::FromInt(num) + TEXT(" "); GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Blue, set_ret); FString map_ret; for (auto num : map) map_ret += num.Value + TEXT(" "); GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Blue, map_ret);

四,向量及变换类型

FVector,表示3D空间点、向量等的三维向量类型,包含三个浮点数分量:X、Y和Z;

  • 常用于表示对象的位置、方向、速度等;
  • 支持向量的基本运算,如加法、减法、点积、叉积等;
  • 可以方便地转换为其他数学类型,如四元数(FQuat)和矩阵(FMatrix);

FRotator,表示3D旋转的三维向量类型,包含三个浮点数Pitch、Yaw、Roll(以角度为单位存储);

  • Pitch表示绕右轴(Y轴)旋转的角度,上下(0=正前方,+向上,-向下)的旋转;
  • Yaw表示绕上轴(Z轴)旋转的角度,绕圈(0=东,+北,-南)
  • Roll表示绕前向轴(X轴)旋转的角度,歪着头(0=正直,+顺时针旋转,-逆时针旋转);
  • 可以转换为四元数(FQuat)以进行更高效的旋转计算;

FTransform,更高级别的矩阵类型,包含三个矩阵:Rotation(旋转)、Translation(平移)和Scale3D(缩放);

  • 广泛用于表示对象在3D空间中的位置和变换;
  • 支持矩阵的基本运算,如乘法、逆运算等;
  • 可以方便地转换为其他数学类型,如四元数(FQuat)和向量(FVector);
FVector Location(10.0f, 20.0f, 30.0f); FRotator Rotation(0.0f, 45.0f, 0.0f); FTransform Transform(FVector(10.0f, 20.0f, 30.0f), FRotator(0.0f, 45.0f, 0.0f), FVector(1.0f, 1.0f, 1.0f));

五,枚举类型

enum,使用enum关键字定义枚举类型;

enum class EMyEnum { Value1, Value2, Value3 }; EMyEnum MyEnumValue = EMyEnum::Value1;

六,对象指针

  • *UPROPERTY标记后支持,尽可能使用TObjectPtr;
  • † 只有TObjectPtr被UPROPERTY标记后才支持;
  • ‡ 已弃用,改用TSoftObjectPtr;
  • §
  • ❡ 该类型无法标记UPROPERTY,会运行所有位置的GC;

TObjectPtr<T>

  • 可直接替代原生指针,只能用于从UObject派生的类型;
  • 序列化方式与指向UObject的原始指针相同;
  • 当被标记为UPROPERTY时,是对对象的强引用,会阻止垃圾回收销毁目标对象;
class UMyObject : UObject { UPROPERTY() TObjectPtr<UMyOtherObject> MyOtherObject; UPROPERTY() TObjectPtr<UStaticMeshComponent> Mesh; }

TSoftObjectPtr<T>

  • 指向对象的弱引用,跟踪磁盘上目标对象的路径,不影响GC;
  • 当引用的对象加载到内存和从内存卸载时,可能会在有效和挂起状态间来回变化;
  • 对按需异步加载的资源或防止硬依赖非常有用;如目标对象尚未有效,则必须以同步或异步方式显式加载它;
public AMyActor : AActor { // ... UPROPERTY(EditAnywhere) TSoftObjectPtr<UNiagaraSystem> NiagaraVFX; // Use NiagaraVFX.Get() inside OnLoadComplete void OnLoadComplete(); } // When asset needs to be used... // ...load synchronously UNiagaraSystem* VFX = NiagaraVFX.LoadSynchronous(); // ...or, stream asynchronously FStreamableManager& StreamableManager = UAssetManager::Get().GetStreamableManager(); FStreamableDelegate OnLoadCompleteDelegate = FStreamableDelegate::CreateUObject(this, *AMyActor::OnLoadComplete); StreamableManager.RequestAsyncLoad(NiagaraVFX.ToSoftObjectPath(), OnLoadCompleteDelegate);

TWeakObjectPtr<T>

  • 指向对象的弱指针,无需被标记为UPROPERTY;
  • 支持序列化,并且也支持网络传输;
  • 通常,当明确不希望阻止对象被垃圾回收时使用;目标对象被回收或销毁,会自动置空;
  • 使用前应通过TWeakObjectPtr::IsValid检查是否有效,或使用TWeakObject::Get;
  • 不支持作为 TMap 中的键,也不支持作为 TSet 中的元素; UObject 作为键,使用 TObjectKey;
// Object Cache TMap<TSubclassOf<UObject>, TWeakObjectPtr<UObject>> CachedObjects; // Get cached object by class, if still valid UObject* GetCachedObject(TSubclassOf<UObject> CachedObjectClass) { if (TWeakObjectPtr<UObject> FoundObject = *CachedObjects.Find(CachedObjectClass)) { // If running on the game thread, this pattern is permissable: if (FoundObject.IsValid()) { return FoundObject.Get(); } /* If running on any thread other than game thread, use this pattern: if (TStrongObjectPtr<UObject> FoundObjectPinned = FoundObject.Pin()) { return FoundObjectPinned.Get(); } */ } return nullptr; }
FSimpleDelegate MyDelegate; TObjectPtr<UMyObject> MyObject; MyDelegate.BindLambda( [MyWeakObject = MakeWeakObjectPtr(MyObject)]() { if (TStrongObjectPtr<UMyObject> MyStrongObject = MyWeakObject.Pin()) { // object safe to access } else { // object already garbage collected } } );

TStrongObjectPtr<T>

  • 指向对象的强指针,会统计目标对象引用次数,并在目标对象处于作用域内时阻止垃圾回收;
  • 不支持UPROPERTY,不适合用于派生自UObject的类中的字段;对调试工具的可见性也较低;
  • 创建和销毁该类型开销较大,应尽可能避免;对于不常更改的长期引用,应使用;
  • 每个TStrongObjectPtr都会为垃圾回收增加一个被跟踪的引用;
  • 用于在非 UObject 拥有类(如未从 UObject 派生的类或结构体)中存储对 UObject 的强引用,因为在 UObject 之外无法使用 UPROPERTY;
    • 对在UObject类内部,使用标记为UPROPERTY的TObjectPtr;
    • 对于资源引用,使用TWeakObjectPtr;
class FMyClass { // ... // Strong reference to a UObject inside a non-UObject class TStrongObjectPtr<UMyObject> MyObject; }