新增了 long long 和 unsigned long long ,支持64bit的整型
在VS中 int和long都是4B,long long 8B
在Linux中 int是4B,long和long long 8B
新增了类型 char16 t和 char32 t,以支持 16 位和 32 位的字符,
意义不大,好像没什么人用,连 demo程序都找不到
原始字面量可以直接表示字符串的实际含义,不需要转义和连接
修饰换行的字符串
语法
R"(字符串的内容)"
R"aaa(字符串的内容)aaa" //可以在括号前后加标签 无实际作用,类似注释 但是必须成对出现
string l = R"(G:\code\c++)";
cout<<l<<endl;
C++11 丰富了大括号的使用范围,用大括号括起来的列表(统一的初始化列表)可以用于所有内置类型和用户自定义类型。使用统一的初始化列表时,可以添加等号(=),也可以不添加:
int x{10};
double y{3.14};
int q[5]{1,2,3,4,5};
在C和C++98中,auto 关键字用于修饰变量(自动存储的局部变量)
在 C++11 中,赋予了 auto 全新的含义,不再用于修饰的变量,而是作为一个类型指示符,指示编译器在编译时推导 auto 声明的变量的数据类型。
auto a = 50;
auto b = "你好";
注意
真正用途
int f(int a,double b,const char *c,long long d,short e){
cout<<11<<endl;
return 0;
}
int main() {
auto a = 50;
auto b = "你好";
auto pf = f; //和下面的效果是一样的
int (*pf1)(int,double,const char *,long long,short) = f;
pf(1,1.1,"你好",1,1);
pf1(1,1.2,"你好",1,1);
}
decltype
关键字用于查询表达式的数据类型
语法:decltype(expression) var
decltype分析表达式并得到其类型,不会计算执行表达式
规则:要么是expression类型,yaom是expression类型的引用
const int a = 1;
decltype(a) c = 5;//c的类型也是 const int
int fun2(){
return 1;
}
decltype(fun2())d; //不会调用fun2
//fun2 和 fun2() 不一样
int a = 10;
decltype(++a) e = a;
decltype((a)) e = a;
int fun(int x,double y){}
//等同于
auto fun(int x,double y) -> int{}
auto fun(int x,double y) -> decltype(x+y){}
//但是C++14标准 函数返回值允许是auto,不必尾随返回类型
auto fun(int x,double y){}
auto是一个占位符
空指针是不会指向有效数据的指针
以前,C/C++用0表示空指针,这带来了一些问题,这样的话0 既可以表示指针常量,又可以表示整型常量
C++11 新增了关键字 nullptr,用于表示空指针 它是指针类型,不是整型类型
为了向后兼容,C++11仍允许用0来表示空指针,因此表达式nullptr==0为true
使用 nullptr 提供了更高的类型安全
例如,可以将0传递给形参为int的函数,但是,如果将 nullptr 传递给这样的函数,编译器将视为错误
出于清晰和安全考虑使用nullptr
智能指针初级
C++支持对象自动转换,但是,自动类型转换可能导致意外
为了解决这种问题,C++11引入了explicit 关键字,用于关闭自动转换的特性
class Person{
public:
int age=18;
string name="西施";
};
语法
for(迭代变量:迭代范围){
//循环体
}
std::vector<int>v({1,2,34,55,68,1,23});
for(auto it:v){
cout<<it<<endl;
}
注意事项:
array 静态数组
forward_list 单向链表
unordered_map、unordered_set 哈希表
final 关键字用于限制某个类不能被继承,或者某个虚函数不能被重写
final 关键字放在类名或虚函数名的后面
在派生类中,把 override 放在成员函数的后面,表示重写基类的虚函数,提高代码的可读性
在派生类中,如果某成员函数不是重写基类的虚函数,随意的加上 override 关键字,编译器会报错
静态断言
const既可以表示只读,也可以表示常量
C++11 标准为了解决 const 关键字的双重语义问题,保留了 const 表示“只读”的语义,而将“常量”的语义划分给了新添加的 constexpr 关键字
所以,C++11 标准中,建议将const和 constexpr 的功能区分开,表达“只读”语义的场景用 const,表达“常量”语义的场景用 constexpr
C++自定义的类有默认生成一些成员函数:
在实际的开发中,为了满足不同的需求,一个类可能会重载多个构造函数。多个构造函数之间可能会有重复的代码。例如变量初始化,如果在每个构造函数中都写一遍,这样代码会显得臃肿
委托构造就是在一个构造函数的初始化列表中调用另一个构造函数
class P {
public:
int _a;
double _b;
std::string _name;
P() : _a(0), _b(0.0), _name("") {}
P(int a, double b) : _a(a), _b(b) {
_name = "";
std::cout << "P(int a,double b)" << std::endl;
}
//如果 P(a, b) 写在里面,那么代表创建一个匿名对象而不是初始化
P(int a, double b, const std::string &name) : P(a, b) {
_name = name;
std::cout << "P(int a,double b,std::string &name)" << std::endl;
}
};
注意
class P {
public:
int _a;
double _b;
std::string _name;
P() : _a(0), _b(0.0), _name("") {}
P(int a, double b) : _a(a), _b(b) {
_name = "";
std::cout << "P(int a,double b)" << std::endl;
}
//如果 P(a, b) 写在里面,那么代表创建一个匿名对象而不是初始化
P(int a, double b, const std::string &name) : P(a, b) {
_name = name;
std::cout << "P(int a,double b,std::string &name)" << std::endl;
}
};
class B:public P{
public:
int b_a;
using P::P;//使用基类的构造函数
B(int a,double b,int c):P(a,b),b_a(c){}//B类有三个构造函数
};
lambda表达式或匿名函数
特点:距离近、简洁、高效和功能强大
捕获列表
通过捕获列表,lambda函数可以访问父作用域中的非静态局部变量(静态局部变量可以直接访问,不能访问全局变量)
捕获列表书写在[]中,与函数参数传递类似(原理),捕获的方式可以是值和引用
lambda函数本质就是标准委员会把仿函数换个花样给大家
在C++中所有的值不是左值就是右值
左值:表达式结束后依然存在的持久化对象(有名字的对象)
右值:表达式结束后就不再存在的临时对象(没有名字)
可以取地址的就是左值,否则为右值
C++11拓展了右值:纯右值和将亡值
左值引用(T&):以前所学的引用,只能绑定左值
右值引用(T&&):给右值取个名字 数据类型&& 变量名=右值
,只能绑定右值
//右值引用
int &&a = 10; //10是右值 a和左值没有区别
但是,常量左值(const T&)引用既可以绑定非常量左值、常量左值、右值,而且在绑定右值的时候,常量左值引用还可以像右值引用一样将右值的生命期延长,缺点只读
const int a =5;//常量左值
const int&b = a;
const int&c = 1;//1是右值
引入右值引用的主要目的是实现移动语义
如果一个对象中有堆区资源,需要编写拷贝构造函数和赋值函数,实现深拷贝
深拷贝把对象中的堆区资源复制一份,如果源对象(被拷贝的对象)是临时对象,拷贝完就没什么用了,这样会造成无意义的资源申请和释放操作
如果可以直接使用源对象的资源,可以节省资源申请和释放的时间,C++11的移动语义就可以实现
右值调用以下
移动构造函数:类名(类名&& 源对象)
移动赋值函数:类名& operator=(类名&& 源对象)
注意:
std:.move()
方法来将左值转义为右值,从而方便使用移动语义。它其实就是告诉编译器,虽然我是一个左值,但不要对我用拷贝构造函数,用移动构造函数吧。左值对象被转移资源后,不会立刻析构,只有在离开自己的作用域的时候才会析构,如果继续使用左值中的资源,可能会发生意想不到的错误。在函数模板中,可以将参数“完美”的转发给其它函数。
所谓完美,即不仅能准确的转发参数的值,还能保证被转发参数的左、右值属性不变
c++11标准引入了右值引用和移动语义,所以,能否实现完美转发,决定了该参数在传递过程使用的是拷贝语义还是移动语义。
T&&
,那么函数可以接受左值也可以接受右值std::forward(参数)
,用于转发参数,右值还是右值,左值还是左值void fun1(int&i){
std::cout<<"左值"<<std::endl;
}
void fun1(int&&i){
std::cout<<"右值"<<std::endl;
}
void fun2(int i){
fun1(i);
}
template<typename T>
void fun3(T&& i){
fun1(std::forward<T>(i));
}
int main() {
int i=5;
// fun2(i);
// fun2(2);/*左值
// 左值*/
fun2(i);
fun3(2);/*左值
右值*/
对参数进行泛化,能支持任意个数、任意数据类型的参数
//递归中止时调用非模板函数,函数名要和展开参数包的递归函数相同 无参数
void print(){
std::cout<<"递归结束"<<std::endl;
}
//第一个普通参数 第二个可变参数
template<typename T, typename ...Args>
void print(T arg, Args... args) {//arg本次参数 args尚未展开的参数
std::cout << "本次参数为" << arg << std::endl;
std::cout<<"还剩下"<< sizeof...(args)<<"个参数"<<std::endl;
print(args...);//递归调用 继续展开参数
}
int main() {
print("西施", 18, "你好");
}
需求:
给出表白对象,但是表白前要喊一句口号
//递归中止时调用非模板函数,函数名要和展开参数包的递归函数相同 无参数
void print(){}
//第一个普通参数 第二个可变参数
template<typename T, typename ...Args>
void print(T arg, Args... args) {//arg本次参数 args尚未展开的参数
std::cout<<"亲爱的"<<arg<<",我要向你表白!"<< std::endl;
print(args...);//递归调用 继续展开参数
}
template<typename ...Args>
void biaoBai(const std::string&str,Args...args){
std::cout<<str<<std::endl;
print(args...);
std::cout<<"表白完成"<<std::endl;
}
int main() {
biaoBai("我是一个大帅锅", 18, "你好");
}
C++11提供了 chrono 模板库,实现了一系列时间相关的操作(时间长度、系统时间、计时器)
头文件#include
命名空间std::chrono
duration
模板类用于表示一段时间(时间长度、时钟周期),如1小时、8分钟、5秒
std::chrono::hours t1(1);//1小时
std::chrono::minutes t2(60);//60分钟
std::cout<<(t1==t2)<< std::endl;
std::cout<<t1.count()<<std::endl;//时钟周期的值
std::cout<<t2.count()<<std::endl;//时钟周期的值
duration
模板类重载了各种算术运算符,用于操作duration
对象
duration
模板类提供count方法,获取duration
对象的值
system_clock
类支持了对系统时钟的访问
//引入
//#include
//#include
//1.获取系统时间(C++时间)
//std::chrono::time_point now
auto now = std::chrono::system_clock::now();
//2.把系统时间转化为time_t时间(UTC时间)
time_t t_now = std::chrono::system_clock::to_time_t(now);
// 这两个之间可以进行时间偏移
//3.把time_t时间转化为本地时间(北京时间)
// localtime()不是线程安全的,VS用localtime_s代替,Linux用localtime_r代替
tm*tm_now = localtime(&t_now);
//4.格式化输出tm结构体的成员
std::cout<<std::put_time(tm_now,"%Y-%m-%d %H:%M:%S")<<std::endl;
std::cout<<std::put_time(tm_now,"%Y%m%d %H%M%S")<<std::endl;
//将时间写入字符串
std::stringstream ss;//创建stringstream对象ss 包含头文件
ss<<std::put_time(tm_now,"%Y-%m-%d %H:%M:%S");//将时间输出到对象ss
std::string timestr = ss.str();//把ss对象转化为string对象
std::cout<<timestr<<std::endl;
steady_clock
类相当于秒表。操作系统只要启动就好进行时间的累加,常用于耗时的统计
std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
for (int i = 0; i < 100000; ++i) {
}
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
auto dt = end - now;
std::cout << "耗时:" << dt.count() << "纳秒" <<"--"<<(double)dt.count()/(1000*1000*1000)<<"秒"<< std::endl;