我曾经是一名C ++程序员,对我来说,一个宏是使用#define
的预处理器定义。
现在我回到使用C ++的虚幻引擎进行编程,但是所有这些宏 UCLASS()
UFUNCTION()
FORCELINE
都是UNreal教程所称的宏。我之前从未见过这样的事情,并希望了解它。
我不是在询问宏在虚幻中做了什么,但是有人帮我填补了我与C ++的知识差距所以我(作为开发人员)可以理解如何设计以及何时实现 this输入 的宏。即使给我链接指南或其他东西也没关系。我尝试使用术语宏,C ++,UCLass,Unreal 进行搜索,但这些术语并未真正提出此宏的C ++定义。
#include "GameFramework/Actor.h"
#include "Pickup.generated.h"
UCLASS()
class BATTERYCOLLECTOR_API APickup : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
APickup();
// Called when the game starts or when spawned
virtual void BeginPlay() override;
答案 0 :(得分:9)
虚幻引擎C ++代码库使用名为Unreal Header Tool (UHT)的自定义预处理器从C ++代码生成自定义运行时类型信息(RTTI)。它通过在代码中查找这些特殊的类似宏的注释来实现这一目的。迂腐地说,它们不是简单的C ++宏,对它们来说还不止于此。
我不是虚幻引擎的用户,因此我不了解实施细节。我不知道UHT预处理器是否在运行后将它们剥离出来,或者它们可能只是为C ++编译器定义为什么,例如:
#if !RUNNING_UHT
#define UCLASS()
#endif
这两种方法似乎都有效。
这是正常的C ++吗?
这取决于。它肯定不是标准 C ++。宏在C ++中的使用较少,因为在大多数情况下,语言提供了更好的选项(例如:内联函数,枚举,const
,模板),因此您可能在大多数代码库中都看不到这种宏的用法。
答案 1 :(得分:8)
正如虚幻引擎文档所说:
类声明定义了类的名称,它继承的类,以及它继承的任何函数和变量,以及通过类说明符和元数据可能需要的其他引擎和编辑器特定行为。声明类的语法如下:
UCLASS([specifier, specifier, ...], [meta(key=value, key=value, ...)])
class ClassName : ParentName
{
GENERATED_UCLASS_BODY()
}
声明包含该类的标准C ++类声明。在标准声明之上,诸如类说明符和元数据之类的描述符将传递给UCLASS宏。这些用于为声明的类创建UClass,可以将其视为引擎的类的专用表示。此外,GENERATED_UCLASS_BODY()
宏必须放在类主体的最开头。
创建此宏是为了向引擎类添加一些元数据功能,如RTTI,Reflection等。此宏不是C ++ STD库提供的标准宏,而是由Epic Games编写的宏,以满足虚幻引擎的需要。 强>
有关虚幻引擎Gameplay Classes及其使用的宏的更多信息。
以下是虚幻引擎为简单游戏类所取代的一些宏代码示例:
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
/*===========================================================================
C++ class header boilerplate exported from UnrealHeaderTool.
This is automatically generated by the tools.
DO NOT modify this manually! Edit the corresponding .h files instead!
===========================================================================*/
#include "ObjectBase.h"
#ifdef MYPROJECTCODE_MyProjectCodeGameMode_generated_h
#error "MyProjectCodeGameMode.generated.h already included, missing '#pragma once' in MyProjectCodeGameMode.h"
#endif
#define MYPROJECTCODE_MyProjectCodeGameMode_generated_h
#define AMyProjectCodeGameMode_EVENTPARMS
#define AMyProjectCodeGameMode_RPC_WRAPPERS
#define AMyProjectCodeGameMode_RPC_WRAPPERS_NO_PURE_DECLS \
static inline void StaticChecks_Implementation_Validate() \
{ \
}
#define AMyProjectCodeGameMode_CALLBACK_WRAPPERS
#define AMyProjectCodeGameMode_INCLASS_NO_PURE_DECLS \
private: \
static void StaticRegisterNativesAMyProjectCodeGameMode(); \
friend MYPROJECTCODE_API class UClass* Z_Construct_UClass_AMyProjectCodeGameMode(); \
public: \
DECLARE_CLASS(AMyProjectCodeGameMode, AGameMode, COMPILED_IN_FLAGS(0 | CLASS_Transient | CLASS_Config), 0, MyProjectCode, MYPROJECTCODE_API) \
DECLARE_SERIALIZER(AMyProjectCodeGameMode) \
/** Indicates whether the class is compiled into the engine */ enum {IsIntrinsic=COMPILED_IN_INTRINSIC}; \
UObject* _getUObject() const { return const_cast<AMyProjectCodeGameMode*>(this); }
#define AMyProjectCodeGameMode_INCLASS \
private: \
static void StaticRegisterNativesAMyProjectCodeGameMode(); \
friend MYPROJECTCODE_API class UClass* Z_Construct_UClass_AMyProjectCodeGameMode(); \
public: \
DECLARE_CLASS(AMyProjectCodeGameMode, AGameMode, COMPILED_IN_FLAGS(0 | CLASS_Transient | CLASS_Config), 0, MyProjectCode, MYPROJECTCODE_API) \
DECLARE_SERIALIZER(AMyProjectCodeGameMode) \
/** Indicates whether the class is compiled into the engine */ enum {IsIntrinsic=COMPILED_IN_INTRINSIC}; \
UObject* _getUObject() const { return const_cast<AMyProjectCodeGameMode*>(this); }
#define AMyProjectCodeGameMode_STANDARD_CONSTRUCTORS \
/** Standard constructor, called after all reflected properties have been initialized */ \
MYPROJECTCODE_API AMyProjectCodeGameMode(const FObjectInitializer& ObjectInitializer); \
DEFINE_DEFAULT_OBJECT_INITIALIZER_CONSTRUCTOR_CALL(AMyProjectCodeGameMode) \
private: \
/** Private copy-constructor, should never be used */ \
MYPROJECTCODE_API AMyProjectCodeGameMode(const AMyProjectCodeGameMode& InCopy); \
public:
#define AMyProjectCodeGameMode_ENHANCED_CONSTRUCTORS \
private: \
/** Private copy-constructor, should never be used */ \
MYPROJECTCODE_API AMyProjectCodeGameMode(const AMyProjectCodeGameMode& InCopy); \
public: \
DEFINE_DEFAULT_OBJECT_INITIALIZER_CONSTRUCTOR_CALL(AMyProjectCodeGameMode)
#undef UCLASS_CURRENT_FILE_NAME
#define UCLASS_CURRENT_FILE_NAME AMyProjectCodeGameMode
#undef UCLASS
#undef UINTERFACE
#if UE_BUILD_DOCS
#define UCLASS(...)
#else
#define UCLASS(...) \
AMyProjectCodeGameMode_EVENTPARMS
#endif
#undef GENERATED_UCLASS_BODY
#undef GENERATED_BODY
#undef GENERATED_IINTERFACE_BODY
#define GENERATED_UCLASS_BODY() \
PRAGMA_DISABLE_DEPRECATION_WARNINGS \
public: \
AMyProjectCodeGameMode_RPC_WRAPPERS \
AMyProjectCodeGameMode_CALLBACK_WRAPPERS \
AMyProjectCodeGameMode_INCLASS \
AMyProjectCodeGameMode_STANDARD_CONSTRUCTORS \
public: \
PRAGMA_POP
#define GENERATED_BODY() \
PRAGMA_DISABLE_DEPRECATION_WARNINGS \
public: \
AMyProjectCodeGameMode_RPC_WRAPPERS_NO_PURE_DECLS \
AMyProjectCodeGameMode_CALLBACK_WRAPPERS \
AMyProjectCodeGameMode_INCLASS_NO_PURE_DECLS \
AMyProjectCodeGameMode_ENHANCED_CONSTRUCTORS \
private: \
PRAGMA_POP
和它的课程。
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
#pragma once
#include "GameFramework/GameMode.h"
#include "MyProjectCodeGameMode.generated.h"
UCLASS(minimalapi)
class AMyProjectCodeGameMode : public AGameMode
{
GENERATED_BODY()
public:
AMyProjectCodeGameMode(const FObjectInitializer& ObjectInitializer);
};
正如您所看到的,此宏为类添加了额外的字段变量和方法,以便为虚幻引擎元数据信息提供接口。所以引擎可以使用这个信息来建立关卡,产生玩家e.t.c ......
引擎定义的宏不能被重写,如果您想设计自己的引擎框架来添加一些新功能(使用新的宏保护),或修改当前的虚幻引擎以满足您的特定需求(这是一个真正的努力工作) )。