虚幻c++中的细节之枚举类型(enum)
文章目录
- 前言
- 一、原生c++的枚举类型
- 关键字class
- int8 - 枚举的基础类型(`underlying type`)
- 二、枚举类型的灵活运用
- 位运算
- 枚举循环遍历
- 三、虚幻风格的枚举类型
- UENUM
- UMETA
- TEnumAsByte
- 总结
前言
虚幻引擎中的代码部分实现了一套反射机制,为c++代码带了更多方便的特性。本篇文章将会着眼于其中更加细节的部分——虚幻中的enum。
在虚幻风格的代码中,我们经常能使用这样的方法来创建枚举类型:
UENUM(BlueprintType)
enum class EMyEnum : uint8
{Option1 UMETA(DisplayName = "Option 1"),Option2 UMETA(DisplayName = "Option 2"),Option3 UMETA(DisplayName = "Option 3")
};
似乎有一些c++的影子,但又好像有一些不一样的部分。它有基本c++的框架,但又有一些额外的东西。如果你对c++很熟悉,那再好不过。只需要始终把握一点,一切还是源于c++,额外的内容的目的是将该类型加入到反射系统中,使其支持序列化,使其能够支持蓝图编辑。
一、原生c++的枚举类型
我们来先将上面的例子简化一下
enum EMyEnum
{Option1,Option2,Option3
};
这是我们最熟悉的枚举创建方法,EMyEnum是枚举的名字。
下面是它一般的使用方式
// Example use of the enum
void MyFunction()
{EMyEnum MyOption = Option1;if (MyOption == Option2){// Do something}
}
接下来,我们一点一点为它扩展。
关键字class
首先添加关键字class。
enum class EMyEnum
{Option1,Option2,Option3
};
在这个例子中,我们的枚举类型EMyEnum有三个具体的选项:Option1,Option2和Option3。其中class关键字的作用是说明这是一个有作用范围(作用域)的枚举(scoped enum),意思是枚举的值需要在枚举类型的作用范围内使用,具体如下:
// Example use of the enum
void MyFunction()
{EMyEnum MyOption = EMyEnum::Option1;if (MyOption == EMyEnum::Option2){// Do something}
}
int8 - 枚举的基础类型(underlying type)
可以利用int8确定枚举值的基本类型
enum class EMyEnum : int8
{Option1,Option2,Option3
};
这意味着每个枚举值都会以一个8位的整型值来表示。其他可用基本类型还有uint8,uint16,uint32,int16,int32等等。
那这有什么用呢?比如说希望判断枚举值是否在某个范围内,或者是多个枚举值之间进行比较的时候。
下面看一个具体的例子
enum class EDamageType : uint8
{Blunt,Piercing,Fire,Ice,Electric,Poison
};
我们创建了一个表示伤害类型的枚举,当然从游戏的层面来讲,枚举值可能远远不止这些。
这里,我们可以利用>和<符号来判断枚举值是否在一个范围内,比如
EDamageType DamageType = EDamageType::Fire;if (DamageType < EDamageType::Electric)
{// Do something for non-electric damage types
}
else
{// Do something for electric damage type
}
例子中,只要待判断的伤害类型属于Blunt,Piercing,Fire或Ice中的任何一个,判断条件都将成立,因为他们都小于Electric。
更直观的,我们将每个枚举值的默认uin8都写出来
enum class EDamageType : uint8
{Blunt = 0,Piercing = 1,Fire = 2,Ice = 3,Electric = 4,Poison = 5
};
在进行比较或者范围判定的时候,实际上是这些枚举值背后的数字在进行判断。
当然,也可以不使用默认值而用任意指定的值,比如
enum class EDamageType : uint8
{Blunt = 100,Piercing = 200,Fire = 300,Ice = 400,Electric = 500,Poison = 600
};
可以使用static_cast或reinterpret_cast来进行枚举类型和其基础类型之间的显示转换
EDamageType DamageType = EDamageType::Fire;
uint8 DamageTypeValue = static_cast<uint8>(DamageType);
那么如果不指定基本类型会怎么样?像一开始那样直接将这个省略会有什么结果?
答案是编译器会根据枚举值自动为它挑选合适的基本类型,所以似乎省略也没有什么不妥,甚至为书写方便了不少。但是还是推荐在书写的时候指明基本类型,否则可能会有一些类型匹配方面的问题,亦或是出现一些无法预测的行为。
二、枚举类型的灵活运用
除了上面介绍的特性和基本应用,枚举还有一些其他好玩的用法。
位运算
利用位运算,可以快捷得将枚举值分配为以2为系数的等比数列,从而可以将枚举值表示为二进制码的组合,比如:
enum class EMyFlags : uint8
{None = 0,Flag1 = 1 << 0,Flag2 = 1 << 1,Flag3 = 1 << 2,Flag4 = 1 << 3,Flag4 = 1 << 5,All = Flag1 | Flag2 | Flag3 | Flag4,
};
在这个例子中,每个标志都进行左移运算,即每一个值都是前一个值的2倍。可以利用位运算符号(|,&,^)对这些枚举值进行组合。All就是所有标志组合的结果,将它与其中某个枚举值进行&运算,即可判断它是否包含该枚举值
EMyFlags MyFlag = EMyFlags::Flag1;
if (EMyFlags::All & MyFlag)
{// Do something
}
这里的结果自然是通过的。
枚举循环遍历
在c++ 11的新特性中,可以对枚举类型的值使用循环遍历,如
for (EMyEnum Value : TEnumRange<EMyEnum>())
{// Do something with Value
}
在这个例子中,TEnumRange模板提供了一种遍历所有EMyEnum的枚举值的方式。
三、虚幻风格的枚举类型
虚幻在基础c++枚举的基础上,也加入了自己风格的代码,这自然也为它添加了更多的功能和特性。
这里以一个游戏中典型的枚举为例
UENUM(BlueprintType)
enum class EWeaponType : uint8
{Pistol UMETA(DisplayName = "Pistol"),Shotgun UMETA(DisplayName = "Shotgun"),RocketLauncher UMETA(DisplayName = "Rocket Launcher")
};
EWeaponType是该枚举类型的名称,Pistol,Shotgun,RocketLauncher是具体的枚举值。
UENUM
UENUM将枚举类型进行标记,方便UHT为其生成相应的类型文件,生成反射系统需要的代码。BlueprintType说明符令该枚举可以在蓝图中自如使用。
UMETA
使用UMETA宏来指定每个枚举值指定一个显示名,即在蓝图使用中和UI中显示的名称。
TEnumAsByte
虚幻引擎还提供了一种特殊类型的枚举,称为TEnumAsByte,用于加强类型安全并且解决一些常见的错误,主要是一些将枚举类型强行用作其基础类型的应用场合,例如意外使用枚举作为数组的索引。
TEnumAsByte<EWeaponType> Weapon = EWeaponType::Shotgun;
这里就声明了一个TEnumAsByte<EWeaponType>类型的枚举变量Weapon,它本身其实是一个结构体,其中只有一个简单的uint8类型的字段。这是一种典型的面向对象的做法,用一个类型对象将数据封装,这样,当你用一个枚举值去为另一个枚举值赋值的时候就会报错了,这种做法进一步保证了类型安全。
在将枚举类型变量公布给蓝图使用时,通常需要将它与基本枚举类型结合起来进行类型的声明。
总结
枚举类型是一种强大的编程工具,可以使你的代码更加清晰、简洁、易于维护。在使用时,要注意选择适当的技巧,以确保你的代码能够正常工作并避免潜在的错误。
希望文中的例子可以帮助更多人更好地了解如何在编写代码时使用枚举类型。
相关文章:
虚幻c++中的细节之枚举类型(enum)
文章目录前言一、原生c的枚举类型关键字classint8 - 枚举的基础类型(underlying type)二、枚举类型的灵活运用位运算枚举循环遍历三、虚幻风格的枚举类型UENUMUMETATEnumAsByte总结前言 虚幻引擎中的代码部分实现了一套反射机制,为c代码带了…...
判断某个字符串在另一个字符串中的个数
/** * 用于判断字符串中字符的个数 * * param str1 原字符串 * param str2 需要判断的字符 * return 返回有几个 */ private int getCount(String str1, String str2) { //获取两个字符串的长度 int oneLength str1.length(); int toLength str2.length(); //定义两个整数&am…...
测试人员如何运用好OKR
在软件测试工作中是不是还不知道OKR是什么?又或者每次都很害怕写OKR?或者总觉得很迷茫,不知道目标是什么? OKR 与 KPI 的区别 去年公司从KPI换OKR之后,我也有一段抓瞎的过程,然后自己找了两本书看,一本是《OKR工作法》…...
CentOS7 Hive2.3.9 安装部署(mysql 8.0)
一、CentOS7安装MySQL数据库 查询载mariadb rpm -qa | grep mariadb卸载mariadb rpm -e --nodeps [查询出来的内容]安装wget为下载mysql准备 yum -y install wget在tools目录下执行以下命令,下载MySQL的repo源: wget -P /tools/ https://dev.mysql.…...
【PTA Advanced】1142 Maximal Clique(C++)
目录 题目 Input Specification: Output Specification: Sample Input: Sample Output: 思路 代码 题目 A clique is a subset of vertices of an undirected graph such that every two distinct vertices in the clique are adjacent. A maximal clique is a clique …...
1. MySQL在金融互联网行业的企业级安装部署
这里写目录标题 1. 版本介绍示例2.安装MySQL规范(建议二进制)2.1 安装方式2.2 安装用户2.3 目录规范3.二进制安装3.1 操作系统配置3.2 MySQL 5.7.33 安装部署2.3 MySQL8.0.27安装2.4 源码安装(了解 )3.多实例部署及注意事项3.1 多实例概念3.2 多实例安装3.3 多实例第二种方式…...
【C++修炼之路】19.AVL树
每一个不曾起舞的日子都是对生命的辜负 AVL树前言:一.AVL树的概念二.AVL树的结构2.1 AVL树节点的定义2.2 AVL树的结构2.3 AVL树的插入2.4 AVL树的验证2.5 AVL树的删除(了解)三.AVL树的旋转(重要)3.1 左单旋3.2 右单旋3.3 左右双旋3.4 右左双旋…...
项目管理工具dhtmlxGantt甘特图入门教程(十):服务器端数据集成(下)
这篇文章给大家讲解如何利用dhtmlxGantt在服务器端集成数据。 dhtmlxGantt是用于跨浏览器和跨平台应用程序的功能齐全的Gantt图表,可满足应用程序的所有需求,是完善的甘特图图表库 DhtmlxGantt正版试用下载(qun 764149912)http…...
LeetCode 793. 阶乘函数后 K 个零
f(x) 是 x! 末尾是 0 的数量。回想一下 x! 1 * 2 * 3 * ... * x,且 0! 1 。 例如, f(3) 0 ,因为 3! 6 的末尾没有 0 ;而 f(11) 2 ,因为 11! 39916800 末端有 2 个 0 。 给定 k,找出返回能满足 f(x) …...
maven打包顺序与jvm类加载顺序
背景:一次dev测试过程中,发现代码中关于jsr303的校验失效,校验类如下,会报一个莫名其妙的运行时错误;遂进行排查。import javax.validation.constraints.NotBlank;Data Accessors(chain true) public class Demo {Not…...
④ 链表
24. 两两交换链表中的节点 题目链接:https://leetcode.cn/problems/swap-nodes-in-pairs/ 注意点: 遍历链表的时候什么时候截止(避免空指针异常或无限死循环的问题)? 节点数量为偶数或链表为空时,cur.ne…...
小孩扁桃体肿大3度能自愈吗?6岁小孩扁桃体肥大怎么治效果好?
12月7日,四川眉山市民唐先生说,他刚出生的儿子在妇产医院分娩中心住了20天后感染了败血症。据唐先生介绍,哈子出院时各项指标正常。他在分娩中心住了半个月左右,孩子喝牛奶很生气,第二天就开始发烧了。同一天ÿ…...
【C++提高编程】C++全栈体系(二十二)
C提高编程 第三章 STL - 常用容器 五、stack容器 1. stack 基本概念 概念:stack是一种先进后出(First In Last Out,FILO)的数据结构,它只有一个出口 栈中只有顶端的元素才可以被外界使用,因此栈不允许有遍历行为 栈中进入数据称为 — 入…...
linux系统编程2--网络编程socket知识
在linux系统编程中网络编程是使用socket(套接字),socket这个词可以表示很多概念:在TCP/IP协议中,“IP地址TCP或UDP端口号”唯一标识网络通讯中的一个进程,“IP地址端口号”就称为socket。在TCP协议中&#…...
Python-__repr__、__hash__和__eq__方法,split()、join()、yield()和append()函数
1.__repr__方法程序1class Python:passa Python() print(a) print(a.__repr__())结果<__main__.Python object at 0x0000023B82185FD0> <__main__.Python object at 0x0000023B82185FD0>默认情况下,我们得到的信息只会是“类名object at内存地址”程序…...
【安卓开发】安卓广播机制
读书笔记系列(第一行代码) 5.1 广播机制简介 标准广播:完全异步执行,广播发出后,所有广播接收器几乎都同一时刻收到这条广播(无法被截断)有序广播:同步执行,广播发出后…...
移动WEB开发四、rem布局
零、文章目录 文章地址 个人博客-CSDN地址:https://blog.csdn.net/liyou123456789个人博客-GiteePages:https://bluecusliyou.gitee.io/techlearn 代码仓库地址 Gitee:https://gitee.com/bluecusliyou/TechLearnGithub:https:…...
request.getURL()和request.getURI() 以及通过request获得路径相关大全
request.getURL()和request.getURI() 如果我的请求是:http://localhost:8080/ServletTest/servlet/Hello request.getRequestURI() 返回值类似:/ServletTest/servlet/Hello request.getRequestURL() 返回值类似:http://localhost:8080/Servle…...
java网络编程-nio学习:阻塞和非阻塞
一、阻塞 阻塞模式下,相关方法都会导致线程暂停 ServerSocketChannel.accept 会在没有连接建立时让线程暂停 SocketChannel.read 会在没有数据可读时让线程暂停 阻塞的表现其实就是线程暂停了,暂停期间不会占用 cpu,但线程相当于闲置 单线…...
JVM-JMM内存模型(happens-before、volatile)
前言 由于计算机的存储设备与处理器的运算速度有几个数量级的差距所以现代计算机系统都不得不加入一层读写速度尽可能接近处理器运算速度的高速缓存(Cache)来作为内存与处理器之间的缓冲。 将运算需要使用到的数据复制到缓存中,让运算能快速进行,当运算…...
效率提升:用快马ai一键生成直播数据监控与管理面板代码
最近在开发直播后台管理工具时,发现很多功能模块其实都有固定套路。比如数据看板、弹幕管理这些常见需求,每次都要从零开始写类似的代码结构,特别浪费时间。后来尝试用InsCode(快马)平台的AI生成功能,效率直接翻倍。 1. 为什么需…...
D3KeyHelper完整指南:暗黑破坏神3终极自动化解决方案
D3KeyHelper完整指南:暗黑破坏神3终极自动化解决方案 【免费下载链接】D3keyHelper D3KeyHelper是一个有图形界面,可自定义配置的暗黑3鼠标宏工具。 项目地址: https://gitcode.com/gh_mirrors/d3/D3keyHelper 在暗黑破坏神3的激烈战斗中…...
StreamCap:构建直播内容捕获的神经网络式生态系统
StreamCap:构建直播内容捕获的神经网络式生态系统 【免费下载链接】StreamCap Multi-Platform Live Stream Automatic Recording Tool | 多平台直播流自动录制客户端 基于FFmpeg 支持监控/定时/转码 项目地址: https://gitcode.com/gh_mirrors/st/StreamCap …...
浙江清洁拖把这样选
随着现代生活节奏的加快和健康家居理念的普及,家庭清洁工具正经历着一场深刻的智能化、便捷化变革。在众多品类中,清洁拖把作为地面清洁的核心工具,其技术演进与产品创新直接关系到清洁效率和用户体验。本文将聚焦行业痛点、技术方案与应用效…...
Qwen-Turbo-BF16与MATLAB协同计算:科学研究的AI加速器
Qwen-Turbo-BF16与MATLAB协同计算:科学研究的AI加速器 打通AI大模型与科学计算平台的数据通道,让科研效率提升10倍 1. 引言:当AI大模型遇上科学计算 在流体力学实验室里,张博士正在处理一组复杂的湍流模拟数据。传统方法需要3天时…...
从USB2.0协议到Zynq7000实现:手把手拆解一次完整的批量传输(Bulk Transfer)
从USB2.0协议到Zynq7000实现:深入解析批量传输的硬件协同机制 USB批量传输(Bulk Transfer)作为最基础的数据传输模式之一,在嵌入式系统中扮演着关键角色。本文将带您深入理解USB2.0协议中批量传输的完整流程,并揭示Zyn…...
解锁Noria查询重用机制:如何智能复用数据流组件实现应用性能飞跃
解锁Noria查询重用机制:如何智能复用数据流组件实现应用性能飞跃 【免费下载链接】noria Fast web applications through dynamic, partially-stateful dataflow 项目地址: https://gitcode.com/gh_mirrors/no/noria 在现代Web应用开发中,性能优化…...
从安装到出图:Anything V5 Stable Diffusion 完整入门流程详解
从安装到出图:Anything V5 Stable Diffusion 完整入门流程详解 1. 环境准备与快速部署 1.1 系统要求 在开始使用Anything V5之前,请确保您的系统满足以下最低配置要求: 操作系统:Linux (推荐Ubuntu 20.04)GPU:NVID…...
电子系统设计中7种经典电路接口详解与应用
1. 电路接口概述:信号传输的关键桥梁在电子系统设计中,不同模块间的数据交换就像城市间的交通网络,需要标准化的"道路规则"来确保信息高效流通。实际工程中常遇到三大类信号传输问题:时序不同步(如CPU与外设…...
with open方法详解
Python with open 方法详解 with open 是 Python 中操作文件最推荐、最安全的写法,核心作用是自动管理文件资源,不用手动关闭文件,也能避免文件泄露、数据丢失等问题。 一、基础语法 python 运行 # 标准格式 with open(文件路径, 模式, 编码) as 变量名:# 缩进内写文件操…...
