1、字符串原始字面量
R“()”用于取消转义,可用于路径表示
运行成功
这两个RawValue起到描述作用(可以不写),并不参与输出
注意,这里输出中文乱码
2、nullptr
NULL在C++中表示0,在非C++中表示万能指针
nullptr是空指针,而不是0,能兼容各种类型的指针,但为空
3、constexpr
在定义常量时,const与constexpr是等价的
constexpr修饰函数时,函数应尽可能精简:
1、不能出现非常量表达式之外的语句(using指令、typedef指令、static_assert、return语句除外)
例如,不能出现for循环
场景:简单的计算
4、auto 与 decltype 类型推导
auto不能去定义数组:
auto a[10] = { 1, 2, 3 };//为错误写法
auto推导的对象必须声明和赋值同时进行,例如auto a = 3;而不能直接auto a;因为是通过这个3来推导a的类型的,而decltype不需要
在UE4中:
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "list"
#include "iostream"
#include "GlobeAwareDefaultPawn.h"
#include "GlobeAwareActor.generated.h"
UCLASS()
class UNREALEARTHLIBRARY_API AGlobeAwareActor : public AGlobeAwareDefaultPawn
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AGlobeAwareActor();
virtual void BeginPlay() override;
private:
std::list<int> int_list;
};
template<typename T>
class Test {
public:
void Print(T a) {
for (templateIter = a.begin(); templateIter != a.end(); templateIter++) {
PrintNumOnScreen(*templateIter);
}
}
void PrintNumOnScreen(FString str) {
GEngine->AddOnScreeenDebugMessage(-1, 10.f, FColor::Red, str);
}
void PrintNumOnScreen(int value) {
GEngine->AddOnScreenDebugMessage(-1, 10.f, FColor::Red, FString::FromInt(value));
}
private:
decltype(T().begin()) templateIter;
};
// Fill out your copyright notice in the Description page of Project Settings.
#include "GlobeAwareActor.h"
AGlobeAwareActor::AGlobeAwareActor()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
int_list = { 1, 2, 3, 4 };
}
void AGlobeAwareActor::BeginPlay() {
Super::BeginPlay();
Test<std::list<int>> *test = new Test<std::list<int>>();
test->Print(int_list);
}
编译成功,运行效果如下:
当T没有构造函数时,需要对函数进行返回值后置:这里以TArray<int>为例
auto Function->decltype(TArray<int>) {}
5、final修饰的函数,不能虚函数重写、继承,正确用法如下:
这时候继承自Child过后就不能对test方法进行重写了,俗话说的好,final断子绝孙,嗯,好记
在Child类后面加final,之后类就不能被继承了
6、override
如果B类继承自A类,B类型想定义一个与A类一模一样的方法,若A类的该方法有virtual修饰,那么该行为为重写,若没有virtual修饰,叫覆盖,若只是方法名意义,其余不一样,则叫重载
7、尖括号
例如原来TArray<list<int>> a,这里的>>会有歧义,4>>2的运算符号,之前必须TArray<list<int> > a加个空格来区别,而c++11过后就可以写成TArray<list<int>> a了
8、模板默认类型
不只是可以通过传递类型进行类型确定,也可以传递对象参数进行类型推导,如上
9、using功能
①命名空间
使用场景:在C/C++中,变量、函数和类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染。
using namespace std;
②定义类型别名 (和typedef意义)
using MY_INT = int ;
typedef int MY_INT;
总结:using看起来更直观
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
using func = void(*)(FString);
#define NONE LogChoice::NA
#define WARNING LogChoice::Warning
#define ERROR LogChoice::Error
#define DISPLAY LogChoice::Display
#define RED FColor::Red
#define GREEN FColor::Green
#define CYAN FColor::Cyan
#define BLUE FColor::Blue
#define YELLOW FColor::Yellow
#define BLACK FColor::Black
#define SILVER FColor::Silver
#define WHITE FColor::White
#define PURPLE FColor::Purple
#define ORANGE FColor::Orange
enum LogChoice : uint8 {
NA,
Warning,
Error,
Display
};
namespace DebugHelper {
void WarningLog(FString text) {
UE_LOG(LogTemp, Warning, TEXT("%s"), *text);
}
void ErrorLog(FString text) {
UE_LOG(LogTemp, Error, TEXT("%s"), *text)
}
void DisplayLog(FString text) {
UE_LOG(LogTemp, Display, TEXT("%s"), *text);
}
void Printf(float time, FColor color, float text_float, bool isUseLog = false, LogChoice logChoice = NONE) {
FString FloatToString = FString::SanitizeFloat(text_float);
func logFunc = NULL;
if (isUseLog) {
switch (logChoice) {
case NONE: {
break;
}
case WARNING: {
logFunc = WarningLog;
break;
}
case ERROR: {
logFunc = ErrorLog;
break;
}
case DISPLAY: {
logFunc = DisplayLog;
break;
}
default: {
}
}
logFunc(FloatToString);
}
GEngine->AddOnScreenDebugMessage(-1, time, color, FloatToString);
}
void Printf(float time, FColor color, FString text, bool isUseLog = false, LogChoice logChoice = LogChoice::NA) {
func logFunc = NULL;
if (isUseLog) {
switch (logChoice) {
case NONE: {
break;
}
case WARNING: {
logFunc = WarningLog;
break;
}
case ERROR: {
logFunc = ErrorLog;
break;
}
case DISPLAY: {
logFunc = DisplayLog;
break;
}
default: {
}
}
logFunc(text);
}
GEngine->AddOnScreenDebugMessage(-1, time, color, text);
}
};
10、委托构造函数
由于第二个构造函数包含第一个构造函数,所以可以写成以下形式
委托构造就是构造函数嵌套其它构造函数进行使用
11、继承构造函数
相当于写了以下代码:
提高了写代码的速度,因为Child继承了Base的int m_i,double m_j, string m_k,所以要在Child中也要对这些变量进行初始化,所以就得每个写它们父类构造函数的赋值,极其麻烦,现在可以直接替换称using Base::Base,就结束,这就是继承构造函数
12、初始化列表
13、std::initializer::list
接收任意多个相同参数的能力
#include "iostream"
using namespace std;
template<typename T>
void func(std::initializer_list<T> llist) {
auto it = llist.begin();
for (; it != llist.end(); it++) {
cout << *it << endl;
}
}
int main() {
func<int>({ 1,2,3,4,5 });
func<string>({ "123","534" });
return 0;
}
std::initializer::list只能接收初始化列表,不能接收对象
使用情景:
#include "SpawnAc.h"
void ASpawnAc::BeginPlay() {
Super::BeginPlay();
SpawningAc({ 1, 2, 3 });//这些1,2,3可以用于actor编号等,如果为字符串可以为actor名字等用途
}
void ASpawnAc::SpawningAc(std::initializer_list<int> llist) {
auto it = llist.begin();
for (; it != llist.end(); it++) {
GetWorld()->SpawnActor<AActor>();
}
}
生成了对应的3个actor
14、for循环的新式表达:
vector<int> a {1, 2, 3};
for(auto item : a){
cout << item << endl;
}
因为auto item : a每次都会拷贝,消耗会大一些,如果用引用则不会产生拷贝,还能修改item的值,从而提升效率:
for(auto &item : a) {
cout << item << endl;
}
如果想只读则加个const即可
for(const auto &item : a) {
cout << item << endl;
}
15、可调用对象
#include "iostream"
using namespace std;
using funcptr = void(*)(int, string);
class Test {
public:
Test(int a, string b) {
cout << b << " " << a << endl;
}
operator funcptr() {
return PrintIntAndString;
}
static void PrintIntAndString(int a, string b) {
cout << a << " " << b << endl;
}
};
int main() {
Test t(1, "12");
t(1, "12");
return 0;
}
为什么一定要用static,因为static的目标是类,而没有static的目标对象是类的对象,在operator functptr的时候是没有对象的,所以一定要加上static
将类对象转化为函数指针,该类函数称作为仿函数
16、std::function
需要头文件#include "functional"
std::function<返回值类型(函数参数)> name = 可调用对象
1、包装普通函数
#include "iostream"
#include "functional"
using namespace std;
int hello(string text) {
cout << text << endl;
return 1;
}
int main() {
function<int(string)> testFunc = hello;
hello("123");
return 0;
}
2、包装静态函数
#include "iostream"
#include "functional"
using namespace std;
static void world(string text) {
cout << text << endl;
}
class Test {
public:
static void world(string text) {
cout << text << endl;
}
};
int main() {
function<void(string)> f1 = world;
f1("4322");
f1 = Test::world;
f1("55345");
return 0;
}
#include "iostream"
#include "functional"
using namespace std;
template<typename T, typename T1, typename T2>
class Test {
public:
Test(const function<T(T1, T2)>& f1) : funcptr(f1) {}
void notify(T1 t1, T2 t2) {
funcptr(t1, t2);
}
private:
function<T(T1, T2)> funcptr;
};
void Hello(int a, string b) {
cout << a << " " << b << endl;
}
int main() {
Test<void, int, string> test(Hello);
test.notify(1, "123");
return 0;
}
17、std::bind
#include "iostream"
#include "functional"
using namespace std;
int Add(int x, int y, const function<void(int, int)>& f1){
if ((x + y) % 2) {
f1(x, y);
}
return 1;
}
void add(int x, int y) {
cout << x + y << endl;
}
int main() {
auto f2 = bind(add, placeholders::_1, placeholders::_2);
Add(2, 5, f2);
Add(3, 5, f2);
return 0;
}
18、lambda表达式
格式:[]() {} ->ret{body;};
要调用Lambda函数一定要在最后加上()以及参数
lambda是仿函数
19、右值引用
使用场景:当A a = 临时对象;该临时对象通过大量运算进行构造出来,这时候,临时对象再拷贝给a,这样同样也会消耗大量资源,这里就用右值引用大大减少了开销:
A &&a = 临时对象; 减少了拷贝,且立马销毁的开销
要以上效果必须得先实现移动拷贝,将临时变量当作输入a传进来,将内部要用的指针的地址给到新对象中的指针的地址,然后将临时变量的指针赋值为nullptr,这个就是移动构造,不用拷贝构造,不用立马销毁就可以将值全部拿过来的方法
#include "iostream"
using namespace std;
class RightVTest {
public:
RightVTest(int* nnum) : num(nnum) {}
RightVTest(RightVTest&& r) : num(r.num) {
r.num = nullptr;
cout << *num << endl;
}
int* num;
};
RightVTest GetTemp() {
int b = 5;
RightVTest test(&b);
return test;
}
int main() {
int b = 45;
int* num = &b;
RightVTest&& rightVTest = GetTemp();
return 0;
}
auto &&a = 不管是左值还是右值,若是auto&& a = 5;那么auto推导为int,若是auto&& a = b;那么auto推导为int& 为int&&& a = b:引用折叠,两个引用就省略为int& a = b;
20、std::move
将左值转化为右值
按照这样写法,左值t2是没有办法给右值引用t3赋值的
加上move过后将t2从左值变成右值,即可对t3进行赋值
即使t2是左值,为了确保t2是左值,那么加上move也可以让左值变成左值,右值变成左值,反正move确保变量是左值
21、std::forward(完美转发)
作用:保证右值引用传递过程中,引用类型不发生变化
规则(用法):
友元函数不属于类的成员函数,但是它能够访问类的私有成员