# C++学习笔记 **Repository Path**: Y_F_Wang/cppLearningNotes ## Basic Information - **Project Name**: C++学习笔记 - **Description**: C++语言学习笔记、代码片段 - **Primary Language**: C++ - **License**: LGPL-3.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-07-31 - **Last Updated**: 2024-07-31 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # C++语言学习笔记 ## 一、变量和基本类型 ### 1. constexpr变量 C++11标准中,可以通过声明constexpr让编译器验证常量表达式。 一般使用constexpr来声明一个常量表达式。 ```cpp constexpr int mf = 20; constexpr int limit = mf + 1; ``` constexpr和const是有区别的: ```cpp const int sz = get_size(); //sz是常量,但它的值只有运行时才能确定 constexpr int csz = size(); //只有size函数为constexpr函数时,此语句才正确 ``` 对于指针类型,constexpr和const也有区别: ```cpp const int *p = nullptr //p是一个指向int型常量的指针(p的值可以改变,但不能改变解引用*p) constexpr int *q = nullptr; //q是一个常量指针,指向nullptr(q是个始终为nullptr的常量) ``` ### 2. decltype和引用 使用类型说明符号decltype可以获得表达式的类型,比如 ```cpp int a{0}; //C++11新引入的初始化方式 decltype(a) x = 0; // x的类型是int decltype((x)) y = x; // y的类型是int&,且绑定到x ``` 其中,`decltype((x))`(双层括号)的结果永远是“引用”,`decltype(x)`的结果与变量`x`的类型相同。 ## 二、数组、vector和string ### 1. 指针与迭代器 指针就是数组的迭代器,可以通过指针来遍历数组,就像下面这样: ```cpp int arr[] = {0, 1, 2, 3}; int *end_arr = arr + 4; // &arr[4] for (int *it = arr; it != end_arr; ++it) std::cout << *it << std::endl; ``` 在C++11标准中,可以使用std::begin()函数获取数组的首元素指针,std::end()函数获取数组秩序最后一个元素的后一位置的指针(也就是尾后指针) ```cpp #include int arr[] = {0, 1, 2, 3}; for (auto it = std::begin(arr); it != std::end(arr); ++it) std::cout << *it << std::endl; ``` 这样的写法不容易出错,但实际编程中能用vector的话,尽量不用使用C风格的数组。 ### 2. 范围for语句处理多维数组 在C++11中,如果使用范围for语句遍历多维数组,除了最内层的循环外,其他循环控制遍历必须使用引用类型: ```cpp int ia[3][4]; for (auto &row : ia) { for (auto col : row) { std::cout << col << std::endl; } } ``` ## 三、运算符 ### 1. 强制类型转换 #### static_cast 一般来说,对于不涉及底层const的类型转换,都可以使用`static_cast` ```cpp int a = static_cast(b); // 也可以使用 int(b) 或者 (int)b void *p = &d; double *dp = static_cast(p); ``` #### const_cast 可以使用const_cast来将常量对象转换为非常量对象 ```cpp const char *pc; char *p = const_cast(pc); ``` const_cast经常用于函数重载的上下文当中,比如有如下函数: ```cpp using std::string; const string &shorterString(const string &s1, const string &s2) { return s1.size() <= s2.size() ? s1 : s2; } ``` 如果我们要定义一个去掉const版本的shorterString函数,但又想调用const版本的shorterString, 就可以使用const_cast: ```cpp using std::string; string &shorterString(string &s1, string &s2) { auto &r = shorterString(const_cast(s1), const_cast(s2)); return const_cast(r); } ``` ## 四、函数 ### 1. 常量引用作为参数 使用非常量应用有很大的局限性。不能把const对象、字面值或者需要类型转换的对象传递给非常量引用参数。 比如,定义下面的`is_empty`函数,使用字面值实参会发生编译错误。 ```cpp bool is_empty(string &s) { return s.empty(); } is_empty("abcd"); //发生编译错误 ``` 应该改成`bool is_empty(const string &s)`,这样接收参数的类型就更多。 ```cpp bool is_empty(const string &s) { return s.empty(); } is_empty("abcd"); //正确 ``` ### 2. C++中的可变形参 #### initializer_list形参 initializer_list是模板类型,用于数量未知但类型相同的函数参数 成员函数有`size(); begin(); end()`,使用方法可以参考C++ primer中这个例子: ```cpp #include void error_msg(std::initializer_list il) { for (auto beg = il.begin(); beg != il.end(); ++beg) std::cout << *beg << " "; std::cout << std::endl; } //调用参数时,必须使用花括号 error_msg({"a", "b", "c"}) ``` #### 省略号形参 使用方法和C语言中的一样,可以参考下面的例子: ```cpp void val_print(int num, ...) //在C++中,这里的逗号可以省略 { //也就是声明为 void val_print(int num ...) va_list(v); //但是在C语言中,这是不允许的 va_start(v, num); for (int i = 0; i < num; ++i) { int n = va_arg(v, int); printf("%d\n", n); } va_end(v); } ``` ## 五、类 ## 六、标准库 ## 七、