c++11的一些新特性

c++11

  • 1. {}初始化
  • 2. 范围for循环
  • 3. final与override
  • 4. 右值引用
    • 4.1 左值引用和右值引用
    • 4.2 左值引用与右值引用比较
  • 5. lambda表达式
  • 6. 声明
    • 6.1 auto
    • 6.2 decltype
    • 6.3 nullptr
  • 7. 可变参数模版

1. {}初始化

在C++中,使用花括号初始化的方式被称为列表初始化。列表初始化可以用于数组、结构体、类等类型的初始化。在C++11之前,列表初始化仅能用于数组和POD类型的初始化。C++11新标准将列表初始化应用于所有对象的初始化。以下是一些使用列表初始化的例子:

struct Point 
{int _x;int _y;
}; class foo 
{
public:foo(int i, double d) :_i(i), _d(d) {} // 构造函数
private:int _i;double _d;
};
int main()
{int arr[]{ 1, 2, 3, 4, 5 }; // 数组Point p{ 1,2 }; // 结构体foo f{ 1, 3.14 }; // 类return 0;
}

以上代码中,arr 是一个整型数组,使用列表初始化方式进行了初始化;p 是一个结构体,使用列表初始化方式对其成员变量进行了初始化;f 是一个类对象,使用列表初始化方式对其成员变量进行了初始化。

2. 范围for循环

在C++中,范围for循环是一种用于遍历数组、容器、初始化列表等类型的语法结构。它的语法格式如下:

for (declaration : expression)
{// 循环体
}

其中,declaration 表示遍历声明,在遍历过程中,当前被遍历到的元素会被存储到声明的变量中。expression 是要遍历的对象,它可以是表达式、容器、数组、初始化列表等。

以下是一个使用范围for循环的例子:

#include <iostream>
#include <vector>int main()
{std::vector<int> v = {1, 2, 3, 4, 5};for (auto value : v){std::cout << value << " ";}std::cout << std::endl;return 0;
}

以上代码中,v 是一个整型向量,使用范围for循环方式进行了遍历。
需要注意的是,在使用范围for循环遍历容器时,循环会自动以容器为范围展开,并且循环中也屏蔽掉了迭代器的遍历细节,直接抽取容器中的元素进行运算,使用这种方式进行循环遍历会让编码和维护变得更加简便。

其中还有一个点需要注意,上述value相当于一个形参,也就是说value改变,不影响数组v的改变,那么怎么在遍历的时候又能修改数组v?其实可以使用引用访问元素,如下:

#include <iostream>
#include <vector>int main()
{std::vector<int> v = { 1, 2, 3, 4, 5 };cout << "没有使用引用访问:";for (auto value : v){value *= 2;}for (auto value : v){std::cout << value << " ";}std::cout << std::endl;cout << "使用引用访问:";for (auto &value : v){value *= 2;}for (auto value : v){std::cout << value << " ";}std::cout << std::endl;return 0;
}

在这里插入图片描述
在C++中,使用范围for循环时,如果使用引用访问元素,可以避免对元素进行拷贝,从而提高程序的效率。当使用值访问元素时,会对元素进行一次拷贝,而使用引用访问元素时,则不会进行拷贝。因此,在不改变元素的情况下,使用引用访问元素可以减少一次拷贝,提高程序的效率。

3. final与override

在C++11中,override 和 final 是两个新的关键字,用于增强代码的安全性和可读性。

override 用于在派生类中重写基类的虚函数时,显式地告诉编译器此函数是重写基类的虚函数。如果重写时函数名、参数列表和返回类型都和基类的虚函数一致,但是没有加上 override 关键字,那么编译器无法判断是否是故意的重写,容易导致程序出错。加上 override 关键字后,编译器会在编译时检查是否真的重写了基类的虚函数,如果没有则会报错,从而避免了这种错误。

final 用于修饰类、函数或者变量,表示它们是终态的,不能被派生类、重写或者修改。使用 final 关键字可以防止子类再覆写父类的虚函数。如果一个虚函数被声明为 final,则派生类不能再重写它。

4. 右值引用

4.1 左值引用和右值引用

什么是左值?什么是左值引用?
左值是一个表示数据的表达式(如变量名或解引用的指针),我们可以获取它的地址对它赋值,左值可以出现赋值符号的左边,右值不能出现在赋值符号左边。定义时const修饰符后的左值,不能给他赋值,但是可以取它的地址。左值引用就是给左值的引用,给左值取别名。

int main()
{// 以下的p、b、c、*p都是左值int* p = new int(0);int b = 1;const int c = 2;// 以下几个是对上面左值的左值引用int*& rp = p;int& rb = b;const int& rc = c;int& pvalue = *p;return 0;
}

什么是右值?什么是右值引用?
右值也是一个表示数据的表达式,如:字面常量、表达式返回值,函数返回值(这个不能是左值引用返回)等等,右值可以出现在赋值符号的右边,但是不能出现出现在赋值符号的左边,右值不能取地址。右值引用就是对右值的引用,给右值取别名。

int main()
{double x = 1.1, y = 2.2;// 以下几个都是常见的右值10;x + y;fmin(x, y);// 以下几个都是对右值的右值引用int&& rr1 = 10;double&& rr2 = x + y;double&& rr3 = fmin(x, y);// 这里编译会报错:error C2106: “=”: 左操作数必须为左值//10 = 1;//x + y = 1;//fmin(x, y) = 1;return 0;
}

需要注意的是右值是不能取地址的,但是给右值取别名后,会导致右值被存储到特定位置,且可以取到该位置的地址,也就是说例如:不能取字面量10的地址,但是rr1引用后,可以对rr1取地址,也可以修改rr1。如果不想rr1被修改,可以用const int&& rr1 去引用。

4.2 左值引用与右值引用比较

  1. 左值引用是用符号 & 声明的,它只能绑定到左值,即可以取地址、有名字、非临时的对象。左值引用可以用来修改或读取所绑定的对象的值。
  2. 右值引用是用符号 && 声明的,它只能绑定到右值,即不能取地址、没有名字、临时的对象。右值引用可以用来延长所绑定的对象的生命周期,或者实现移动语义,即将对象的资源从一个所有者转移到另一个所有者,而不需要进行拷贝。
  3. 一个例外是,const左值引用可以绑定到右值,这样可以实现对右值的只读访问,而不改变其生命周期。
  4. 另一个例外是,在函数重载时,如果有一个参数既可以接受左值引用,又可以接受右值引用,那么编译器会优先选择左值引用。这是为了避免对左值进行不必要的移动操作。

左值引用和右值引用的优缺点如下:

  1. 左值引用的优点是可以对所引用的对象进行修改或读取,而不需要拷贝或移动。左值引用的缺点是不能绑定到右值,如果需要绑定到右值,必须使用常量左值引用,但这样就不能修改所引用的对象了。
  2. 右值引用的优点是可以实现移动语义,减少拷贝或赋值操作的开销,提高程序的效率。右值引用的缺点是不能修改所引用的对象,而且会改变所引用对象的状态,使其失去资源的所有权。

5. lambda表达式

在C++98中,如果想要对一个数据集合中的元素进行排序,可以使用std::sort方法,但是如果排序的是自定义类型元素,每次为了实现一个algorithm算法,都要重新去写一个类,如果每次比较的逻辑不一样,还要去实现多个类,特别是相同类的命名,这些都给编程者带来了极大的不便。因此,在C++11语法中出现了Lambda表达式。

在C++11中,Lambda表达式是一种用于定义匿名函数的语法结构。Lambda表达式可以用于任何需要函数对象的地方,例如函数参数、返回值、STL算法等。Lambda表达式的语法格式如下:

[capture-list] (parameters) mutable -> return-type { statement };

lambda表达式各部分说明:

  1. [capture-list] : 捕捉列表,该列表总是出现在lambda函数的开始位置,编译器根据[]来判断接下来的代码是否为lambda函数,捕捉列表能够捕捉上下文中的变量供lambda函数使用。
  2. (parameters):参数列表。与普通函数的参数列表一致,如果不需要参数传递,则可以连同()一起省略。
  3. mutable:默认情况下,lambda函数总是一个const函数,mutable可以取消其常量性。使用该修饰符时,参数列表不可省略(即使参数为空)。
  4. ->returntype:返回值类型。用追踪返回类型形式声明函数的返回值类型,没有返回值时此部分可省略。返回值类型明确情况下,也可省略,由编译器对返回类型进行推导。
  5. {statement}:函数体。在该函数体内,除了可以使用其参数外,还可以使用所有捕获到的变量。

注意:
在lambda函数定义中,参数列表和返回值类型都是可选部分,而捕捉列表和函数体可以为空。因此C++11中最简单的lambda函数为:[]{}; 该lambda函数不能做任何事情。

int main()
{// 最简单的lambda表达式, 该lambda表达式没有任何意义[] {};// 省略参数列表和返回值类型,返回值类型由编译器推导为intint a = 3, b = 4;[=] {return a + 3; };// 省略了返回值类型,无返回值类型auto fun1 = [&](int c) {b = a + c; };fun1(10);cout << a << " " << b << endl;// 各部分都很完善的lambda函数auto fun2 = [=, &b](int c)->int {return b += a + c; };cout << fun2(10) << endl;// 复制捕捉xint x = 10;auto add_x = [x](int a) mutable { x *= 2; return a + x; };cout << add_x(10) << endl;return 0;
}int main()
{int x = 10, y = 20;auto func1 = [](int x = 1,int y = 2) //当捕捉列表和参数列表都有x,y,优先用参数列表中的值。{cout << x + y << endl; // 3};func1();return 0;
}int main()
{int x = 0, y = 1;int m = 0, n = 1;auto swap1 = [](int& rx, int& ry){int tmp = rx;rx = ry;ry = tmp;};swap1(x, y);cout << x << " "<< y << endl;// 引用捕捉auto swap2 = [&x, &y](){int tmp = x;x = y;y = tmp;};swap2();cout << x << " " << y << endl;// 混合捕捉auto func1 = [&x, y](){//...};// 全部引用捕捉auto func2 = [&](){//...};// 全部传值捕捉auto func3 = [=](){//...};// 全部引用捕捉,x传值捕捉auto func4 = [&, x](){//...};return 0;
}

lambda表达式的优点是可以使代码更加简洁紧凑,并且可以避免定义不必要的函数对象。Lambda表达式的缺点是可能会降低代码的可读性和可维护性。

6. 声明

6.1 auto

auto是C++11引入的一个关键字,用于在声明变量时自动推导变量的类型。auto的使用可以让编译器在编译期间自动推算出变量的类型,这样就可以更加方便的编写代码了。auto还可以用于定义函数返回值类型,但此时auto仍然使用的是模板实参推断的机制,因此返回类型为auto的函数如果返回一个初始化列表,则会出错。

6.2 decltype

在C++11中,decltype 是一种用于推导表达式类型的关键字。decltype 可以用于推导变量、函数返回值、表达式等的类型。decltype 的语法格式如下:

decltype(expression)

其中,expression 是要推导类型的表达式。

以下是一个使用 decltype 的例子:

#include <iostream>int main()
{int i = 42;decltype(i) j = i + 1;std::cout << "i = " << i << ", j = " << j << std::endl;return 0;
}

以上代码中,使用了 decltype 推导了变量 j 的类型。

decltype 的优点是可以在编译期间推导出表达式的类型,从而提高程序的效率。decltype 的缺点是可能会降低代码的可读性和可维护性。

6.3 nullptr

C++11中,nullptr是一个用于表示空指针的关键字,它可以替代C++03中的0或NULL。nullptr的类型是std::nullptr_t,它可以隐式转换为任意类型的指针或成员指针,但不能转换为整数类型或布尔类型。nullptr的优点是可以避免一些类型推导的歧义,例如在函数重载或模板参数推导时。nullptr的缺点是可能会与一些旧代码不兼容,例如使用NULL作为整数常量的代码。

在C++中NULL被定义成字面量0,这样就可能回带来一些问题,因为0既能指针常量,又能表示整形常量。所以出于清晰和安全的角度考虑,C++11中新增了nullptr,用于表示空指针。

#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif

7. 可变参数模版

在C++11中,可变参数模板是一种用于定义可变数量参数的模板。它允许模板函数或类接受任意数量的参数,包括类型、非类型和模板参数。可变参数模板的语法格式如下:

template<typename... Args>
void foo(Args... args)
{// 函数体
}

其中,Args 是一个模板参数包,可以接受任意数量的模板参数。在函数体中,可以使用 args… 来展开参数包,以便对每个参数进行操作。

可变参数模版中有一点需要注意,在使用sizeof()求可变参数的个数时,应该这样书写:sizeof…(args),//错误格式sizeof(args…);如下所示:

template <class ...Args>
void ShowList(Args... args)
{cout << sizeof...(args) << endl; //求可变参数的个数
}
int main()
{ShowList(1);ShowList(1, 2.2);ShowList(1, 2.2, "hello");return 0;
}

在这里插入图片描述

如何解析可变参数包?这里使用递归来解决。以下是一个使用可变参数模板的例子:

void ShowList() //函数重载,当参数个数为0时,没有该函数,就会找不到匹配的函数
{cout << endl;
}
template <class T, class ...Args>
void ShowList(const T& val, Args... args) //每次从参数包中解析一个
{cout << val << " ";ShowList(args...);
}
int main()
{ShowList(1);ShowList(1, 2.2);ShowList(1, 2.2, "three");return 0;
}

在这里插入图片描述

可变参数模板的优点是可以使代码更加灵活和通用,可以接受任意数量和类型的参数。可变参数模板的缺点是可能会降低代码的可读性和可维护性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/110182.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++:初始化列表,static成员,友元,内部类

个人主页 &#xff1a; 个人主页 个人专栏 &#xff1a; 《数据结构》 《C语言》《C》 文章目录 前言一、初始化列表二、static成员三、友元四、内部类总结 前言 本篇博客作为C&#xff1a;初始化列表&#xff0c;static成员&#xff0c;友元&#xff0c;内部类的知识总结。 一…

java面向对象(二)

文章目录 一、方法1.例子2.例子3.例子 二、使用步骤1.举例说明类跟对象&#xff08;高大上&#xff09;2.理解“万事万物皆对象”3.变量在内存中的位置体现4.引用类型的变量5.匿名对象的使用 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、方法 描…

Mysql开启binlog

本案例基于mysql5.7.16实验 1、在linux中进入mysql查询binlog是否打开&#xff0c;执行命令如下&#xff1a; mysql -u root -p 2、查询binlog是否开启命令如下&#xff0c;如果log_bin为OFF则证明mysql的binlog没有打开 show variables like %log_bin%; 3、退出mysql终端&…

基于 Alpine 环境构建 aspnetcore6-runtime 的 Docker 镜像

关于 Alpine Linux 此处就不再过多讲述&#xff0c;请自行查看相关文档。 .NET 支持的体系结构 下表列出了当前支持的 .NET 体系结构以及支持它们的 Alpine 版本。 这些版本在 .NET 到达支持终止日期或 Alpine 的体系结构受支持之前仍受支持。请注意&#xff0c;Microsoft 仅正…

unity 使用声网(Agora)实现语音通话

第一步、先申请一个声网账号 [Agora官网链接]&#xff08;https://console.shengwang.cn/&#xff09; 第二步在官网创建项目 &#xff0c;选择无证书模式&#xff0c;证书模式需要tokenh和Appld才能通话 第三步 官网下载SDK 然后导入到unity&#xff0c;也可以直接在unity商店…

Spring-Cloud GateWay+Vue 跨域方案汇总

文章目录 一、简介背景和概述 二、前端跨域解决方案Axios跨域CORS跨域 三、后端跨域解决方案反向代理服务器 四、Spring Cloud中的跨域解决方案Gateway网关的跨域配置 五、基于Vue和Spring Cloud的跨域整合实践**这两种配置只需配置一种即可生效&#xff08;前端or后端&#xf…

Zookeeper 启动失败【Cannot open channel to 3 at election address...】

文章目录 完整报错信息解决方法1.检查文件夹权限2.未监听所有IP3.IP映射名称与 ID 不对应 完整报错信息 Cannot open channel to 3 at election address hadoop121/192.168.10.121:3888 java.net.ConnectException 解决方法 1.检查文件夹权限 检查当前用户是否拥有 Zookeep…

【SpringMVC】JSR 303与interceptor拦截器快速入门

目录 一、JSR303 1、什么是JSR 303&#xff1f; 2、为什么要使用JSR 303&#xff1f; 3、JSR 303常用注解 3.1、常用的JSR 303注解 3.2、Validated与Valid区别 3.2.1、Validated 3.2.2、Valid 3.2.3、区别 4、使用案例 4.1、导入依赖 4.2、配置校验规则 4.3、编写…

去耦电路设计应用指南(二)电容的噪声抑制

&#xff08;二&#xff09;电容的噪声抑制 1. 电容的频率特性1.1 MLCC1.2 LW逆转电容1.3 三端子电容 2. 电容layout3. 电容安装位置与干扰路径4. 多个电容并联及反谐振 由于电容自身的频率特性以及器件在 PCB 上面的 layout&#xff0c;在噪声抑制的效果也会受到影 响&#xf…

智慧公厕建设的好处

在现代社会的迅猛发展中&#xff0c;智慧公厕的建设越来越受到重视。通过智慧高效管理和保持公厕整洁&#xff0c;城市形象得以提升&#xff0c;为居民提供更加便捷舒适的生活服务。本文将以智慧公厕源头厂家广州中期科技有限公司&#xff0c;大量精品项目案例&#xff0c;实景…

关系型三大范式与BCNF有什么用呢

学的时候就知道是一堆公式。 实际中在设计表的时候可能会用到。 前提是关系型数据库&#xff0c;比如mysql。 &#xff08;实际中oracle比mysql更好用。但是他收费啊。&#xff09; 第一范式&#xff1a;每个属性都是原子的&#xff08;需要做到每个属性都是不可分割的。&…

LeetCode 2596. 检查骑士巡视方案

【LetMeFly】2596.检查骑士巡视方案 力扣题目链接&#xff1a;https://leetcode.cn/problems/check-knight-tour-configuration/ 骑士在一张 n x n 的棋盘上巡视。在有效的巡视方案中&#xff0c;骑士会从棋盘的 左上角 出发&#xff0c;并且访问棋盘上的每个格子 恰好一次 。…