【UE4从零开始 012】代码编写标准

1、命名规则

  • 命名(如类型或变量)中的每个单词需 大写首字母 且单词之间无下划线。如:Health和UPrimitiveComponent,而不是lastMouseCoordinates或delta_coordinates。
  • 类型名前缀需使用额外的大写字母,以将其和变量名进行区分。例如:FSkin为类型名,而Skin则是FSkin的实例。
  • 类型和变量的命名为名词。
  • 函数名为动词,以描述函数的效果。
  1. 模板类的前缀为 T,如TArray;
  2. 继承自 UObject 的类前缀为 U
  3. 继承自 AActor 的类前缀为 A
  4. 继承自 SWidget 的类前缀为 S
  5. 抽象接口类的前缀为 I
  6. 枚举的前缀为 E
  7. bool类型的变量必须以 b 为前缀,如“PendingDestruction”,获得“bHasFadedIn”;
  8. 其他多数类均以 F 为前缀,而部分子系统则以其他字母为前缀;
  9. Typedefs 应以与其类型相符的字母为前缀,如结构体的 Typedefs 使用 F ,UObject 的 Typedefs 使用 U 等,
    多数情况下,UnrealHeaderTool 需要正确的前缀,因此添加前缀至关重要。
  • 变量、函数和类的命名应清楚明了且通读易懂,避免过度缩写;
  • 所有变量应逐个声明,以便对变量进行注释;
  • 所有返回bool的函数应发起 true/false 的询问,如IsVisible()或ShouldClearBuffer();

2、注释

  • 编写可读性强的自描述代码:
// 差:
t = s + l - b;

// 优:
TotalLeaves = SmallLeaves + LargeLeaves - SmallAndLargeLeaves;
  • 编写有用的注释:
// 差:
// increment Leaves
++Leaves;

// 优:
// we know there is another tea leaf
++Leaves;
  • 不编写悖论代码:
// 差:
// never increment Leaves!
++Leaves;

// 优:
// we know there is another tea leaf
++Leaves;

3、常量正确性

常量 即是文档也是编译器指令,因此应保证所有代码正确。

  • 若函数不修改参数,则用 const 修饰参数;
  • 若函数不修改对象,则用 const 修饰函数;
  • 若循环不修改容器,则用 const 修饰迭代器。
    void SomeMutatingOperation(FThing& OutResult, const TArray& InArray); // SomeMutatingOperation不会修改InArray,但可能会修改OutResult

    void FThing::SomeNonMutatingOperation() const
    {
        // 若此代码在FThing上被调用,其不会修改FThing
    }

    TArray StringArray;
    for (const FString& : StringArray)
    {
        // 此循环的主体不会修改StringArray
    }

注意:不要随意在返回类型上使用常量,此操作将会禁止复杂类型的移动语意,并会对内置类型发出编译警告。此规则仅适用于返回类型自身,而非指针目标类型或返回的引用:

  // 差 - 返回常量数组
    const TArray GetSomeArray();

    // 优 - 将引用返回至常量数组
    const TArray& GetSomeArray();

    // 优 - 将指针返回至常量数组
    const TArray* GetSomeArray();

    // 差 - 将常量指针返回至常量数组
    const TArray* const GetSomeArray();

4、强类型枚举

使用 enum class 不要使用 namespace enum

// Old enum
UENUM()
namespace EThing
{
    enum Type
    {
        Thing1,
        Thing2
    };
}

// New enum
UENUM()
enum class EThing : uint8
{
    Thing1,
    Thing2
}

可以直接使用 UPROPERTY ,不需要 TEnumAsByte

// Old property
UPROPERTY()
TEnumAsByte MyProperty;

// New property
UPROPERTY()
EThing MyProperty;

Enum property 可以是任意大小,不只局限于 byte。但暴露给蓝图的枚举必须基于uint8.

5、代码格式

大括号{ }

大括号格式必须一致。在Epic的传统做法中,大括号被放在新行。请保持这种格式。
固定在单语句块中使用大括号,例如:

if (bThing)
{
	return;
}
If - Else

if-else语句中的每个执行块都应该使用大括号。此举是为防止编辑时出错——未使用大括号时,可能会意外地将另一行加入if块中。这会造成if表达式无法控制该行,使之成为较差代码;更糟糕的情况是条件编译的项目会导致if/else语句中断。所以请务必使用大括号。


if (HaveUnrealLicense)
{
	InsertYourGameHere();
}
else
{
	CallMarkRein();
}
代码缩进
  • 按执行块缩进代码。
  • 在行的起始位置使用制表符(tab),而非空格缩进。将制表符设为4个字符。
命名空间

可以使用命名空间来组织类、函数和变量,需遵循以下规则。

  • 虚幻代码目前尚未包含在全局命名空间中。应避免在全局作用域中的冲突,尤其是在使用第三方代码时。
  • 不要在全局作用域中使用 “using” 声明,在 .cpp 中也不可以。(这会导致统一构建系统出错)
  • 可以在其他命名空间或函数中使用 “using” 声明。
  • 注意:前置声明需在各自的命名空间中进行声明,否则将引起链接错误。
  • UnrealHeaderTool不支持命名空间。定义UCLASS、USTRUCT等时,请勿使用。
物理依赖性
  • 若可能,文件名不应添加前缀。例如应为Scene.cpp,而非UScene.cpp。
  • 头文件中使用 #pragma once 避免多重包含。
  • 尽可能降低耦合度。
  • 尽可能使用 前置声明 替代 include
  • 使用 include 时尽量细化。如不要使用 Core.h 来完成某些头文件的包含。
  • 不要依赖间接包含的头文件。
  • 将大型函数拆分为逻辑子函数。编译器优化的一个方面就是消除常见的子表达式。函数越大,编译器识别它们的工作量就越大,构建时间也就越长。
  • 谨慎使用内联函数。因为内联函数会强制在不需要它们的文件中重新编译。内联函数仅可在浅显访问器中并且分析显示有益时使用。
  • 对于 FORCEINLINE 的使用应更加谨慎。因为所有的代码和局部变量都将扩展到调用函数中,这与大型函数问题相似,会导致编译时间大大加长。
一般格式问题
  • 修复编译器警告。出现编译器警告消息意味着某些项目有错。修复编译器警告的内容。若无法修复,使用#pragma压制警告;这是最后的补救办法。
  • 在文件末尾留下空白行。所有.cpp和.h文件应包含空白行,以便和gcc兼容。
  • 勿使float隐式转换为int32。此操作十分缓慢,且无法再所有编译器中进行编译。请固定使用appTrunc()函数转换为int32。此操作可在保证交叉编译器兼容性的情况下,同时生成更快代码。
  • 在字符串文字周围固定使用TEXT()宏。若未使用,在文字中构建FStrings的代码将导致不理想的字符转换过程。
  • 指针与引用应仅含一个空格,该空格位于指针/引用右侧。在文件中可更易查找指向特定类型的所有指针或引用。

你可能感兴趣的:(UE4从零开始,UE4)