赞
踩
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(完美转发)
作用:保证右值引用传递过程中,引用类型不发生变化
规则(用法):
友元函数不属于类的成员函数,但是它能够访问类的私有成员
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。