陕西省建设监理协会网站成绩查询,网站后台服务,clef wordpress,江门做网站公司开网络公司序言 C11 是 C 编程语言的一个重要版本#xff0c;于 2011 年由国际标准化组织 (ISO) 和国际电工委员会 (IEC) 旗下的 C 标准委员会 (ISO/IEC JTC1/SC22/WG21) 正式公布#xff0c;并于同年 9 月出版。其正式名称为 ISO/IEC 14882:2011 - Information technology – Programm…序言 C11 是 C 编程语言的一个重要版本于 2011 年由国际标准化组织 (ISO) 和国际电工委员会 (IEC) 旗下的 C 标准委员会 (ISO/IEC JTC1/SC22/WG21) 正式公布并于同年 9 月出版。其正式名称为 ISO/IEC 14882:2011 - Information technology – Programming languages – C 。C11 是 C98 发布后 13 年来的第一次重大修正它引入了 140 多个新特性和改进使得 C 语言更加现代化、易用和强大。 在这几篇文章中笔者将介绍新特性中比较重要的那些让大家感受到 C11 为现代 C 编程带来的变革和增强。 1. 自动类型推导
1.1 auto 关键字 auto 允许编译器自动推导变量的类型简化了变量声明。就比如auto A 1; 编译器会自动推导出 A 的类型是 int但是这种用法简直是大材小用换一个复杂的场景就要比如我们现在有一个如下的 vector
std::vectorstd::pairstd::string, int arr;现在我们想要获取该 vector的迭代器正常流程应该是这样的吧
std::vectorstd::pairstd::string, int::iterator it arr.begin();但是现在有了 auto 之后我们可以直接表示为auto it arr.begin();。 虽然 auto 极大的便捷了我们的书写但是会大大的降低代码的可读性就比如
auto Func(const int num){std::vectorint arr;for(size_t i 0; i num; i){arr.push_back(i);}return arr;
}int main(){auto ret Func(5);return 0;
}原来我们一眼就能看出的返回值类型现在需要需要到具体的函数查看大体细节。 总结起来就是我们可以使用 auto 来便利我们的书写但是我们不能依赖于他
1.2 decltype 关键词 decltype 用于在编译时查询表达式的类型。decltype 可以避免显式地写出复杂的类型名称特别是在模板编程、自动类型推导以及需要精确类型信息的场景中就比如
int main() { int x 42; double y 3.14; // 使用 decltype 推导 x 的类型 decltype(x) z 100; // z 的类型是 int // 使用 decltype 推导表达式的类型 decltype(x y) sum x y; // sum 的类型是 double return 0
}2. 范围for循环 范围 for 循环 是 C11 引入的一种新的循环语法它简化了对容器如 std::vector、std::list 等或数组遍历的代码编写。范围for循环 能够自动处理容器的迭代过程使得遍历容器元素变得更加直观和简洁。格式如下
// Container 是具体的容器结构
for(auto elem : Container){// 对容器中元素的具体操作
}在这里提一嘴这个只能支持本身就支持可以遍历的容器StackQueue等 容器本身不支持遍历的容器是不支持的哈。 就比如我想要遍历我的 vector 中的元素就可以表示为
void test_1() {vectorint arr { 1, 2, 3 ,4 };for (auto e : arr) {cout e ;}cout endl;
}2.1 遍历的元素为深拷贝 如果我想要利用 范围 for 循环 将我的所有 vector 元素加一那是这样的吗
void test_2() {vectorint arr { 1, 2, 3 ,4 };for (auto e : arr) {e;}for (auto e : arr) {cout e ;}cout endl;
}你可以发现元素并未发生变化这是因为 e是vector中每一个元素的深拷贝这个要牢记哈。那怎么解决呢很简单 for (auto e : arr) {e;}我们只需要加上引用就好啦。当我们遍历时也通常加上引用符号这是因为如果不引用容器中的元素都是需要动态申请空间的话那遍历时拷贝的代价就太大了。
2.2 本质是使用了迭代器 你可以简单的认为 范围 for 循环 可以转化为如下形式
void test_3() {vectorint arr { 1, 2, 3 ,4 };auto it arr.begin();while (it ! arr.end()) {cout *it ;it;}
}所以说如果你想要你的自定义容器也支持 范围 for 循环那就必须要如下前提
你的容器实现了迭代器你的迭代器支持! 3. 统一的列表初始化
3.1 {} 用法 在 C98 版本中我们可以使用 {} 对数组或者是结构体进行初始化
class Test {
public:Test(int A, int B) {_A A;_B B;}
private:int _A;int _B;
};void test_4() {int arr[] { 1, 2, 3, 4 };Test t1 { 1, 2 };
}在 C11 中{} 可以初始化的对象包括基本类型、复合类型如结构体、类以及 STL 容器等。这种语法提供了一种一致且清晰的初始化方式避免了之前不同初始化方式可能带来的混淆和错误
void test_5() {// 对内置类型初始化int A { 1 };int B{ 2 }; // 甚至可以去除 // 对容器初始化vectorint arr {1, 2, 3, 4};// 对自定义类型初始化Test t2{ 1, 2 };// 对 new 表达式初始化int* ptr new int[2] {1, 2};delete[] ptr;
}3.2 initializer_list — {} 背后的男人 {} 在背后是如何对容器进行初始化的呢靠的是 initializer_list。他具体是
类型std::initializer_listT 是一个模板类其中 T 是列表中元素的类型。用途主要用于构造函数和函数调用的初始化列表中允许以花括号 {} 包围的列表形式传递多个值。特性initializer_list 是轻量级的它不拥有它所包含的元素它仅仅是对现有数据的引用。因此使用 initializer_list 时需要注意生命周期问题确保 initializer_list 引用的数据在 initializer_list 被使用时仍然有效。 4. 关键字 overridefinal
override override 修饰一个成员函数代表你想要重写该函数如果没有达到重写的条件就会报错。就比如
final 当 final 修饰一个成员函数代表该函数不可以被重写。就比如 当 final 修饰一个类代表该类不可以被继承。就比如 5. 关键字 nullptr
在 C 语言中, NULL 的定义是
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)#endif
#endif由于 C 中 NULL 被定义成字面量 0这样就可能回带来一些问题因为 0 既能指针常量又能表示整形常量。所以出于清晰和安全的角度考虑C11 中新增了 nullptr仅用于表示空指针。 6 总结
还有些重要的新特性将在接下来的时间慢慢更新特别重要的特性会作为大章节详细讲解。