1.1_C++速成
- 1.小程序HelloWorld
- 2.名称空间
- 3.字面量
- 4.变量
- 5.运算符
- 6.枚举类型
- 7.结构体
- 8.条件语句
- 9.条件运算符
- 10.逻辑比较运算符
- 11.三向比较运算符(From C++20)
- 12.函数
- 13.属性
- 14.C风格的数组
- 15.std::array
- 16.std::vector
- 17.std::pair
- 18.std::optional
- 19.结构化绑定
- 20.循环
- 21.初始化列表
- 22.C++中的字符串
- 23.作为面向对象语言的C++
- 24.作用域(scope)解析
- 25.统一初始化
- 26.指针和动态内存
- 27.const的用法
- 28.constexpr关键字
- 29.consteval关键字(From C++20)
- 30.引用
- 31.const_cast()
- 32.异常(exceptions)
- 33.类型别名(type alias)
- 34.类型定义
- 35.类型推断
- 36.标准库
1.小程序HelloWorld
略
2.名称空间
2.1嵌套的名称空间(From C++17)
namespace MyLibraries::NetWorking::FTP{
/* ... */
}
2.2名称空间别名
namespace MyFTP = MyLibraries::NetWorking::FTP;
3.字面量
略
4.变量
统一初始化语法
int initializedInt{7};
常见变量类型
4.1数值极限
使用定义在<limits>
中的类模板std::numeric_limits
cout << "int:\n";
cout << format("Max int value: {}\n",numeric_limits<int>::max());
cout << format("Min int value: {}\n",numeric_limits<int>::min());
cout << format("Lowest int value: {}\n",numeric_limits<int>::lowest());
cout << "double:\n";
cout << format("Max double value: {}\n",numeric_limits<double>::max());
cout << format("Min double value: {}\n",numeric_limits<double>::min());
cout << format("Lowest double value: {}\n",numeric_limits<double>::lowest());
输出
int:
Max int value: 2147483647
Min int value: -2147483648
Lowest int value: -2147483648
double:
Max double value: 1.7976931348623157e+308
Min double value: 2.2250738585072014e-308
Lowest double value: -1.7976931348623157e+308
4.2零初始化
整数 -> 0
浮点数 -> 0.0
指针 -> nullptr
对象 -> 默认构造函数初始化
4.3类型转换
float myFloat{3.14f};
int i1{(int)myFloat};
int i2{int(myFloat)};
int i3{static_cast<int>(myFloat)};
4.4浮点型数字
std::isnan()
——判断一个给定的浮点数是否为非数字
std::isinf()
——判断时候为无穷
std::numeric_limits<double>::infinity
——无穷
5.运算符
略
6.枚举类型
enum class PieceType{
King=1,
Queen,
Rook=10,
Pawn
};
通常枚举值的基本类型是整型,但可以改变:
enum class PieceType: unsigned long
{
King=1,
Queen,
Rook=10,
Pawn
};
对于enum class,枚举值名不会自动超出封闭的作用域,这意味着它们不会与定义在父作用域的其他名字冲突。所以,不同的强类型枚举可以拥有同名的枚举值。
可以使用using enum
或using
命令来避免使用枚举全名。
7.结构体
略
8.条件语句
8.1if/else语句
略
8.2if/else语句的初始化器(From C++17)
if(<initializer>;<conditional_expression>){
<if_body>
}else if(<else_if_expression>){
<else_if_body>
}...
8.3switch语句
switch(menuItem){
case a:
// ...
break;
case b:
// ...
break;
case c:
// ...
[[fallthrough]]//告知编译器故意fallthrough
default:
// ...
}
8.4switch语句的初始化器
略
9.条件运算符
? :
10.逻辑比较运算符
略
11.三向比较运算符(From C++20)
<=>
定义在<compare>
中,返回类枚举(enumeration-like)类型。
当操作数是整数类型,返回强排序:
strong_ordering::less
:第一个操作数小于第二个strong_ordering::greater
:第一个操作数大于第二个strong_ordering::equal
:第一个操作数等于第二个
但操作数是浮点类型,返回偏序(partial ordering):
partial_ordering::less
:第一个操作数小于第二个partial_ordering::greater
:第一个操作数大于第二个partial_ordering::equivalent
:第一个操作数等于第二个partial_ordering::unordered
:至少一个操作数是非数字
还有一种弱排序,用来针对自己的类型实现三向比较:
weak_ordering::less
:第一个操作数小于第二个weak_ordering::greater
:第一个操作数大于第二个weak_ordering::equivalent
:第一个操作数等于第二个
<compare>
还提供比较函数来解释排序结果,用std::is_eq()
、is_neq()
、is_lt()
、is_lteq()
、is_gt()
和is_gteq()
分别判断是否满足==、!=、<、<=、>和>=。
12.函数
12.1函数返回类型的推断
略
12.2当前函数的名称
__func__
12.3函数重载
略
13.属性
13.1[[nodiscard]]
用于一个有返回值的函数,当调用函数却未对返回值作出任何处理时发出警告,可用于类、结构体和枚举。
从C++20开始,可用字符串形式为其提供一个原因:
[[nodiscard("Some explanation")]] int func();
13.2[[maybe_unused]]
用于禁止编译器在未使用某些值时发出警告,可用于类和结构体、非静态数据成员、联合、typedef、类型别名、变量、函数、枚举及枚举值。
13.3[[noreturn]]
函数永远不会将控制权交回调用点。
13.4[[deprecated]]
表示某些内容已弃用。
13.5[[likely]]和[[unlikely]] (From C++20)
帮助优化代码。
14.C风格的数组
略
15.std::array
数组大小固定
std::array<_T, size> name;
16.std::vector
略
17.std::pair
定义在<utility>
中,能将1两个可能不同的类型的值组合起来,可通过first
和second
访问这些值。
pair<double,int> myPair{1.23, 4};
cout << format("{} {}", myPair.first, myPair.second);
18.std::optional
定义在<optional>
中,功能为保留特定类型的值或者不包含任何值,可用于if语句。
optional<int> getData(bool giveIt)
{
if(giveIt){
return 42;
}
return nullopt;// or just simply return {};
}
调用方法:
optional<int> data{getData(true)};
if(data.has_value()){// or if(data)
cout << data.value() << endl;
}
对空的optional使用value()
,会抛出std::bad_optional_access
异常,value_or()
可以用来返回optional的值,如果optional为空,则返回指定的值:
cout << data.value_or(0) << endl;
注意:不能将引用保存在optional中(optional<T&>
是无效的),但是可以保存指针。
19.结构化绑定
结构化绑定允许声明多个变量,这些变量使用数组、结构体、pair 或元组中的元素以初始化。
array values{11, 22, 33};
可声明3个变量x、y和 z,像下面这样使用数组中的3个值进行初始化。注意,必须为结构化
绑定使用 auto 关键字。例如,不能用 int替代auto。
auto [x, y, z]{values};
使用结构化绑定声明的变量数量必须与右侧表达式中的值数量匹配。
如果所有非静态成员都是公有的,也可将结构化绑定用于结构体。
通过使用 auto&
或const auto&
代替 auto
,还可以使用结构化绑定语法创建一组对非const 的引用
或 const 引用。
20.循环
20.1while循环
略
20.2do/while循环
略
20.3for循环
略
20.4基于范围的for循环
基于范围的for循环的初始化器(From C++20)
for (<initializer>;<for-range-declaration>:<for-range-initiallzer>){ <body>}
21.初始化列表
定义在<initializer_list>
中,可利用它编写能接收可变参数的函数。
int makeSum(initializer_list<int> values)
{
int total{0};
for(int value: values){
total += value;
}
return total;
}
初始化列表是类型安全的,列表中所有元素必须为同一类型。
22.C++中的字符串
略
23.作为面向对象语言的C++
略
24.作用域(scope)解析
略
25.统一初始化
使用{...}
语法初始化类型
指派初始化器(From C++20)
C++20 引入了指派初始化器,以使用它们的名称初始化所谓聚合的数据成员。聚合类型是满足以下限制的数组类型的对象或结构或类的对象∶仅 public 数据成员、无用户声明或继承的构造函数、无虚函数和无虚基类、private 或 protected 的基类。指派初始化器以点开头,后跟数据成员的名称。指派初始化的顺序必须与数据成员的声明顺序相同。不允许混合使用指派初始化器和非指派初始化器。未使用指派初始化器初始化的任何数据成员都将使用其默认值进行初始化,这意味着∶
● 拥有类内初始化器的数据成员会得到该值。
● 没有类内初始化器的数据成员会被零初始化。
class Example{
public:
char m_val1;
char m_val2;
int m_val3;
int m_val4{7'500};
};
Example myExample{'a', 'b', 0, 80'000};
Example myExample{
.m_val1 = 'a',
.m_val2 = 'b',
.m_val3 = 0,
.m_val4 = 80'000
};
26.指针和动态内存
略
27.const的用法
27.1const修饰类型
const与指针
int* ip;
ip = new int[10];
ip[4] = 5;
如果要让指针本身不可修改,需要将const置于*
之后:
int* const ip{nullptr};
如果要让指针指向的值不可修改,需要将const置于*
之前:
const int* ip;// or int const* ip;
有另一个易于记忆的规则,可以用于读懂复杂的变量声明∶从右向左读。例如,int* const ip
从右到左读取,得到"ip是指向 int 的const指针。“另外,int const* ip
读为"ip是指向const int 的指针”,而const int*ip
读为"ip是指向int常量的指针"。
使用const保护参数
略
27.2const方法
将类方法标记为const(位于函数声明结尾),防止他们修改类的数据成员。
为了遵循const-correctness原则,建议将不改变对象的任何数据成员的成员函数声明为 const。与非 const 成员函数也被称为赋值函数(mutator)相对,这些成员函数也称为检查器(inspector)。
28.constexpr关键字
定义一个常量表达式,
constexpr int getNum(){return 32;}
int main(){
int myArray[getNum()+1];
}
将函数声明为 constexpr 对函数的功能施加了很多限制,因为编译器必须能够在编译时对函数求值。例如,允许 constexpr 函数调用其他 constexpr 函数,但不允许调用任何非constexpr 函数。这样的函数不允许有任何副作用,也不能引发任何异常。
29.consteval关键字(From C++20)
如果确实希望保证始终在编译时对函数进行求值,则需要使用C++20的 consteval关键字将函数转换为所谓的立即函数(immediate function)
30.引用
中的引用(reference)是另一个变量的别名。对引用的所有修改都会更改其引用的变量的值。可以将引用视为隐式指针,它省去了获取变量地址和解引用指针的麻烦。另外,可以将引用视为原始变量的另一个名称。可以创建独立的引用变量,在类中使用引用数据成员,接受引用作为函数和方法的参数,并从函数和方法返回引用。
30.1引用变量
引用变量必须在创建时被初始化。
修改引用
引用始终指向它初始化时的那个变量,引用一旦创建便无法更改。
const引用
无法通过const引用修改原始值。
int z;
const int& zRef{z};
zRef = 4;//DOES NOT COMPLIE
z = 4;
不能创建对未命名值的引用,例如整数字面量,除非该引用是 const 值。
临时对象也是如此。不能为临时对象创建对非 const 的引用,但是 const 引用是可以的。
int& ref{5}; //DOES NOT COMPLIE
const int& cref{5}; // Works as expected
指针的引用和引用的指针
可以声明指针的引用,但是不能声明引用的引用或者引用的指针。
结构化绑定和引用
略
30.2引用数据成员
类的数据成员可以是引用。如前所述,引用不能不指向其他变量而存在,并日不可以更改引用指向的变量。因此,引用数据成员不能在类构造函数的函数体内部进行初始化,必须在所谓的构造函数初始化器中进行初始化。在语法方面,构造函数初始化器紧跟在构造函数的声明之后,并以冒号开头。
30.3引用作为函数参数
const引用传递
略
值传递和引用传递
略
30.4引用作为返回值
略
31.const_cast()
为变量添加或取消const属性。
标准库提供std::as_const()
方法,基本上as_const(obj)
等价于const_cast<const T&>(obj)
。
32.异常(exceptions)
略
33.类型别名(type alias)
using IntPtr = int*;
34.类型定义
typedef
35.类型推断
35.1关键字auto
- 推断函数的返回类型,如前所述。
- 结构化绑定,如前所述。
- 推断表达式的类型,如前所述。
- 推断非类型模板参数的类型,见第12章。
- 简写函数模板的语法,见第12章。
decltype(auto)
,见第 12章。- 其他函数语法,见第12章。
- 泛型lambda 表达式,见第19章。
auto
会去掉引用和const限定符。
auto&语法
始终要记住,auto 去除了引用和const 限定符,从而会创建副本!如果不需要副本,可使用 auto&
或const auto&
。
auto*语法
在使用指针时,建议使用auto*
语法,因为它可以更清楚地指出涉及指针。
拷贝列表初始化与直接列表初始化
- 拷贝列表初始化:
T obj = {arg1, arg2, ...};
- 直接列表初始化:
T obj{arg1, arg2, ...};
// Copy list initialization
auto a = {11};// initializer_list<int>
auto b = {11, 22};// initializer_list<int>
// Direct list initialization
auto c {11};// int
auto d {11, 22};// initializer_list<int>
请注意,对于拷贝列表初始化,带括号的初始化程序中的所有元素都必须具有相同的类型。
在早期的标准版本(C++11/14)中,拷贝列表和直接列表初始化都将推断出 initializer_list<>
。
35.2关键字decltype
decltype
把表达式作为实参,计算出该表达式的类型。
int x{123};
decltype(x) y{456};
auto 与decltype的区别在于,decltype未去除引用和const 限定符。
36.标准库
略