[学习][记录] c++语言:从放弃到入门 <一> c++11新关键字以及引入的新特性(上)

简介: [学习][记录] c++语言:从放弃到入门 <一> c++11新关键字以及引入的新特性

一、nullptr

nullptr 是用于解决 NULL 和 0 的有疑义关系的。NULL 通常被义为(void*)0。在 如下应用中会引发歧义。

1.1 入参

#include <iostream> 
using namespace std; 
void f(int){} 
void f(bool){} 
void f(void*){} 
int main() {
 f(0); // 调用f(int)
 f(NULL); // 可能无法编译通过,但一般会调用f(int)
 f(nullptr); // 调用f(void*)
}

1.1.1 解释

  1. C++ 视 0 首先为 int 型,因此,调用 f(0) 即调用 f(int)
  2. NULL 的情况复杂些,C++ 首先视其为广义整型。假如 NULL 被定义为普通 的 0,则调用 f(int); 如果 NULL 被定义成 0L,则 long -> int, long -> bool, 0L -> void*, 这三 种情况都是合法的,此时,编译器会报错
  3. 使用 nullptr,则不会有重载函数调用模糊的问题 - nullptr 不属于广义整型,也不是普通意义上的指针。 - nullptr 的实际类型是 std::nullptr_t,它能够隐式的转换成所有的原始指针 类型,故可将其视为一个可指向所有类型的指针。

1.1.2 办法

避免NULL重载编译报错:

f((int)NULL) 通过强转的办法解决

1.2 返值

使用 0 与 result 作比较,则一时不能确定 findRecord 的返回值类型 (可能是 广义整型,也可能是指针类型); 使用 nullptr,可以清楚地知道 findRecord 的返回值, 必定是一个指针类型。

auto result = findRecord( /* arguments */ );
 if (result == 0) { ... }
auto result = findRecord( /* arguments */ ); 
if (result == nullptr) { ... }

二、override

2.1 含义

覆盖重新写从父类继承过来的函数

覆写父类的虚函数时候,好的 IDE 一定会给出斜体等的提示,表示此函数覆写自 父类。

2.2 目的

避免发生,编译通过,但是逻辑错误的情况 例如函数名写错了 但是编译通过,却不是从父类继承过来的函数。

利用关键字 override 则指明,此种覆写关系,若此关系不成立,则以报错的形式提示 给用户。

2.3 问题?

class G{
public:
  virtual void func(int) {
    printf("G::func(int) \n");
  };
};
class H:G{
public:
  //virtual void func(int) override{
  //  printf("H::func(int) \n");
  //}
  virtual void func(double){
    printf("H::func(double) \n");
  }
};
void main() {
  H *p = new H; 
  p->func(5); 
  p->func(5.0); 
  system("pause");
}
vs2015
输出
H::func(double)
H::func(double)
请按任意键继续. . .

疑问???

没调用到G类的func(int)

三、final

3.1 含义

关键字 final 有两个用途:

第一,它阻止了子类继承;

class A final 
{
public: 
  virtual void func() const; 
};
class B: A //错误 编译报错 A is final
{
public: 
  void func() const override final;//  错误 编译报错 A is final
{
};

第二,阻止一个虚函数的覆 写。

class A 
{
public: 
  virtual void func() const; 
};
class B
{
public: 
  void func() const override final;//OK 
};
class C: B {
public:
  void func() const; //error, B::func is final  编译报错
};

3.2 意义

阻止类的无限扩展。

四、 =default =delete

4.1 default

C++ 的类有四类特殊成员函数,它们分别是:

  1. 默认构造函数
  2. 析构函数
  3. 拷贝构造函数
  4. 拷贝赋值运算符。
class A {
public:
  A();//构造函数 创建类的实例时 调用
  ~A();//析构函数 销毁类的实例时 调用
  A(const A &) =;//拷贝构造函数 类实例之间的拷贝 例如A a;A b = a;//此时调用拷贝构造函数
  A operator=(const A &);//拷贝赋值运算符   本质重载运算符=进行初始化
}

关键字default

如果程序员没有显式地为一个类定义某个特殊成员函数,而又需要用到该特殊成员 函数时,则编译器会隐式的为这个类生成一个默认的特殊成员函数。

class A {
public: A() = default; 
A(int x ):_x(x) {} 
private: int _x; 
};

4.2 delete

为了能够让程序员显式的禁用某个函数,C++11 标准引入了一个新特性: "=delete"函数。程序员只需在函数声明后上“=delete;”,就可将该函数禁用。

class Singleton {
public:
 static Singleton* getInstance() {
  if(_ins == nullptr) 
  _ins = new Singleton; 
  return _ins; 
 }
 Singleton(Singleton &) = delete; 
 Singleton& operator=(Singleton &) = delete; 
private: 
 Singleton(){
 } 
 static Singleton* _ins; 
};
Singleton* Singleton::_ins = nullptr; //类的静态变量在类外初始化
int main() { 
 Singleton *ps = Singleton::getInstance(); 
 Singleton ps(*ps); 
 *ps = Singleton::getInstance(); 
 return 0; 
}

4.3 Raw String Literals

4.3.1 缘由

C/C++中提供了字符串,字符串的转义序列,给输出带来了很多不变,如果需要 原生义的时候,需要反转义,比较麻烦。

4.3.2 使用

C++提供了 R"()",原生字符串,即字符串中无转义,亦无需再反义。但是注意() 中的)"会导至提前结束。

#include <iostream> 
using namespace std;
string path = "C:\Program Files (x86)\alipay\aliedit\5.1.0.3754"; // 错误,\没转义
string path2= "C:\\Program Files (x86)\\alipay\\aliedit\\5.1.0.3754"; //正确,\转义了 用\\或者/,但麻烦
string path3= R"(C:\Program Files (x86)\alipay\aliedit\5.1.0.3754)"; //正确,使用了R()
string path4= R"(C:\Program "Files" (x86)\\alipay\aliedit\5.1.0.3754)";//正确,使用了R()
//string path5= R"(C:\Program "Files" (x86)\\alipay\aliedit\)"5.1.0.3754)";//错误,R()的缺陷
int main(int argc, char *argv[]) {
  cout << path.c_str() << endl;
  cout << path2.c_str() << endl;
  cout << path3.c_str() << endl;
  cout << path4.c_str() << endl;
  system("pause");
  return 0; 
}
输出结果:
C:Program Files (x86)lipayliedit.1.0.3754
C:\Program Files (x86)\alipay\aliedit\5.1.0.3754
C:\Program Files (x86)\alipay\aliedit\5.1.0.3754
C:\Program "Files" (x86)\\alipay\aliedit\5.1.0.3754

五、Range-Based for 循环Foreach

一种基于STL容器遍历的一种for循环形式 类似Java的 foreach

5.1 语法形式:

for (declaration : expression) 
      statement
例如
vector<int> vecInt = {0,1,2,3,4,5}; //expression 列表
for(auto &i:vecInt){//auto &i  is declaration 申明
  cout << i << endl; 
}
等价写法1
vector<int> vecInt = { 1,2,3,4,5 };
for (int i = 0; i<vecInt.size(); i++) {
  int tmp = vecInt.at(i);
  cout << tmp << endl;
}
等价写法2
vector<int> vecInt = { 1,2,3,4,5 };
vector<int>::iterator itr = vecInt.begin();
for (; itr != vecInt.end(); itr++) {
  cout << *itr << endl;
}

5.2 解释:

expression 部分是一个对象,必须是一个序列,比方说

用花括号括起来的初始值

1.列表

2.数组

int[] a={1,2,3,4,5}; char ch[] = “123”;string str = “china”;

3.vector 或 string 等类型的对象。

vector vet = {1,2,3};list list= {1,2,3} map<int,string>map = {1,“123”};

这些类型的共同特点是拥有能返回迭 代器的 begin 和 end 成员。

declaration 部分负责定义一个变量,该变量将被用于访问序列中的基础元素。

每 次迭代,declaration 部分的变量会被初始化为 expression 部分的下一个元素值。

确 保类型相容最简单的办法是使用 auto 类型说明符。

5.3 关于vector

1.vector::size 会遍历vector 效率会低

六、std::for_each()

#include "stdafx.h"
#include<algorithm>
#include<iostream>
#include<vector>
void func(int n)
{
    std::cout << n << std::endl;
}
int main()
{
    std::vector<int> arr;
    arr.push_back(1);
    arr.push_back(2);
    std::for_each(arr.begin(), arr.end(), func);
    return 0;
}

七、STL容器的使用

7.1 normal init 常规初始化

所谓的常规初始化,即调用类的构 造器。

7.1.1 vector

vector<int> vi; 
vector<int> vi(10,10);//size 10,each value 10
vector<int> vi(arr,arr+10);//begin,end

7.1.2 list

list<int> li(10);
list<int> li2(10);
list<int> li3(10,1);//size 10,each value 1
int arr2[10] = {};
list<int> li4(arr2,arr2+10);//begin,end

7.1.3 map

7.1.3.1 查找
7.1.3.2 插入
//map[key] = value
map<int,string> mis; 
mis[0] = "first"; 
mis[1] = "second"; 
mis[2] = "third"; 
//make_pair
map<int,string> mis2(mis.begin(),mis.end());
mis.insert(std::make_pair(3, "fourth"));
mis.insert(pair<int, string>(3, "fourth"));
//value_type
mis.insert(map<int, string>::value_type(3, "fourth")); 
for (auto& pair : mis) 
  cout << pair.first << ":" << pair.second.c_str() << endl;
7.1.3.3 删除

7.2 initialization List {} 列表方式初始化

以初始化列表的方式来进行实始化,打破了,原有的初始化格局,令实始化更直观 化,人性化。

vector<int> vi = {1,2,3,4,5}; 
list<int> li = {1,2,3,4,5}; 
map<int,string> mis = { 
  {1,"c"}, {2,"c++"}, 
  {3,"java"},{4,"scala"},
  {5,"python"}
  };
mis.insert({6,"ruby"}); 
for(auto &is: mis) {
 cout<<is.first<<is.second<<endl; 
}

7.3 容器的使用

7.3.1 std::map

插入
查找
删除

7.3.2 std::vector

插入
查找
删除

7.3.3 std::list

插入
查找
删除

八、initializer_list 类

8.1 原理

是使用 {} 而不是 () 调用构造函数,

template< class T > class initializer_list; C++11 中提供了新的模板类型 initializer_list。 initializer_list 对象只能用大括号{}初始化,其内有元素都是 const 的。常用于构造 器和普通函数参数。

8.2 常见用法:

8.2.1 普通函数参数

double sum(const initializer_list<double> &il) 
{
 double s = 0; 
 for(auto d:il)
  s += d; 
 return s; 
}
double s = sum({1,2,3,4,5});

8.2.2 构造器参数

template <typename T> 
class myarr {
private: 
  vector<T> _arr;
public: 
  myarr() {
   cout<<"called myarr()"<<endl;
  }
  myarr(const initializer_list<T>& il) {
   cout<<"called myarr(const initializer_list<T>& il)" << endl; 
   for (auto x : il)
    _arr.push_back(x); 
  }
};
int main() {
 myarr<int> ma;
 myarr<int> ma2 = {1,2,3,4,5}; 
 return 0; 
}

8.3 格式

={},({}),{};

会调用initilizer_list构造

int arr[] = {1,2,3};
int arr2[] {1,2,3};
vector<int> vi = {1,2,3}; 
vector<int> vi2{1,2,3};
相关文章
|
2天前
|
存储 分布式计算 编译器
C++入门基础2
本内容主要讲解C++中的引用、inline函数和nullptr。引用是变量的别名,与原变量共享内存,定义时需初始化且不可更改指向对象,适用于传参和返回值以提高效率;const引用可增强代码灵活性。Inline函数通过展开提高效率,但是否展开由编译器决定,不建议分离声明与定义。Nullptr用于指针赋空,取代C语言中的NULL。最后鼓励持续学习,精进技能,提升竞争力。
|
1月前
|
存储 缓存 C++
C++ 容器全面剖析:掌握 STL 的奥秘,从入门到高效编程
C++ 标准模板库(STL)提供了一组功能强大的容器类,用于存储和操作数据集合。不同的容器具有独特的特性和应用场景,因此选择合适的容器对于程序的性能和代码的可读性至关重要。对于刚接触 C++ 的开发者来说,了解这些容器的基础知识以及它们的特点是迈向高效编程的重要一步。本文将详细介绍 C++ 常用的容器,包括序列容器(`std::vector`、`std::array`、`std::list`、`std::deque`)、关联容器(`std::set`、`std::map`)和无序容器(`std::unordered_set`、`std::unordered_map`),全面解析它们的特点、用法
C++ 容器全面剖析:掌握 STL 的奥秘,从入门到高效编程
|
1月前
|
存储 机器学习/深度学习 编译器
【C++终极篇】C++11:编程新纪元的神秘力量揭秘
【C++终极篇】C++11:编程新纪元的神秘力量揭秘
|
2月前
|
C++ 开发者
C++学习之继承
通过继承,C++可以实现代码重用、扩展类的功能并支持多态性。理解继承的类型、重写与重载、多重继承及其相关问题,对于掌握C++面向对象编程至关重要。希望本文能为您的C++学习和开发提供实用的指导。
68 16
|
3月前
|
算法 网络安全 区块链
2023/11/10学习记录-C/C++对称分组加密DES
本文介绍了对称分组加密的常见算法(如DES、3DES、AES和国密SM4)及其应用场景,包括文件和视频加密、比特币私钥加密、消息和配置项加密及SSL通信加密。文章还详细展示了如何使用异或实现一个简易的对称加密算法,并通过示例代码演示了DES算法在ECB和CBC模式下的加密和解密过程,以及如何封装DES实现CBC和ECB的PKCS7Padding分块填充。
78 4
2023/11/10学习记录-C/C++对称分组加密DES
|
4月前
|
安全 编译器 C++
【C++11】新特性
`C++11`是2011年发布的`C++`重要版本,引入了约140个新特性和600个缺陷修复。其中,列表初始化(List Initialization)提供了一种更统一、更灵活和更安全的初始化方式,支持内置类型和满足特定条件的自定义类型。此外,`C++11`还引入了`auto`关键字用于自动类型推导,简化了复杂类型的声明,提高了代码的可读性和可维护性。`decltype`则用于根据表达式推导类型,增强了编译时类型检查的能力,特别适用于模板和泛型编程。
37 2
|
5月前
|
编译器 C语言 C++
配置C++的学习环境
【10月更文挑战第18天】如果想要学习C++语言,那就需要配置必要的环境和相关的软件,才可以帮助自己更好的掌握语法知识。 一、本地环境设置 如果您想要设置 C++ 语言环境,您需要确保电脑上有以下两款可用的软件,文本编辑器和 C++ 编译器。 二、文本编辑器 通过编辑器创建的文件通常称为源文件,源文件包含程序源代码。 C++ 程序的源文件通常使用扩展名 .cpp、.cp 或 .c。 在开始编程之前,请确保您有一个文本编辑器,且有足够的经验来编写一个计算机程序,然后把它保存在一个文件中,编译并执行它。 Visual Studio Code:虽然它是一个通用的文本编辑器,但它有很多插
126 6
|
1月前
|
编译器 C++ 开发者
【C++篇】深度解析类与对象(下)
在上一篇博客中,我们学习了C++的基础类与对象概念,包括类的定义、对象的使用和构造函数的作用。在这一篇,我们将深入探讨C++类的一些重要特性,如构造函数的高级用法、类型转换、static成员、友元、内部类、匿名对象,以及对象拷贝优化等。这些内容可以帮助你更好地理解和应用面向对象编程的核心理念,提升代码的健壮性、灵活性和可维护性。
|
10天前
|
设计模式 安全 C++
【C++进阶】特殊类设计 && 单例模式
通过对特殊类设计和单例模式的深入探讨,我们可以更好地设计和实现复杂的C++程序。特殊类设计提高了代码的安全性和可维护性,而单例模式则确保类的唯一实例性和全局访问性。理解并掌握这些高级设计技巧,对于提升C++编程水平至关重要。
37 16

热门文章

最新文章