# 现代 C++
## [auto](https://zh.cppreference.com/w/cpp/language/auto)
这并不是动态类型,最终的类型取决于编译期间右值的类型。换句话说就是让编译器在编译期根据右值推导出这个变量的类型:
```cpp
auto x = 1; // int
auto y = 'c'; // char
```
当你觉得一个类型没必要明确写出来或者无论是写还是看都显得太长时,可以试试 auto 关键字。
## [constexpr](https://zh.cppreference.com/w/cpp/language/constexpr)
constexpr 的语义是“常量表达式”,代表在编译期可求值的表达式,可用于修饰变量、函数、构造函数等。它可以用于声明变量、函数、构造函数等,使得它们可以在编译期计算出结果,提高程序的执行效率。constexpr 和 const 的主要区别是,const 变量的初始化可以推迟到运行时,而 constexpr 变量必须在编译时进行初始化。constexpr 函数或构造函数必须只接受并返回字面类型,并且函数体不能包含复杂的语句,如 goto、try 等。C++14 中放宽了一些限制,允许 constexpr 函数包含 if、switch、循环等语句,并且可以修改局部变量。
constexpr 包含了 const 的含义,也就是说 constexpr 变量或函数都是 const 的,但反过来不一定成立。
下面是 constexpr 的使用示例:
```cpp
#include <iostream>
constexpr int factorial(int n)
{
return n <= 1 ? 1 : (n * factorial(n - 1));
}
int main()
{
// 5的阶乘
constexpr int num = factorial(5);
std::cout << num << std::endl;
system("pause");
}
```
## using 替代 typedef
在 C++11 中规定了一种新的方法,使用别名声明(alias declaration)来定义类型的别名,即使用 `using`。
`typedef` 作为声明语句中的基本数据类型的一部分出现。含有 `typedef` 的声明语句定义的不再是变量而是类型别名。和以前的声明语句一样,这里的声明符也可以包含类型修饰,从而也能由基本数据类型构造出复合类型来。
C++11 中用关键字 `using` 作为别名声明的开始,其后紧跟别名和等号,其作用是把等号左侧的名字规定成等号右侧类型的别名。如:
```cpp
using i = int;
```
类型别名和类型的名字等价,只要是类型的名字能出现的地方,就能使用类型别名。
使用 `typedef` 定义的别名和使用 `using` 定义的别名在语义上是等效的。唯一的区别是 `typedef` 在模板中有一定的局限性,而 `using` 没有。
尽管 `typedef` 具有更长的历史记录并且在现有代码中可能更常见,但 `using` 更通用。
无论是 `typedef` 还是 `using`,它们都不会创建新的数据类型,它们仅仅创建现有类型的同义词(synonyms)。不能用于更改现有类型名称的含义。
`typedef` 和 `using` 标识符可以声明数组和函数类型,指针和引用,类类型等等。但不能与任何其它标识符组合使用。仅在它们可见的范围内有效:不同的函数或类声明可以定义具有不同含义的相同名字的类型。
`typedef` 的用法包括:
- 定义一种类型的别名
- 用于 `struct` 声明
- 用来定义与平台无关的类型
- 用于回调函数
- 为复杂的声明定义一个新的简单的别名
**如果某个类型别名指代的是复合类型或常量,那么把它用到声明语句里就会产生意想不到的后果。**
`typedef` 是定义了一种类型的新别名,但它不同于宏,并不是简单的字符串替换。当 `const` 和 `typedef` 一起出现时,就会出现一些玄学问题。举个例子:
```cpp
// 为 int* 起一个别名 p_int
typedef int* p_int;
// 这种情况下 p 的类型是 int* const
// 而不是我们期望的 const int*
const p_int p;
```
在使用 `typedef` 时,不能在声明中有多个存储类关键字,就像 auto、extern、mutable、static、register 一样,是一个存储类关键字。即 `typedef` 中不能出现这些关键字。
## 大括号初始化
C++11 的对象初始化的语法选择是不堪和混乱的。总的来说,初始值可以借助 `{}`、`=`、`()`:
```cpp
int main()
{
int a = 0;
int b(0);
int c{0};
return 0;
}
```
使用等号初始化经常会让我错误的认为会进行一次赋值,但并非如此。对于内置类型,例如 int,初始化和赋值操作的差别是模糊的。但是对于用户定义的类或是 STL 编程,区分初始化和赋值操作是很重要的,因为这会导致不同的函数调用:
```cpp
#include <string>
int main() {
std::string str1; // 默认构造
std::string str4 = str3; // 拷贝构造
str1 = str2; // 运算符重载
return 0;
}
```
因为初始化的语法很混乱,而且有些情况无法实现,所以 C++11 提出了统一初始化语法:一种至少在概念上可以用于表达任何值的语法。它的实现基于大括号,所以我称之为大括号初始化。
使用大括号可以更容易的初始化容器列表初始化:
```cpp
#include <vector>
int main()
{
std::vector<int> vec {1, 3, 5};
return 0;
}
```
大括号也可以**用于类内成员的默认初始值**,在 C++11 中 `=` 也可以实现,但是 `()` 则不可以:
```cpp
class Person {
private:
int a {0}; // x的默认初始值为0
int b = 0; // 同上
int c(0); // 报错
}
```
另一方面,不可拷贝对象(如 `std::atomic`)可以用大括号和圆括号初始化,但不能用等号:
```cpp
std::atomic<int> ai1 {0}; // 可以
std::atomic<int> ai2 (0); // 可以
std::atomic<int> ai3 = 0; // 报错
```
当使用大括号初始化用于内置类型的变量时,可以帮我们避免窄化转换:
```cpp
int main()
{
double d = 3.14;
int a {d}; // 报错(窄化转换不被允许)
int b (d); // 编译器认为没毛病
}
```
大括号初始化的另一个非常值得注意的特性是它解决了 C++ 中最让人头痛的歧义。当开发者想要一个默认构造的对象时,会不经意地声明一个函数而不是构造对象。正常情况下我们去调用一个有参构造是这样写的:
```cpp
Person p1('student1'); // 调用 Person 的带参构造
```
但是,当你尝试用类似的语法调用无参构造时,你就会发现有那么一点不对劲:
```cpp
Person p2(); // tnnd,不小心声明了一个的函数
Person p3; // 正确:p3 是个默认初始化的对象
```
而使用大括号就不会出现这个问题:
```cpp
Person p2{}; // 这就没有歧义了
```
我们说了很多大括号初始化的内容,这种语法可以用于多种场景,还可以避免隐式范围窄化转换,又免疫 C++ 的最让人头痛的歧义问题。一举多得,那么为什么不用大括号初始化语法替代其他的语法呢?
大括号初始化的缺点是它有时会显现令人惊讶的的行为。这些行为的出现是因为与 `std::initializer_list` 混淆了。在构造函数中,只要形参不带有 `std::initializer_list`,圆括号和大括号行为一致:
```cpp
class Test {
public:
Test(int i, bool b);
Test(int i, double d);
};
Test t1(10, true); // 调用第一个构造函数
Test t2{10, true}; // 调用第一个构造函数
Test t3(10, 5.0); // 调用第二个构造函数
Test t4{10, 5.0}; // 调用第二个构造函数
```
但是,如果构造函数的形参带有 `std::initializer_list`,调用构造函数时大括号初始化语法会强制使用带 `std::initializer_list` 参数的重载构造函数:
```cpp
class Test {
public:
Test(int i, bool b);
Test(int i, double d);
Test(std::initializer_list<long double> il);
};
Test t1(10, true); // 使用圆括号,调用第一个构造函数
Test t2{10, true}; // 使用大括号,强制调用第三个构造函数,10 和 true 被转换为 long double
Test t3(10, 5.0); // 使用圆括号,调用第二个构造函数
Test t4{1
没有合适的资源?快使用搜索试试~ 我知道了~
大数据平台搭建文档.zip
共116个文件
png:82个
md:16个
js:9个
需积分: 1 0 下载量 14 浏览量
2024-03-06
23:01:37
上传
评论
收藏 57.4MB ZIP 举报
温馨提示
大数据平台搭建文档.zip
资源推荐
资源详情
资源评论
收起资源包目录
大数据平台搭建文档.zip (116个子文件)
vue.css 16KB
vue.min.css 13KB
.gitignore 5B
index.html 3KB
docsify.min.js 157KB
zoom-image.min.js 9KB
search.min.js 8KB
prism-bash.min.js 6KB
prism-sql.min.js 3KB
sw.js 3KB
prism-cpp.min.js 3KB
prism-scala.min.js 1KB
index.js 1022B
settings.json 154B
.markdownlint.json 62B
LICENSE 1KB
README.md 40KB
README.md 38KB
README.md 33KB
README.md 17KB
README.md 17KB
README.md 8KB
README.md 8KB
README.md 7KB
README.md 7KB
README.md 6KB
README.md 5KB
README.md 3KB
README.md 3KB
README.md 841B
_navbar.md 723B
_coverpage.md 149B
nginx_conf 581B
8_1.png 1.64MB
11_1.png 1.42MB
5_1.png 1.4MB
8_2.png 1.38MB
faq_1_3.png 1.33MB
6_1.png 1.17MB
7_1.png 1.14MB
2_2.png 1.13MB
8_1.png 1.13MB
3_1.png 1.12MB
6_2.png 1.11MB
8_2.png 1.11MB
4_1.png 1.03MB
faq_1_2.png 1.02MB
7_2.png 1.02MB
8_3.png 1.01MB
5_1.png 997KB
4_2.png 996KB
6_1.png 979KB
9_6.png 973KB
2_1.png 970KB
5_2.png 968KB
9_3.png 938KB
9_5.png 927KB
9_4.png 925KB
3_1.png 925KB
7_4.png 920KB
4_1.png 905KB
7_5.png 898KB
6_1.png 891KB
7_1.png 876KB
9_2.png 868KB
7_2.png 862KB
7_3.png 844KB
faq_1_1.png 819KB
4_1.png 813KB
7_1.png 809KB
9_3.png 803KB
6_2.png 797KB
9_2.png 780KB
3_1.png 776KB
7_2.png 767KB
9_1.png 762KB
12_1.png 762KB
7_3.png 761KB
9_3.png 761KB
9_1.png 747KB
8_1.png 744KB
11_2.png 741KB
8_1.png 735KB
6_1.png 715KB
8_2.png 675KB
8_3.png 671KB
7_1.png 669KB
9_2.png 658KB
5_1.png 551KB
7_2.png 522KB
6_1.png 515KB
4-1_1.png 500KB
page_merge.png 486KB
9_1.png 480KB
9_2.png 469KB
overview_3.png 380KB
index_struct.png 369KB
enable_faderated_1.png 303KB
Hash.png 300KB
MySql_B+Tree.png 260KB
共 116 条
- 1
- 2
资源评论
日刷百题
- 粉丝: 5604
- 资源: 951
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功