C++ 相对于98而言,11的新特性(C++11)第一弹

前言:

虽然11年相较于现在,已经过去了9年时间,而C++11的新特性,我们也在不知不觉中使用。但作为C/C++的一名新手程序员,还想看了解一下11这个神奇的版本,相较于经典的98,做了哪些改动!本文是我的一些了解。

C++11 

列表初始化

C++11扩大了初始化列表的使用范围,使其可用于所有的内置类型和用户自定义的类型,使用初始化列表时,可有=,也可以没有 

eg:

内置类型: 

 我们习惯于 int   x=10;     而在C++11我们可以有了新的玩法   int x={10};或者 int x {10} ;

自定义类型: 

    


其实,上面的这两种特性属于透明的,我们已经习惯了原来的写法,对于新写法不太感冒 

标准容器

 新支持了容器可以使用列表进行初始化,我们如果知道了事先要存储的内容不必在调用接口一个个插入了,直接一个初始化列表就可以了。在OJ方面用起来,真是爽极了。

vector<int>  v={1,2,3};
list<int>  l={1,2,3};
map<int,int>  m={{1,1},{7,7},{2,2}};

因为这个我们在C中使用的数组的用法类似,尤其是vector;不得不说这个改动很棒!那么这就有些疑问了?vector等容器怎么修改的,以至于支持的列表初始化呢? 

 看一个直观重要的东西    initializer_list  

 这是C++11中新出现的类模板,主要有三个接口迭代器begin(),end(),以及获取其中的元素个数size()。

同时它也是C++11中容器支持列表初始化的关键。

倘若我们仔细观察一下容器的构造函数就会发现C++11后容器的构造函数多一个参数中有  initializer_list   的。

容器支持列表初始化简单的我们可以理解为下面的状况:先将数据存储于initializer_list  中,在赋值给我们的容器。倘若我们自己设计的类也需要支持初始化列表,也可以这么设计

 tempalte<class T>
class  vector{
   vector (initializer_list<T>  il)
         :_capacity(il.size())
         ,_size(0) 
   {
          _arr=new T[_capacity];
          for(auto e:il)
          {
            _arr[_size]=e;
            ++_size;
          }
   }

private:
    T*     _arr;
    size_t _capacity;
    size_t _size;
};

 

 变量类型推导和范围for循环

说到auto其实,我就直接联想到了范围for,这两个的组合真是  百试不爽!

就看最普遍的vector遍历

vector<int>  arr={...............};

//不使用范围for
for(size_t i=0;i<arr.size();++i)
  {
       cout<<arr[i]<<" ";
  }
  cout<<endl;
//范围for
for(const auto&  e:arr )
 {
      cout<<e<<" ";
 }
 cout<<endl;

 可能这体现的不太明显,但是我们的使用auto+范围for,是我们的代码更加简洁。

并且只要支持迭代器就支持范围for,范围for的应用范围对于我们来说也就足够了。

 至于变量推导,我们刚才已经了解了有auto;在C++11中,我们可以使用auto来根据变量初始化或表达式类型来推导变量的实际类型(这意味着使用auto之前,我们必须对后面的变量进行初始化 eg: auto x=1;。对于某些复杂的类型,我们可以用更加简短的auto进行代替,这样虽然简化了我们的代码,但也让我们的代码显得有些晦涩。

在auto的使用前提,就注定auto不能出现在函数的参数列表和模板参数以及返回值的位置!

 类型推导呢,其实是属于运行时类型识别RTTI(run time type identification)即程序运行之后才推导出结果的类型

C++98中,有支持RTTI

typeid 查看类型    //但是不能去定义变量

dynamic_cast  只应用于含有虚函数的继承体系中

对于RTTI,它可以让我们简洁代码,但是不可避免的带来了,程序运行效率的下降问题。

RTTI从这个名字中,我们可以稍稍玩味一下,运行时类型识别;程序只有运行,才能推导出类型;只编译的话,就不会推导出

类型的,那么解决这个问题,就需要一个新的主角:decltype 

decltype 类型说明符生成指定表达式的类型。在此过程中,编译器分析表达式并得到它的类型,却不实际计算表达式的值。

可以用它定义变量

decltype与函数 

 

final和override 

final主要有两个用处

  • 修饰类,使类变为最终类,不能被继承
  • 修饰虚函数,该虚函数不能被重写

override:子类重写虚函数,检验是否完成重写。如果不符合重写的条件,则报错

 新增加容器

 array:即我们c语言中常用的数组

forward_list:单链表

unordered_map和unordered_set :就是我们常说的哈希有关的容器;这两个容器效率特别高

unordered_map和map类似都可以完成key-value场景的搜索

unordered_set和set类似都可以完成key场景的搜索

但是新增的这个两个容器更好些,why?

map和set底层是红黑树,增删查的时间复杂度为O(logN),支持双向迭代器

unordered_map和unordered_set 的底层是哈希表,增删查的时间复杂度可达O(1),支持单向迭代器

如果两者使用效果相同,这两个新容器的诱惑力还是超级大的!

对 默认成员函数的控制

在生活中总有一些不可避免的尴尬,可在代码中            依旧如此!

我们看下面的一个场景,如果你没声明,编译器可以暗自为class创建默认构造函数、拷贝构造函数、赋值重载函数、以及析构函数。唯有当这些函数被调用时,他们才会被编译器创建出来。但是呢?自己也不是太懒,只想写一个拷贝构造函数。但是编译器不通过下面的代码,原因就是编译器更懒,没有生成默认构造函数。之前,在这种情况下就很尴尬!

这就好比你和你心爱的女孩说,这周六有个新电影,你有时间吗?他告诉你“有”;忽然之间断了,于是你傻傻的等她,而她呢?因为你没有显示的告诉“我们去看电影吧”,所以她和闺蜜去吃火锅了!你傻傻的等,她开心的吃!这就很恼火。

但是,毕竟现在到11了,通信条件也好了,不会出现断线的情况,之前的尴尬也就不再有了!我直接说出我的目的,你看着办,还好意思扔下我不管自己去happy嘛

 上面的场面好点酷,解决方案也很酷:一个default解决!

在C++11中,我们可以在默认成员函数定义或者声明的时候加上=default,就可以显示的指示编译器生成该函数的默认版本,而运来的尴尬也就没了。用default修饰的函数我们称之为显示缺省函数

 

显示缺省函数

 删除默认函数

 代码中的尴尬事件看来不止上面一件

倘若我们不想让一个类有拷贝构造函数,这个要怎么办呢?在98的时候,我们只能力度很小的设置一下:将拷贝构造显示的声明出来,为了防止用户在类外面定义,我们还需要将其设置为private,这样就可以帮助我们达成目的!

这好像出现了一幕场景:你和老婆刚结婚,晚上睡觉发现她总打呼噜,你要是直说吧,感觉不太好,而且可能会被“怎么,你嫌弃我了”,“你怎么回事,我这没漂亮,可能会这样嘛”这样,百般难受!所以你选择旁敲测击!稍稍的提醒解决一下这个问题!这个潜藏的问题,终于经过98到11的时候,老夫老妻,你也磨练出来了,你不在容忍,直说。。。。。。。

后面的自己脑补吧!O(∩_∩)O哈哈~,有些讨厌,但不好意思,我们的主角来了! delete

在C++11中,只要该成员默认函数声明上加上=delete;该语法就会只是编译器不生成对应函数的默认版本。这种函数,我们称之为删除函数

 

 我们的第一弹这到这里了,还有一些新特性,会放在接下来的博文中,敬请期待!

各位看官!

故事好不好,全看各位赏!创造不易,动手点个赞哦!

注:如果本篇博客有任何错误和建议,欢迎伙伴们留言,你快说句话啊!

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值