当前位置:   article > 正文

C++ 11 新特性 学习笔记_aglobeawaredefaultpawn

aglobeawaredefaultpawn

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中:

  1. // Fill out your copyright notice in the Description page of Project Settings.
  2. #pragma once
  3. #include "CoreMinimal.h"
  4. #include "list"
  5. #include "iostream"
  6. #include "GlobeAwareDefaultPawn.h"
  7. #include "GlobeAwareActor.generated.h"
  8. UCLASS()
  9. class UNREALEARTHLIBRARY_API AGlobeAwareActor : public AGlobeAwareDefaultPawn
  10. {
  11. GENERATED_BODY()
  12. public:
  13. // Sets default values for this actor's properties
  14. AGlobeAwareActor();
  15. virtual void BeginPlay() override;
  16. private:
  17. std::list<int> int_list;
  18. };
  19. template<typename T>
  20. class Test {
  21. public:
  22. void Print(T a) {
  23. for (templateIter = a.begin(); templateIter != a.end(); templateIter++) {
  24. PrintNumOnScreen(*templateIter);
  25. }
  26. }
  27. void PrintNumOnScreen(FString str) {
  28. GEngine->AddOnScreeenDebugMessage(-1, 10.f, FColor::Red, str);
  29. }
  30. void PrintNumOnScreen(int value) {
  31. GEngine->AddOnScreenDebugMessage(-1, 10.f, FColor::Red, FString::FromInt(value));
  32. }
  33. private:
  34. decltype(T().begin()) templateIter;
  35. };
  1. // Fill out your copyright notice in the Description page of Project Settings.
  2. #include "GlobeAwareActor.h"
  3. AGlobeAwareActor::AGlobeAwareActor()
  4. {
  5. // Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
  6. PrimaryActorTick.bCanEverTick = true;
  7. int_list = { 1, 2, 3, 4 };
  8. }
  9. void AGlobeAwareActor::BeginPlay() {
  10. Super::BeginPlay();
  11. Test<std::list<int>> *test = new Test<std::list<int>>();
  12. test->Print(int_list);
  13. }

编译成功,运行效果如下:

当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看起来更直观

  1. // Copyright Epic Games, Inc. All Rights Reserved.
  2. #pragma once
  3. using func = void(*)(FString);
  4. #define NONE LogChoice::NA
  5. #define WARNING LogChoice::Warning
  6. #define ERROR LogChoice::Error
  7. #define DISPLAY LogChoice::Display
  8. #define RED FColor::Red
  9. #define GREEN FColor::Green
  10. #define CYAN FColor::Cyan
  11. #define BLUE FColor::Blue
  12. #define YELLOW FColor::Yellow
  13. #define BLACK FColor::Black
  14. #define SILVER FColor::Silver
  15. #define WHITE FColor::White
  16. #define PURPLE FColor::Purple
  17. #define ORANGE FColor::Orange
  18. enum LogChoice : uint8 {
  19. NA,
  20. Warning,
  21. Error,
  22. Display
  23. };
  24. namespace DebugHelper {
  25. void WarningLog(FString text) {
  26. UE_LOG(LogTemp, Warning, TEXT("%s"), *text);
  27. }
  28. void ErrorLog(FString text) {
  29. UE_LOG(LogTemp, Error, TEXT("%s"), *text)
  30. }
  31. void DisplayLog(FString text) {
  32. UE_LOG(LogTemp, Display, TEXT("%s"), *text);
  33. }
  34. void Printf(float time, FColor color, float text_float, bool isUseLog = false, LogChoice logChoice = NONE) {
  35. FString FloatToString = FString::SanitizeFloat(text_float);
  36. func logFunc = NULL;
  37. if (isUseLog) {
  38. switch (logChoice) {
  39. case NONE: {
  40. break;
  41. }
  42. case WARNING: {
  43. logFunc = WarningLog;
  44. break;
  45. }
  46. case ERROR: {
  47. logFunc = ErrorLog;
  48. break;
  49. }
  50. case DISPLAY: {
  51. logFunc = DisplayLog;
  52. break;
  53. }
  54. default: {
  55. }
  56. }
  57. logFunc(FloatToString);
  58. }
  59. GEngine->AddOnScreenDebugMessage(-1, time, color, FloatToString);
  60. }
  61. void Printf(float time, FColor color, FString text, bool isUseLog = false, LogChoice logChoice = LogChoice::NA) {
  62. func logFunc = NULL;
  63. if (isUseLog) {
  64. switch (logChoice) {
  65. case NONE: {
  66. break;
  67. }
  68. case WARNING: {
  69. logFunc = WarningLog;
  70. break;
  71. }
  72. case ERROR: {
  73. logFunc = ErrorLog;
  74. break;
  75. }
  76. case DISPLAY: {
  77. logFunc = DisplayLog;
  78. break;
  79. }
  80. default: {
  81. }
  82. }
  83. logFunc(text);
  84. }
  85. GEngine->AddOnScreenDebugMessage(-1, time, color, text);
  86. }
  87. };

10、委托构造函数

由于第二个构造函数包含第一个构造函数,所以可以写成以下形式

委托构造就是构造函数嵌套其它构造函数进行使用


11、继承构造函数

相当于写了以下代码:

提高了写代码的速度,因为Child继承了Base的int m_i,double m_j, string m_k,所以要在Child中也要对这些变量进行初始化,所以就得每个写它们父类构造函数的赋值,极其麻烦,现在可以直接替换称using Base::Base,就结束,这就是继承构造函数


12、初始化列表


13、std::initializer::list

接收任意多个相同参数的能力

  1. #include "iostream"
  2. using namespace std;
  3. template<typename T>
  4. void func(std::initializer_list<T> llist) {
  5. auto it = llist.begin();
  6. for (; it != llist.end(); it++) {
  7. cout << *it << endl;
  8. }
  9. }
  10. int main() {
  11. func<int>({ 1,2,3,4,5 });
  12. func<string>({ "123","534" });
  13. return 0;
  14. }

 std::initializer::list只能接收初始化列表,不能接收对象

使用情景:

  1. #include "SpawnAc.h"
  2. void ASpawnAc::BeginPlay() {
  3. Super::BeginPlay();
  4. SpawningAc({ 1, 2, 3 });//这些123可以用于actor编号等,如果为字符串可以为actor名字等用途
  5. }
  6. void ASpawnAc::SpawningAc(std::initializer_list<int> llist) {
  7. auto it = llist.begin();
  8. for (; it != llist.end(); it++) {
  9. GetWorld()->SpawnActor<AActor>();
  10. }
  11. }

 生成了对应的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、可调用对象

  1. #include "iostream"
  2. using namespace std;
  3. using funcptr = void(*)(int, string);
  4. class Test {
  5. public:
  6. Test(int a, string b) {
  7. cout << b << " " << a << endl;
  8. }
  9. operator funcptr() {
  10. return PrintIntAndString;
  11. }
  12. static void PrintIntAndString(int a, string b) {
  13. cout << a << " " << b << endl;
  14. }
  15. };
  16. int main() {
  17. Test t(1, "12");
  18. t(1, "12");
  19. return 0;
  20. }

为什么一定要用static,因为static的目标是类,而没有static的目标对象是类的对象,在operator functptr的时候是没有对象的,所以一定要加上static

将类对象转化为函数指针,该类函数称作为仿函数


16、std::function

需要头文件#include "functional"

std::function<返回值类型(函数参数)>  name = 可调用对象

1、包装普通函数

  1. #include "iostream"
  2. #include "functional"
  3. using namespace std;
  4. int hello(string text) {
  5. cout << text << endl;
  6. return 1;
  7. }
  8. int main() {
  9. function<int(string)> testFunc = hello;
  10. hello("123");
  11. return 0;
  12. }

2、包装静态函数

  1. #include "iostream"
  2. #include "functional"
  3. using namespace std;
  4. static void world(string text) {
  5. cout << text << endl;
  6. }
  7. class Test {
  8. public:
  9. static void world(string text) {
  10. cout << text << endl;
  11. }
  12. };
  13. int main() {
  14. function<void(string)> f1 = world;
  15. f1("4322");
  16. f1 = Test::world;
  17. f1("55345");
  18. return 0;
  19. }

  1. #include "iostream"
  2. #include "functional"
  3. using namespace std;
  4. template<typename T, typename T1, typename T2>
  5. class Test {
  6. public:
  7. Test(const function<T(T1, T2)>& f1) : funcptr(f1) {}
  8. void notify(T1 t1, T2 t2) {
  9. funcptr(t1, t2);
  10. }
  11. private:
  12. function<T(T1, T2)> funcptr;
  13. };
  14. void Hello(int a, string b) {
  15. cout << a << " " << b << endl;
  16. }
  17. int main() {
  18. Test<void, int, string> test(Hello);
  19. test.notify(1, "123");
  20. return 0;
  21. }


17、std::bind

  1. #include "iostream"
  2. #include "functional"
  3. using namespace std;
  4. int Add(int x, int y, const function<void(int, int)>& f1){
  5. if ((x + y) % 2) {
  6. f1(x, y);
  7. }
  8. return 1;
  9. }
  10. void add(int x, int y) {
  11. cout << x + y << endl;
  12. }
  13. int main() {
  14. auto f2 = bind(add, placeholders::_1, placeholders::_2);
  15. Add(2, 5, f2);
  16. Add(3, 5, f2);
  17. return 0;
  18. }

 


18、lambda表达式

格式:[]() {} ->ret{body;};

 

要调用Lambda函数一定要在最后加上()以及参数 

lambda是仿函数


19、右值引用

使用场景:当A a = 临时对象;该临时对象通过大量运算进行构造出来,这时候,临时对象再拷贝给a,这样同样也会消耗大量资源,这里就用右值引用大大减少了开销:

A &&a = 临时对象; 减少了拷贝,且立马销毁的开销

要以上效果必须得先实现移动拷贝,将临时变量当作输入a传进来,将内部要用的指针的地址给到新对象中的指针的地址,然后将临时变量的指针赋值为nullptr,这个就是移动构造,不用拷贝构造,不用立马销毁就可以将值全部拿过来的方法

  1. #include "iostream"
  2. using namespace std;
  3. class RightVTest {
  4. public:
  5. RightVTest(int* nnum) : num(nnum) {}
  6. RightVTest(RightVTest&& r) : num(r.num) {
  7. r.num = nullptr;
  8. cout << *num << endl;
  9. }
  10. int* num;
  11. };
  12. RightVTest GetTemp() {
  13. int b = 5;
  14. RightVTest test(&b);
  15. return test;
  16. }
  17. int main() {
  18. int b = 45;
  19. int* num = &b;
  20. RightVTest&& rightVTest = GetTemp();
  21. return 0;
  22. }

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(完美转发)

作用:保证右值引用传递过程中,引用类型不发生变化

规则(用法):


友元函数不属于类的成员函数,但是它能够访问类的私有成员 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/空白诗007/article/detail/765386
推荐阅读
相关标签
  

闽ICP备14008679号