【UE4学习】20200826 UE4 编码规范

概述

提几个C++中需要注意的规范。

什么注释要写好,命名要清晰,这些比较基础的就不提了。说一些有意思和自己不知道的。

一切都看这个文档就好。

布尔值

布尔值的b高于一切,只要是布尔值,第一个字母必须是小写b。

const In Out

  • 函数的参数里,不会被改动到的一般是const,并且名字前面还要加In;如果有可能会被改动到内容,那么就引用+名字前加Out。
  • 如果函数不会改动到实例的内容,那么函数要标注为const函数
  • for-each循环里,如果不会改动到元素,同样用const标注元素
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void SomeMutatingOperation(FThing& OutResult, const TArray<Int32>& InArray)
{
// 此处不会修改InArray,但可能会修改OutResult
}

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

TArray<FString> StringArray;
for (const FString& :StringArray)
{
// 此循环的主体不会修改StringArray
}
  • 基元类型作为参数时,如果不需要改动到(其实如果值传递的话也没能改到),那干脆就加个const,表明不会被改到(感觉无所谓?)
1
2
3
4
5
void AddSomeThings(const int32 Count)
{
const int32 CountPlusOne = Count + 1;
// 函数主体不会改变Count或CountPlusOne
}

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

1
2
3
4
5
6
7
8
9
10
11
// 差 - 返回常量数组
const TArray<FString> GetSomeArray();

// 优 - 返回常量数组的引用
const TArray<FString>& GetSomeArray();

// 优 - 返回指向常量数组的指针
const TArray<FString>* GetSomeArray();

// 差 - 返回指向常量数组的常量指针
const TArray<FString>* const GetSomeArray();

这段的意思大概是说如果直接打的是const返回的话,会发生复制?

const引用的意思是对const对象的引用。

如果用一个const去引用一个非const,会进行隐式转换。

现代C++语言语法

override & final

多多使用。

nullptr

多多使用。NULL这种C时代的宏就不要用了。

auto关键字

能不用就不用。

最好仅在这些场合用:

  • 代表lambda表达式时
  • 代表迭代器时(一般类型名会非常冗长)
  • 模板代码

lambda

可以用,但是不要表达太复杂的逻辑,一般在两行以内为佳。

捕捉列表用显式捕捉,别用[=]

enum class

多用,别用普通的enum了。

但是如果想公布到蓝图,必须继承于uint8

代码格式

换行

大括号的起始要换行,if-else的else也要换行。

1
2
3
4
5
6
7
8
9
10
11
12
13
if (bThing)
{
return;
}

if (bHaveUnrealLicense)
{
InsertYourGameHere();
}
else
{
CallMarkRein();
}

缩进用制表符,不用空格

如题。把tab设置成制表符。

命名空间

  • UHT不支持命名空间,所以用UCLASS, USTRUCT的时候就不要用命名空间了
  • 别乱用using
  • 前置声明需要在各自命名空间中进行声明

其他建议

多使用flag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 旧样式
FCup* MakeCupOfTea(FTea* Tea, bool bAddSugar = false, bool bAddMilk = false, bool bAddHoney = false, bool bAddLemon = false);
FCup* Cup = MakeCupOfTea(Tea, false, true, true);

// 新样式
enum class ETeaFlags
{
None,
Milk = 0x01,
Sugar = 0x02,
Honey = 0x04,
Lemon = 0x08
};
ENUM_CLASS_FLAGS(ETeaFlags)

FCup* MakeCupOfTea(FTea* Tea, ETeaFlags Flags = ETeaFlags::None);
FCup* Cup = MakeCupOfTea(Tea, ETeaFlags::Milk | ETeaFlags::Honey);

避免过多的参数

如果参数过多,直接建立一个新的结构体,结构体内还可以设置默认值。

1
2
3
4
5
6
7
8
9
10
11
12
13
// 旧样式
TUniquePtr<FCup[]> MakeTeaForParty(const FTeaFlags* TeaPreferences, uint32 NumCupsToMake, FKettle* Kettle, ETeaType TeaType = ETeaType::EnglishBreakfast, float BrewingTimeInSeconds = 120.0f);

// 新样式
struct FTeaPartyParams
{
const FTeaFlags* TeaPreferences = nullptr;
uint32 NumCupsToMake = 0;
FKettle* Kettle = nullptr;
ETeaType TeaType = ETeaType::EnglishBreakfast;
float BrewingTimeInSeconds = 120.0f;
};
TUniquePtr<FCup[]> MakeTeaForParty(const FTeaPartyParams& Params);

避免使用 bool 和 Fstring 重载函数

1
2
3
4
void Func(const FString& String);
void Func(bool bBool);

Func(TEXT("String")); // Calls the bool overload!

虚函数

在派生类中重写虚函数,同时使用virtualoverride(其实并无必要)

Buy Me A Coffee / 捐一杯咖啡的钱
分享这篇文章~
0%
//