首页 > 编程语言 >C++11新特性

C++11新特性

时间:2022-08-24 21:15:22浏览次数:57  
标签:11 std cout int 特性 C++ using include Example

c++11增加新关键字auto:实现自动类型的推导

使用auto关键字定义的变量必须要有初始化表达式。

#include<iostream>
using namespace std;

class Example
{
private:
    int x;
public:
    Example(int xx = 0):x(xx){}

    int Show()const
    {
        return x;
    }
};

int main()
{
    //auto a;
    //错误,auto是通过初始化表达式进行类型推导的。
    //如果没有初始化表达式,就无法确定a的类型。
    auto str = "HelloWorld";
    cout<<str<<endl;

    //对自定义类型进行类型推导
    auto ex = new Example();
    cout<<ex->Show()<<endl;
    delete ex;

    return 0;
}

c++11新增关键字decltype,这个关键字可以从一个变量或表达式中得到类型

#include<iostream>
using namespace std;

int main()
{
    double y = 100;
    cout<<sizeof(decltype(y))<<endl;//8

    decltype(y)x = 200;
    cout<<x<<endl;
    return 0;
}

c++11引入表示空指针类型的关键字nullptr.

#include<iostream>
using namespace std;

void F(int a)
{
    cout<<a+1<<endl;
}

void F(int * p)
{
    cout<<p<<endl;
}

int main()
{
    int * p = nullptr;
    int * q = NULL;

    cout<<p<<endl;              //0
    cout<<q<<endl;              //0
    //c++11引入关键字nullptr表示空指针类型,为了兼容NULL这个宏
    //所以两者的值都为0.但是,NULL可以和0相互替代。而0不可以表
    //示为nullptr
    bool equal = (p == q);
    cout<<equal<<endl;          //1

    //int a = nullptr;          //error,nullptr不可以表示0
    int b = NULL;               //right,NULL就是0
    cout<<b<<endl;              //0
    F(0);                       //1
    F(nullptr);                 //0
    return 0;
}

基于范围的for循环(亦称区间迭代)

#include<iostream>
#include<map>
#include<string>
using namespace std;

int main()
{
    int arr[5] {100,200,300,400,500};
    for(auto x:arr)
    {
        cout<<x<<endl;
    }

    map<int,string>m{{1,"wang ming"},{2,"xiao hua"}};
    for(auto p:m)
    {
        cout<<p.first<<" "<<p.second<<endl;
    }
    return 0;
}

更加优雅的初始化方法

  1. 示例1
#include<iostream>
#include<vector>
using namespace std;

int main()
{
    int arr[] {100,200,300,400,500};//等于号可以省略
    vector<double>ve {100,200,300,400,500};
    for(auto x:ve)
    {
        cout<<x<<" ";
    }
    return 0;
}
  1. 示例2
#include <iostream>
#include <initializer_list>
using namespace std;
class Example
{
public:
	explicit Example(int x):x(x){}

	int GetX()const
	{
		return x;
	}
private:
	int x;
};
int main()
{
	//c++扩大了用大括号扩起的列表(初始化列表)
	//的适用范围,使其可用于所有内置类型和用户
	//定义的类型(即类类型)。使用初始化列表时
	//可以添加等号也可以不添加。
	int a{ 100 };
	cout << a << endl;
	//也可以用于new表达式中
	int * pointer = new int[2]{ 100,200 };
	cout << pointer[0] <<" "<<pointer[1]<< endl;
    //创建对象时也可以使用大括号(而不是圆括号)
	//括起的列表来调用构造函数
	Example x{ 100 };
	//Example x = {1000};
	cout << x.GetX() << endl;
	//c++11新增头文件initializer_list,这个模板类的
	//成员变量是指针类型
	initializer_list<int>arr{ 100,200,300,400 };
	cout << *arr.begin() << endl;

}

c++11还引入了变长参数模板。

tuple是一个类模板,允许我们将多个不同类型的成员绑定为单一对象。每一个tuple对象包含指定数量的成员。但对一个给定的tuple对象,标准库并没有限制我们可以定义的成员数量上限。tuple对象中的元素是被紧密的存储的(位于连续的内存区域),而不是链式结构。

#include<iostream>
#include<tuple>
#include<vector>
using namespace std;

int main()
{
    //声明并创建一个元组对象:tuple类构造函数
    tuple <int ,int , vector<int>>tupleText(100,200,{300,400,500});

    //求元组对象的成员数量(参数个数):tuple_size函数
    int tupleTextSize = tuple_size<decltype(tupleText)>::value;

    cout<<"tupleText's size is:"<<tupleTextSize<<endl;//3

    //求元组对象首个成员变量的值:get函数
    auto first = get<0>(tupleText);

    cout<<"The first value is:"<<first<<endl;//100

    auto third = get<2>(tupleText);

    for(const auto &iter:third)
    {
        cout<<"The third value:"<<iter<<" ";
    }

    //生成一个新的tuple对象:make_tuple函数
    auto catTupleText = make_tuple(1,4);
    //元组合并:tuple_cat函数
    auto newTuple = tuple_cat(catTupleText,tupleText);

    int newTupleSize =  tuple_size<decltype(newTuple)>::value;

    cout<<"\nThe newTuple's size is:"<<newTupleSize<<endl;//5

    return 0;
}

lambda表达式用于创建并定义匿名的函数对象

1.lambda表达式基本语法
  1. 它以[]为开始,这个标识叫做捕获指定器,它告诉编译器我们要创建一个lamdba表达式。一个lambda表达式具有如下形式:[capture list] (parameter list) -> return type {function body}
#include<iostream>
using namespace std;

int main()
{
    auto func1 = [](){cout<<"HelloWorld"<<endl;};
    //这个auto关键字可以推断func1变量的类型为函数指针类型
    cout<<func1<<endl;//1

    func1();
    auto func2 = [](int a){cout<<a<<endl;};
    func2(100);

    return 0;
}
  1. lambda表达式与STL
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

int main()
{
    vector<int>ve {100,200,300};
    //遍历方式1
    for_each(ve.begin(), ve.end(),[](int val)
    {
        cout<<val<<" ";
    });
    //遍历方式2
    for(auto x:ve)
    {
        cout<<x<<" ";
    }
    //遍历方法3
    for(auto x = ve.begin();x != ve.end();x++)
    {
        cout<<*x<<" ";
    }
    return 0;
}
  1. 指定lambda返回类型:如果你的lambda函数没有return语句,则默认返回void。假如你有一个简单的返回语句,编译器将推导返回值的类型,因此无需指定返回类型,但也有例外,所以最好指定返回类型。
2.lambda表达式的完整变量捕获:
  1. [] 不捕获任何变量
  2. [&] 以引用方式捕获所有变量。note:当以引用方式捕获一个局部变量时,必须确保在lambda执行时变量是存在的。
  3. [=] 用值的方式捕获所有变量(可能被编译器优化为const &)。23属于隐式捕获。
  4. [=, &foo] 以引用捕获foo, 但其余变量都靠值捕获
  5. [bar] 以值方式捕获bar; 不捕获其它变量
  6. [this] 捕获所在类的this指针

image.png

#include<iostream>
using namespace std;

class Example
{
private:
    int x;
public:
    Example():x(100){}

    void Show()const
    {
        [this]()//捕获所在类的指针
        {
            cout<<x<<endl;
        }();//调用lambda表达式
    }
};

int main()
{
    Example ex;
    ex.Show();
    return 0;
}
3.可变lambda

默认情况下,对于一个值被拷贝的变量,lambda不能改变其值,因为是只读的。如果希望改变一个采用值捕获方式的变量的值,就必须在参数列表首加上关键字mutable,这样就可以在lambda函数体改变捕获的变量的值,但是外部的变量没有影响,因为是值捕获。

int val = 100;
auto func = [val]()mutable
{
    // 如果没有mutable关键字
    // error: increment of read-only variable 'val'
    return ++val;
};
cout << func() << endl; // 101
cout << val << endl;    // 100

新的std::function是传递lambda函数的最好的方式,不管是传递参数还是返回值。它允许你在模板中指定参数列表和返回值的确切类型。function定义在’functional’头文件中。

#include<iostream>
#include <functional>
#include <vector>
#include<string>
using namespace std;

class AddressBook
{
public:
    vector<string> findMatchingAddresses (function<bool (const string&)> func)
    {
        vector<string> results;
        for ( auto itr = _addresses.begin(), end = _addresses.end(); itr != end; ++itr )
        {
            // 调用传递到findMatchingAddresses的函数并检测是否匹配规则
            if ( func( *itr ) )
            {
                results.push_back( *itr );
            }
        }
        return results;
    }

private:
    vector<string> _addresses;
};

constexpr函数

常量表达式主要是允许一些计算发生在编译时,即发生在代码编译而不是运行的时候。这是很大的优化.为了使函数获取编译时计算的能力,你必须指定constexpr关键字到这个函数的返回值前。

explicit关键字

explicit关键字在Cpp11以前是只能用于修饰构造函数,但在C++11中可以用来修饰操作符,上面代码中的operator bool()加上explicit表示其无法隐式转化为bool。

#include<iostream>
using namespace std;
struct Testable
{
    explicit operator bool() const {
          return false;
    }
};

int main()
{
  Testable a, b;
  if (a)      {  }
  if (a == b) {  }  // 编译错误,这里无法将a,b隐式
  //转换为bool.
}

利用c++11的新特性在类内初始化成员变量

1.对非静态成员数组变量进行初始化
#include<iostream>
using namespace std;

class Example
{
private:
    int x[5];
public:
    Example():x{1,2,3,4,5}{}

    void Show()const
    {
        for(auto y:x)
        {
            cout<<y<<" ";
        }
    }
};
int main()
{
    Example ex;
    ex.Show();
    return 0;
}
2.对非静态非数组成员变量进行初始化
#include <iostream>
using namespace std;
class Example
{
public:
	Example(int x):x(x){}

	int  GetX()const
	{
		return x;
	}
	static int  GetY()
	{
		return y;
	}

	Example()
	{

	}
private:
	int x{ 100 };
	//int x = 100;//可以使用等号或者大括号版本的初始化
	const static int y = 200;
    //static int y = 200; // error
};
int main()
{
	Example ex;
	cout << ex.GetX() << endl;
	cout << Example::GetY() << endl;
	//基于范围的for循环可以简化代码的编写量
	int arr []= {100,200,300,400};
	for (auto x : arr)
	{
		cout << x << " ";
	}
	return 0;
}

3.对类内常量的静态成员变量直接初始化(非常量的静态成员变量不能在类内直接初始化)

右值引用和move(移动)语义

1.右值引用

传统的cpp引用(左值引用)关联到左值。c++11增加了右值引用,这是使用&&表示的,右值引用可以关联到右值。通过将数据与特定的地址关联,使得可以通过右值引用来访问该数据。右值引用的赋值表达式右边一般是常量。

#include <iostream>
using namespace std;
int main()
{
	//右值引用举例
	int && a = 100;		//若引用是常引用,则a的值不可更改
	cout << &a << endl;//获取100这个元素的地址
	cout << a << endl;
	a = 100000;//此时a的地址值还是100的地址
	cout << &a << endl;
	cout << a << endl;
	int x = 1000;
	int y = 1000;
	int && b = x + y;//右边是表达式
	cout << b << endl;
	return 0;
}
2.移动构造函数与移动赋值运算符函数

转移构造函数(移动构造函数)的工作:把资源从一个对象转移到另一个对象,而不是复制它们。一般参数是左值则调用拷贝构造函数,右值则调用移动构造函数。源对象本身必须不能被改变,作为左值。用户不再使用的对象作为右值。

#include<iostream>
#include<memory>
using namespace std;

class Example
{
private:
    unique_ptr<int>_member;//智能指针类对象,为左值
public:
    //Example(unique_ptr<int>&&member):_member(member){}
    //error,因为对右值member的转移是不允许的
};
int main()
{
    return 0;
}

c++11新增关键字noexcept:

其语法为:

  1. noexcept:等同于noexcept(true)
  2. noexcept(expression)
If the value of the constant expression is true, the function isdeclared to not throw any exceptions. 
noexcept without a constant expression is equivalent to noexcept(true).

标准库bind函数

bind函数定义在functional头文件中,可以将bind函数看作一个通用的函数适配器,他接受一个可调用对象,生成一个新的可调用对象来适应原对象的参数列表。

// arg_list中的参数可能包含入_1,_2等,这些是新函数newCallable的参数。
auto newCallable = bind(callbale, arg_list);

_1,_2等,是放在了命名空间placeholder中,所以要使用:

//_1,_n定在std::placeholders里面
using namespace std::placeholders;

bind参数用法:

//g是以个有2个参数的可调用对象
auto g = bind(func, a, b, _2, c, _1);//func是有5个参数的函数
调用g(X, Y), 等于 func(a, b, Y, c, X)

绑定引用参数:默认情况下,bind的那些不是占位符的参数被拷贝到返回的可调用对象中。但是有时希望以引用方式传递绑定的参数,或者要绑定参数的类型不能拷贝。(比如ostream)

ostream& print(ostream& os, const string &s, const char &c)
{
  return os << s << c;
}

//bind引用,必须使用ref或者cref函数,把对象转化成引用,不能用&
ostream &os = cout;
const char c = ' ';
vector<string> svec{"aab","d","aa","bb","e","bbb"};
for_each(svec.begin(),svec.end(),bind(print, ref(os), _1, cref(c)));

新增函数定义语法,在函数名和参数列表后指定函数返回类型

#include "pch.h"
#include <iostream>
#include <vector>
using namespace std;
auto Sum(int x)->int
{
	return x;
}
int main()
{
	cout << Sum(100) << endl;
	//c++为标识符创建别名提供了typedef,c++11提供了创建
	//别名的新语法using=
	vector<int>vec;
	for (int i = 1; i < 3; i++)
	{
		vec.push_back(i);
	}
	using itType = vector<int>::iterator;
	itType it = vec.begin();
	cout << *it << endl;
	//c++11新增了一种作用域内的枚举类型,使用关键字
	//struct或者class来定义
	enum class color{red,white,yellow};
	//如上,需要使用red时,需要加上color::red;
	int  a = int(color::red);
	cout << a << endl;  // 0
	return 0;
}

delete和default关键字的作用

  1. c++11使用关键字default来指定声明一些编译器可以默认提供的构造函数、赋值函数、析构函数这些方法.这样就可以使用编译器生成的函数。
  2. 禁用函数的用法:关键字delete则指定禁止使用编译器提供的某个方法。(对任何成员函数都适用)
#include <iostream>
using namespace std;
class Example
{
private:
	int x;
public:
	Example() = delete;//将导致类无法使用默认构造函数

	Example(int x):x(x){}
	int GetX()const
	{
		return x;
	}
	//导致调用默认拷贝构造函数
	Example(const Example & ex) = default;
};
int main()
{
	//Example ex;//无合适的函数可以调用
	Example ex(100);
	cout << ex.GetX() << endl;
	Example ex1 = ex;
	cout << ex1.GetX() << endl;
	return 0;
}

委托构造函数

如果给类提供了多个构造函数,可能需要重复编写相同的
代码。委托构造函数允许在一个构造函数中使用另一个构
造函数。

标签:11,std,cout,int,特性,C++,using,include,Example
From: https://www.cnblogs.com/xiaocer/p/16621549.html

相关文章

  • C++ Primer阅读笔记
    如何设置GNU编译器对C++11的支持运行编译器的时候指定-std=C++11参数黑窗口下编译运行源文件//windows下gcctest.c-otest//-o表示指定可执行文件的文件名.\tes......
  • C++Primer阅读笔记续
    chapter13.拷贝控制概述控制类类型的对象的拷贝,赋值,移动,销毁包括五种特殊的成员函数(这些称为拷贝控制成员):拷贝构造函数拷贝赋值运算符移动构造函数移动赋值运算符......
  • Windows10 pybind11 opencv 和numpy相互转换 (tcy)
      利用pybind11实现python和C++图像之间的相互调用。将Mat类引入python中。 图像相互转换通过左值引用及智能指针实现。封装了类操作及8个函数(Mat和numpy......
  • Pybind11实现python调取C++
    1、一些处理矩阵运算,图像处理算法,直接采用python实现可能速度稍微慢,效率不高,或者为了直接在python中调用其他C++第三方库。图像,矩阵在python中通常表示为numpy.ndarray,......
  • 洛谷 P1162 填涂颜色
    题目链接:https://www.luogu.com.cn/problem/P1162试题分析:本题运用广搜,我们大体思路是这样的:首先,我们将起始位置放到队尾,然后,在队列不为空的情况下,我们要一直取队首并拓......
  • C++ 静态库、动态库使用Cmake构建系统
    案例1:无静态库、动态库参与文件目录结构1假设include目录存放头文件data.h包含函数声明,src目录存放对应的data.cpp文件包含函数定义、以及一个全局变量。main.cpp存放在......
  • 什么也不会之-我要进大厂-要不就回家种地;吃饭的手艺-唯一的熟练-号称可以造一切轮子的
    1、c和cpp不同之处mark看到这个代码,我人都麻了。先是.h文件中定义了x,并对x附了值再在main.cpp中调用了module.cpp中的func函数。看上去十分的简单。但是,我在main.cpp......
  • 多位时间戳转换(10、11、13位时间戳都适用)
    10、11、13位时间戳都适用<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metahttp-equiv="X-UA-Compatible"content="IE=edge"><met......
  • windows使用/服务(3)windows11 部署tomcat图文教程
    参考地址:https://zhuanlan.zhihu.com/p/874392681、下载JDK安装包,下载地址:下载JDK安装包,已安装jdk忽略Java18oracle-jdk官网:https://www.oracle.com/java/techno......
  • win10、win11环境下查看IIS里各项目资源占用情况
    参照链接:【如何设置IIS程序池的回收时间,才能最大程度的减少对用户的影响?】-走看看(zoukankan.com)概念:简单理解IIS应用程序池应用程序池可以看成是计算机分配给Web......