1 枚举enum
// 枚举从0开始
enum color {red, green, blue=5} c;
c = green;
2 const
- 作用:定义常量、类型检查、防止修改、节省空间
- 定义常量:常量不可更改,且必须初始化。
- 指针与const:
// const位于*左侧,用于修饰指针所指的const对象
const char* a;
char const* a;
// const位于*右侧,用于修饰指针为const指针
char* const a;
// const指针指向const对象
const char* const a;
// 允许将非const对象的地址赋给指向const对象的指针
const int* ptr;
int val = 3;
ptr = &val;
// const指针必须初始化,且值不可更改
int* const ptr = &val;
// 指向const对象的const指针
const int val = 3;
const int* const ptr = &val;
- 对于自定义类型的输入参数,应采用常量引用的方式增加效率。
void func(const A &a) //尽量避免按值传递void func(A a)
- const在类中应用
const对象只能访问const成员函数,非const对象可访问任意成员函数。
3 智能指针
class Entity //自定义类
{
public:
Entity();
~Entity();
void Print();
};
// 智能指针,无需手动delete
std::unique_ptr<Entity> e = std::make_unique<Entity>();
std::unique_ptr<Entity> e(new Entity());
e->Print();
4 复制
- 浅复制:只复制了对象的内容,如类中的成员变量,其地址指向同一个对象(raw,copy =>obj)。
- 深复制:拷贝整个对象,通过复制构造函数Entity(const Entity& other)实现,其地址指向不同的对象(raw=>obj, copy=>obj)。
5 vector
std::vector<Entity> Entities;
// 遍历
for (Entity& e : Entities)
e.Print();
// 作函数参数(常量引用)
void Function(const std::vector<Entity>& entities);
// 优化(减少复制)
Entities.reserve(3); // 要求vector至少能容纳3个元素,避免不必要的重分配
Entities.push_back(e); // push_back()先构造对象再复制构造一次,会导致性能损失
Entities.emplace_back(1, 2, 3); // emplace_back()可根据输入参数原地构造对象,避免复制
6 使用第三方库
- 将外部库的include文件夹和bin文件夹拷贝,并放置在工程文件夹中。
- 拷贝头文件目录 $(SolutionDir)ThirdParty/include(相对路径)到属性\C++\常规\附加包含目录。
- 拷贝库文件目录 $(SolutionDir)ThirdParty/bin 到链接器\常规\附加库目录。
- 对于静态链接,将库文件glfw.lib拷贝至链接器\输入\附加依赖项;
对于动态链接,将指向dll的lib文件glfwdll.lib拷贝至链接器\输入\附加依赖项,并且将glfw.dll文件拷贝至输出的exe文件夹下。
7 函数多返回值处理
方法1:使用struct
// 返回变量
struct ReturnValue
{
std::string name;
int age;
};
// 多返回值函数
ReturnValue Function(const std::string& filepath)
{
//do something
return { out_name, out_age };
}
// 调用函数
auto person = Function("res/person/Annie.txt");
int score = FindClass(person.name, person.age);
方法2:利用引用传递在函数内修改变量
// 函数定义
void Function(const std::string& filepath, std::string& outName, int& outAge)
{
//do something
outName = ...;
outAge = ...;
}
方法3:C++17特性structured binding
// 函数定义
std::tuple<std::string, int> Function(const std::string& filepath)
{
//do something
return { "Cherno", 24 };
}
// 调用函数
auto [name, age] = Function();
8 template
// 模板函数
template<typename T>
void Print(T value)
{
std::cout << value << std::endl;
}
// 模板类
template<typename T, int N>
class Array
{
private:
T m_Array[N];
public:
int GetSize() const { return N; }
};
// 实例化
Array<std::string, 5> array;
9 Stack & Heap
Note:尽可能在stack中使用变量,除非数据较大或数据生命周期较长时,才使用heap。
int value = 5;// stack分配
int* hvalue = new int; // heap分配
*hvalue = 5;
10 宏macro
在属性/C++/预处理器/预处理定义,根据debug/release模式添加PR_DEBUG/PR_RELEASE。
// 通常用于调试时记录信息
#ifdef PR_DEBUG
#define LOG(x) std::cout << x << std::endl
#else
#define LOG(x)
#endif // PR_DEBUG
int main()
{
LOG("hello");
}
11 auto
自动推导数据类型,通常用于数据类型较长的情况,使用auto简化代码。
std::vector<std::string> strings;
for (std::vector<std::string>::iterator it = strings.begin();
it != strings.end(); it++) // 代码过长
for (auto it = strings.begin(); it != strings.end(); it++) // 使用auto简化
12 函数指针
void PrintValue(int value); // 待使用的函数
// 调用函数指针的函数
void ForEach(const std::vector<int>& values, void(*func)(int))
{
for (int value : values)
func(value);
}
// main()调用
ForEach(values, PrintValue);
13 lambda
auto lambda = [](int value) {return value > 3; }; //lambda表达式
std::vector<int> values = { 1,5,4,2,3 };
// 使用lambda寻找符合条件的值
auto it = std::find_if(values.begin(), values.end(),
[](int value) { return value > 3; }); // *it = 5
14 Thread线程
#include <thread>
static bool s_Finished = false; // 状态位
void DoWork()
{
using namespace std::literals::chrono_literals;
while (!s_Finished)
{
std::cout << "Working...\n";
std::this_thread::sleep_for(1s); // 线程以1s为间隔执行
}
}
int main()
{
std::thread worker(DoWork);
std::cin.get();
s_Finished = true;
worker.join();
std::cout << "Finished.\n";
}
15 计时
#include <chrono>
// 构造Timer计时器
struct Timer
{
std::chrono::time_point<std::chrono::steady_clock> start, end;
std::chrono::duration<float> duration;
Timer()
{
start = std::chrono::high_resolution_clock::now();
}
~Timer()
{
end = std::chrono::high_resolution_clock::now();
duration = end - start;
float ms = duration.count() * 1000.0f;
std::cout << "Timer took " << ms << " ms" << std::endl;
}
};
void Function() // 要计时的函数
{
Timer timer;
// do something
}
16 多维数组
int* array2d = new int[5 * 5];
for (int y = 0; y < 5; y++)
{
for (int x = 0; x < 5; x++)
{
array2d[x + y * 5] = 2;
}
}
17 排序
#include <algorithm>
int main()
{
std::vector<int> values = { 3, 5, 1, 4, 2 };
std::sort(values.begin(), values.end()); //默认升序
std::sort(values.begin(), values.end(), std::greater<int>()); //降序排序
// 按返回的true/false排序,true则a排在前面,false则b排在前面,下例为降序
std::sort(values.begin(), values.end(), [](int a, int b)
{ return a > b; });
}
18 多态(虚函数)
class Base
{
public:
Base(){}
virtual ~Base(){} //虚析构函数:防止基类指针不会调用子类的析构函数,从而引起的内存泄漏
virtual std::string GetName(); //虚函数:允许基类指针调用子类函数
virtual int GetScore() = 0; //纯虚函数:只有声明,实现留给子类
};
class Derived : public Base
{
public:
std::string GetName() override;
int GetScore() override;
};
19 C++17特性optional
#include <optional>
#include <fstream>
std::optional<std::string> ReadFileAsString(const std::string& filepath)
{
std::ifstream stream(filepath);
if (stream)
{
std::string result;
// read file
stream.close();
return result;
}
return {};
}
int main()
{
std::optional<std::string> data = ReadFileAsString("data.txt");
if (data.has_value())
std::cout << "File read successfully.\n";
else
std::cout << "File could not be opened.\n";
//若data存在,返回数据到value;否则返回Not present
std::string value = data.value_or("Not present");
}