学习新特性,带你做C++学习的弄潮儿!!!

简介: 学习新特性,带你做C++学习的弄潮儿!!!

1. 空指针初始化


在C语言中我们使用NULL来初始化空指针:

int* ptr = NULL;

在C++11新特性下引入了一个特殊的字面值nullptr,它可以被转换成任意其他类型的指针:

int* ptr = nullptr;

相比一下,在C++中,NULL被定义为0,这根本就不是一个指针变量,它就是一个简单的变量0罢了:

#ifdef __cplusplus
        #define NULL 0   //C++中是这样定义的
    #else
        #define NULL ((void *)0)
    #endif

类似下面这种情况,如果使用nullptr我们只能初始化指针变量,而NULL可以初始化指针变量和普通变量,这样就会导致二义性的出现,NULL到底是一个指针变量还是一个普通变量呢?所以在C++中我们最好是使用nullptr来初始化指针变量。

int* ptr = NULL;
  int* ptr1 = nullptr;
  int a = NULL;//合法
  int b = nullptr;//非法


2. auto类型


有时候我们苦于准确的记住一些返回值类型,所以不知道声明变量的过程中具体应该声明什么类型?C++11帮助我们解决了这个难题,我们可以使用auto来声明一个变量,它会根据初始化的值来推断变量应该成为什么类型,比如:

int a = 2;
  int* ptr = &a;
  auto c = a;   //c为int类型变量
  auto d = ptr; //d为int*类型的指针变量

使用auto可以动态分配内存吗?of course!

int a = 2;
  int* ptr = &a;
  //c为a所指向类型的一个指针,此处c为int*指针
  auto c = new auto(a);   //并且指针指向的地址是&a

image.png

注意:使用new auto时,只能使用单个变量来初始化,为了让编译器准确判断想要分配的类型!也就是说不能使用auto分配数组!


3. decltype类型


这个类型和auto是有点相似的,我们用auto声明的变量去承接了未知类型的一个函数返回结果,但是有时候我们就只是想知道返回类型是啥,又不想调用这个函数,那我们可以怎么办?decltype应运而生。

int a = 2;
  int* ptr = &a;
  decltype(sizeof(int)) c; 
  //d此时为引用类型,必须初始化
  decltype(*ptr) d;

此时我们声明的c是一个sizeof函数的返回类型,unsigned int类型的未初始化的变量c。此时d这里会报错,因为d是一个引用变量,必须给它一个初始化值!

image.png


4. 范围for循环


范围for循环是一个非常简洁的for循环语句,并且对于程序的安全性也全面提升,使用这种for循环语句,可以有效防止数组越界,因为普通的for循环不会检测数组越界问题,一旦越界,会产生不可预知的错误,所以还是相对来说比较危险的。有关范围for循环的使用举例,之前我有写过博客,点击这里:C++11新标准之范围for语句。我个人还是非常建议去使用新的for循环来代替旧的for循环写法。


5. lambda表达式


lambda表达式就是一个可调用的代码单元,这个调用单元可以传参,类似于函数一样,不过这个函数一般比较精致小巧,我举个简单的使用例子:

int a = 1;
  int b = 2;
  //比较参数的大小
  auto Lambda_Function = [](const int a, const int b) {return a < b; };
  bool IsOk = Lambda_Function(a, b);


6. 类型别名声明


类型别名类似于我们生活中给人起的小名,就是虽然是不同的名字,但是都是叫同一个人!这里所说的类型别名也是这个意思,只要能用到这个类型的地方,都可以用别名去代替!对于类型别名我们应该并不陌生,因为使用typedef就可以搞定一个变量类型别名的声明。

typedef int III;
  III a = 2;//int型的变量
  int b = 3;

这个东西对于初学者来说不是那么友好,因为在声明时候,感官上看来不是很直观,于是C++11有了一种新的定义类型别名的方式。

typedef int III;
  using II = int;
  III a = 2;
  int b = 3;
  II c = 4;

相比于使用typedef,使用using的时候,可以看到惯用的 = 思维,这个也就是告诉我们左边和右边类型一样!!是相等的!更容易记忆和学习的一种声明类型别名的方式。我们可以从结果截图上看到,上面的三个变量都是int类型的变量。

image.png


7. 列表初始化


C++11新标准用花括号来初始化变量,举个例子:

int b{3};
int b = 3;

这两个语句的初始化效果是一样的,列表初始化不仅可以应用于简单的类型变量,也可以使用在标准库类型初始化,拿vector举例:

vector<int> v1{ 1,2,3,4,5 };

使用列表初始化完成对vector数组的初始化时候,也可以在函数调用中作为返回值进行返回。

vector<string> Function_1()
{
  return { "Hello","KookNut","Hello","Boys" };
}
vector<int> Function_2()
{
  return { 1,2,3,4,5,6 };
}

就这些?那动态申请内存时候呢?也可以的!

//动态分配内存  并且进行列表初始化
  vector<int>* v1 = new vector<int>{1,2,3,4,5,6,7};


8. 标准库函数begin、end


使用begin()函数返回指向数组a的首地址的指针,end()指向数组a的最后一个元素的下一个元素处的地址:

int a[5] = { 1,2,3,4,5 };
  int* ptr_begin = begin(a);
  int* ptr_end = end(a);
  while (ptr_begin != ptr_end)
  {
  cout << *ptr_begin << endl;
  ++ptr_begin;
  }

使用标准库的这两个函数,可以保证指针安全的对数组成员解引用,需要注意的一点就是不要对尾后指针进行解引用和递增的操作。


9. constexpr函数


constexpr是用于常量表达式的函数,我们从这个词语的组成上就可以看出来,它以const开头,那如果这个函数中出现的形参和返回值不是字面值类型的时候,是行不通的,因为编译器在编译阶段需要把这个函数给替换掉,所以必须是常量,才可以让编译器顺利的识别并替换!

//错误,string属于非字面值类型
constexpr int Function_3(string a)
{
  return a;
}

我们可以看出它的函数声明定义和普通函数没什么区别,需要注意的是返回值也只能有一条return语句,有且只能有一条!constexpr函数也会被展开,被隐式的指定为内联函数了。

constexpr int Function_3(int a)
{
  return a * 5;
}
void main()
{
  int i = 6;
  constexpr int a1 = Function_3(2);
  constexpr int a2 = Function_3(i);
}


10. 容器中的cbegin、cend


容器中的cbegin、cend是为了得到const_iterator,我们都知道容器中的begin和end可以获得操作容器的迭代器,但是我们有时候也需要const类型的迭代器,那C++11就再一次满足我们,这两个函数和begin、end函数的作用非常的类似,如果我们只需要对容器进行读,而不需要进行写操作的时候,可以使用它来获取元素。

vector<int> d = { 1,2,3,4,5 };
  auto ptr_cbegin = d.cbegin();
  auto ptr_cend = d.cend();

更多有关容器的使用,我之前都写过一些常见容器简单的使用举例:

vector以及使用举例

list以及使用举例

stack以及使用举例

queue以及使用举例

deque以及使用举例

set以及使用举例

map以及使用举例


11. 智能指针


智能指针在我心目中的地位是比较高的,在所有的C++11新特性里面,可以说是我个人最喜欢的部分,因为我比较懒,哈哈哈,所以我也专门写过一篇博客来总结智能指针的问题,大家可以点击这个链接去看一下:智能指针


12. 右值引用


这是面试中我曾经被问到过的问题,也是一开始我学习时候疏忽的知识点之一,我之前只知道传统的引用,也就是我们常说的左值引用。

int a = 1;
  int &b = a;

类似上面的这个代码,b是a的引用,也可以当作是a的一个别名。对于右值引用,需要知道这些:右值引用的书写时是两个&&;它只能绑定到即将销毁的对象;我们可以将右值引用绑定的到一个表达式上;右值是一个短暂性的状态,所以需要右值引用来把它保存下来。有关右值引用,举例如下:

int a = 1;
  int &b = a;
  int &&c = a * 5;//右值引用
  int &&d = b + 2;//右值引用
  int &e = a + 2;//非法,左值引用的对象 必须为左值 而a+2是右值


13. 可变参数模板


多态是C++中非常重要的特性之一,而可变参数模板将多态可谓体现的淋漓尽致,也是C++11中的新特性之一,我们来看看怎么使用:

template<typename T>
int Function(T a)
{
  return a;
}
template<typename T,typename... Arguments>
int Function(T a, Arguments ... Other)
{
  return a + Function(Other...);
}
void main()
{
  int a = 1;
  int b = 2;
  long c = 3;
  int r1 = Function(a);
  r1 = Function(a, b);
  r1 = Function(a, b, c);
}

我们使用可变参数模板定义了一个Function函数,用它来计算int类型的加法,我们不知道将有多少个形参传入,所以定义了一个template<typename T,typename... Arguments>模板,它的意思就是说我可能包含0个或者多个参数,Arguments也包含了多个参数模板包,然后我们为了计算单个参数又定义了这样一个模板template<typename T>,然后我们进行了函数的调用。


14. 正则表达式库


关于正则表达式,我就举一个简答的使用例子:

string  URL = "(https?|ftp|file)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]";
regex r_URL(URL);
for (sregex_iterator it(file.begin(), file.end(), r_URL), end_it;
    it != end_it; it++)
  {
    cout<<it->str()<<endl;
  }

首先定义一个string类型的变量用来存放URL的正则表达式,然后我们使用regex 初始化一个正则表达式对象,我们的file中包含了我们需要搜寻的所有字符内容,然后,用for循环进行遍历,it和end_it是两个声明的迭代器,控制循环条件,我们把所有匹配到的URL项,用cout打印出来!


15. 未完待续…


由于文章篇幅和阅读时间的关系,在这里知识列举了部分常见的新特性,我会在之后更新C++11新特性在类中的应用,大家可以点个关注,后续来看新文章呦!!!


目录
相关文章
|
1月前
|
编译器 程序员 定位技术
C++ 20新特性之Concepts
在C++ 20之前,我们在编写泛型代码时,模板参数的约束往往通过复杂的SFINAE(Substitution Failure Is Not An Error)策略或繁琐的Traits类来实现。这不仅难以阅读,也非常容易出错,导致很多程序员在提及泛型编程时,总是心有余悸、脊背发凉。 在没有引入Concepts之前,我们只能依靠经验和技巧来解读编译器给出的错误信息,很容易陷入“类型迷路”。这就好比在没有GPS导航的年代,我们依靠复杂的地图和模糊的方向指示去一个陌生的地点,很容易迷路。而Concepts的引入,就像是给C++的模板系统安装了一个GPS导航仪
108 59
|
27天前
|
编译器 C语言 C++
配置C++的学习环境
【10月更文挑战第18天】如果想要学习C++语言,那就需要配置必要的环境和相关的软件,才可以帮助自己更好的掌握语法知识。 一、本地环境设置 如果您想要设置 C++ 语言环境,您需要确保电脑上有以下两款可用的软件,文本编辑器和 C++ 编译器。 二、文本编辑器 通过编辑器创建的文件通常称为源文件,源文件包含程序源代码。 C++ 程序的源文件通常使用扩展名 .cpp、.cp 或 .c。 在开始编程之前,请确保您有一个文本编辑器,且有足够的经验来编写一个计算机程序,然后把它保存在一个文件中,编译并执行它。 Visual Studio Code:虽然它是一个通用的文本编辑器,但它有很多插
|
1月前
|
Java 编译器 C++
c++学习,和友元函数
本文讨论了C++中的友元函数、继承规则、运算符重载以及内存管理的重要性,并提到了指针在C++中的强大功能和使用时需要注意的问题。
21 1
|
1月前
|
存储 编译器 C++
【C++】面向对象编程的三大特性:深入解析多态机制(三)
【C++】面向对象编程的三大特性:深入解析多态机制
|
1月前
|
存储 编译器 C++
【C++】面向对象编程的三大特性:深入解析多态机制(二)
【C++】面向对象编程的三大特性:深入解析多态机制
|
1月前
|
编译器 C++
【C++】面向对象编程的三大特性:深入解析多态机制(一)
【C++】面向对象编程的三大特性:深入解析多态机制
|
1月前
|
存储 安全 编译器
【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值(一)
【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值
|
1月前
|
C++
C++ 20新特性之结构化绑定
在C++ 20出现之前,当我们需要访问一个结构体或类的多个成员时,通常使用.或->操作符。对于复杂的数据结构,这种访问方式往往会显得冗长,也难以理解。C++ 20中引入的结构化绑定允许我们直接从一个聚合类型(比如:tuple、struct、class等)中提取出多个成员,并为它们分别命名。这一特性大大简化了对复杂数据结构的访问方式,使代码更加清晰、易读。
34 0
|
2月前
|
编译器 C++ 容器
C++ 11新特性之语法甜点2
C++ 11新特性之语法甜点2
30 1
|
1月前
|
存储 编译器 C++
【C++】面向对象编程的三大特性:深入解析继承机制(三)
【C++】面向对象编程的三大特性:深入解析继承机制