1. C++入门

由于本框架采用C++和基于C++的SFML图形库,所以如果您需要进一步进行修改和创作,就需要了解下述内容。

1.1. 数字变量的类型

C++中数字常用变量类型分为 short , int , long , long long , float , double

short 是短整型变量,范围为 -32768~+32767int 为整形变量, 范围为 -2147483648~2147483647long 为32位长整型变量, 实际上为 long int ,在C++中, longint 范围相同, long long 为64位长整型数据,范围为 -9223372036854774808~9223372036854774807

float 为浮点型变量,范围为 -3.4E38~3.4E38double 为双浮点类型变量,范围为 -1.7E308~1.7E308 ,这两种类型支持小数点的计算。

如果在前面加上 unsigned ,范围则会从0开始,上限增加一倍。

1.2. 布尔类型

在C++中,布尔类型变量(bool)的取值为 truefalse ,但是, true 可以在计算中等价转换为 1false 在计算中可以等价转换为 0

所以可以延申处下面的小技巧,例如bool变量 atrue 时, b 会增加3,否则不增加,可以直接写为: b = b + a * 3;

1.3. 字符串

字符串的类型为 string ,不同的字符串之间可以用 + 连接。

1.3.1. 宽字符串

需要注意,因为编码的缘故,中文/汉字/全角字符在直接使用 string 输出到屏幕上时会变成乱码, 此时需要引进 宽字符 来表示中文字符,工程内提供了一个函数 str2wstr 来进行转换,不过一般不用担心, 需要显示中文的地方(如 drawText 函数)内部都对输入的 string 类型变量进行了转换,您只需要放心用 string 即可。

1.3.2. std::to_string(value)

to_stringC++11 引入的标准,可以将数字转换成字符串类型,需要使用 <string> 头文件。

1.3.3. stoi(str),stof(str)

stoistof 可以将字符串转换成整型、浮点型变量,需要使用 <string> 头文件。

类似的函数还有如下几种:

stoi

将字符串转换为int类型

stol

将字符串转换为long类型

stoll

将字符串转换为long long类型

stoui

将字符串转换为unsigned int类型

stoull

将字符串转换为unsigned long long类型

1.3.4. std::format(fmt,…args)

formatC++20 引入的标准,用以格式化字符串,需要使用 <format> 头文件和 using namespace std;

下面是 format 的一个示例:

1int a = 3,b = 4;
2std::cout << std::format("a={},b={}",a,b) << endl;

可以注意到, formatprintf``有部分相似之处,即格式化输出,不过在 ``printf 中的例如 %d 等内容, 都被换成了 {} ,然后在后面逐个表示变量即可,一般数字和字符串不需要再进行调整。

1.4. 条件分歧

1.4.1. 真伪值

在C++中,因为历史原因(最初C语言标准并没有bool类型),在条件分歧等判断中, 实际上是 非零 实际上是

1.4.2. 三目运算符

使用符号 ?: 可以在同一行内进行条件分歧。

下面是一个示例:

1int a = 3;
2std::cout << (a > 10 ? "big" : "small") << endl;

这个示例的意思是, 输出时如果 a 大于10,则输出 big ,否则输出 small

1.5. Lambda表达式

Labmda表达式是C++11引入的标准,一般用于定义匿名函数,使得代码更加灵活简洁,最常见的Lambda表达式如下所示:

1auto plus = [] (int v1,int v2) -> int { return v1 + v2; }
2int sum = plus(1,2);

在写比如自定义排序时,往常可能需要写一个 cmp 函数,但是这种只在特定范围调用的函数可以用Lambda表达式来写,比如如下示例:

 1struct Item
 2{
 3    Item(int aa,int bb) : a(aa),b(bb) {}
 4    int a;
 5    int b;
 6};
 7
 8int main()
 9{
10    std::vector<Item> vec;
11    vec.push_back(Item(1,19));
12    vec.push_back(Item(10,3));
13    vec.push_back(Item(3,7));
14    vec.push_back(Item(8,12));
15    vec.push_back(Item(2,1));
16
17    // 根据Item中成员a升序排序
18    std::sort(vec.begin(),vec.end(),
19        [] (const Item& v1,const Item& v2) { return v1.a < v2.a; });
20
21    // 打印vec中的item成员
22    std::for_each(vec.begin(),vec.end(),
23        [] (const Item& item) { std::cout << item.a << " " << item.b << std::endl; });
24    return 0;
25}

1.5.1. Lambda表达式写法

Lambda表达式有如下三种写法:

1[captures]<tparams>(params) lambda-specifiers {body};
2[captures](params) lambda-specifiers {body};
3[captures](params) {body};

1.5.2. captures

captures 是捕获列表,可以把上下文变量以值或引用的方式捕获,在 body 中直接使用。

通过引用隐式捕获 [&] :所有局部变量的名字都能使用,所有局部变量都通过引用访问。

通过值隐式捕获 [=] :所有局部变量的名字都能使用,所有名字都指向局部变量的副本,这些副本是在lambda表达式的调用点获得。

1.5.3. tparams

模板参数列表(C++20引入),让Lambda可以像模板函数一样被调用。

1.5.4. params

参数列表,和正常函数类似。

1.5.5. lambda-specifiers

Lambda说明符,包括specifiers,exception,attr,trailing-return-type和requires(C++20),顺序不能改变,每一个组件都是可选的。

1.6. std::ranges

std::ranges 是C++20的新特性,以下是几个常用的算法。

1.6.1. std::ranges::any_of(container,condition)

用于判断一个容器中是否有任意一个符合条件,条件可用 lambda 表达式来确定,下面举个简单的例子。

按照传统的方法,在地图中查找一个符合要求xy坐标的事件的函数haveAnEvent(x,y)写法如下:

1for (auto ev : mapEvents)
2    if (ev.x == x && ev.y == y)
3        return true;
4return false;

但是有了 any_of 之后,可以写成:

1return ranges::any_of(mapEvents,[&](auto ev){
2    return (ev.x == x && ev.y == y);
3});

1.6.1.1. std::ranges::count(container,compare) & std::ranges::count_if(container,condition)

第一个 std::ranges::count 返回的是容器中和给定值相等的元素的数量, 第二个 std::ranges::count_if 返回的是 满足指定条件 的元素数量,可以是大于或者小于,下面是一个简单的例子:

1std::vector<int> numbers = {1,2,3,2,4,2,5};
2int valueToCount = 2;
3int count = std::ranges::count(numbers,valueToCount);
4std::cout << "Count of " << valueToCount << " is: " << count << std::endl;
1std::vector<int> numbers = {1,2,3,4,5,6,7};
2int threshold = 3;
3auto condition = [threshold](int x) {
4    return x > threshold;
5};
6int count = std::ranges::count_if(numbers,condition);
7std::cout << "Count of elements greater than " << threshold << " is: " << count << std::endl;

1.6.1.2. std::ranges::find(container,compare) & std::ranges::find_if(container,condition)

第一个 std::ranges::find 返回的是在范围内查找的与给定值相等的元素的 迭代器 , 第二个 std::ranges::find_if 返回的是 满足指定条件 的元素的迭代器。

RM中有一个函数叫做 check_event(x,y) ,返回的是在(x,y)坐标上的事件ID,按理来说,本应该这么写:

1for (auto ev : mapEvents)
2    if (ev.x == x && ev.y == y)
3        return ev.ID;
4return -1;

但是现在可以写成这样:

1auto ev = ranges::find_if(mapEvents,[&](auto ev) {
2    return ev.x == x && ev.y ==y;
3});
4return ev == mapEvents.end() ? -1 : ev->ID;

1.6.1.3. std::ranges::transform(container,start,function)

这个函数可以给容器内从 start 开始的所有元素进行操作 function ,例如:

 1std::vector<int> numbers = {1,2,3,4,5};
 2std::vector<int> squaredNumbers(numbers.size());
 3// 使用 std::ranges::transform 对每个元素进行平方操作
 4std::ranges::transform(numbers,squaredNumbers.begin(),[](int x) {
 5    return x * x;
 6});
 7// 打印转换后的结果
 8for (int square : squaredNumbers) {
 9    std::cout << square << " ";
10}

1.6.1.4. std::ranges::min(container) & std::ranges::max(container)

可以求容器内的最小/最大值,但是前提要是可对比的对象,或者自行写好重载小于号或者compare函数。

1.6.1.5. std::ranges::all_of(container,condition) & std::ranges::none_of(container,condition)

用于检查容器内元素是否 全部满足不满足 条件。

1.7. std::filesystem

std::filesystem 是C++17中引入的标准库,它提供了一组用于操作文件系统的函数和类。 它的目标是为了简化对文件和目录的操作,使文件系统的操作更加便捷和安全。

1.7.1. std::filesystem::path

std::filesystem::path() :默认构造函数,创建一个空的路径对象。

std::filesystem::path(const std::string&) :使用给定的字符串构造路径对象。

std::filesystem::path::string() :将路径对象转换为字符串表示。

1.7.2. 路径操作

std::filesystem::current_path() :返回当前工作目录的路径对象。

std::filesystem::exists(const std::filesystem::path&) :检查路径是否存在。

std::filesystem::create_directory(const std::filesystem::path&) :创建一个新的目录。

std::filesystem::remove(const std::filesystem::path&) :删除文件或目录。

std::filesystem::rename(const std::filesystem::path&,const std::filesystem::path&) :重命名文件或目录。

1.7.3. 文件和目录属性

std::filesystem::file_size(const std::filesystem::path&) :返回文件的大小。

std::filesystem::last_write_time(const std::filesystem::path&) :返回最后修改时间。

std::filesystem::is_directory(const std::filesystem::path&) :检查路径是否为目录。

std::filesystem::is_regular_file(const std::filesystem::path&) :检查路径是否为普通文件。

1.7.4. 文件遍历

std::filesystem::directory_iterator :遍历指定目录中的文件和目录条目。

std::filesystem::recursive_directory_iterator :递归遍历指定目录及其子目录中的文件和目录条目。