本来打算从上家公司辞职以后备考公务员的,学了不久感觉难度还是挺大的,还是得找个工作边上班边学习吧。
1.字符串原始字面量
R"()"在括号中的特殊字符不会被转义,也可以使用回车不用加连接符
String s=R"((D:\t\n\rhelloworld))";
cout<<s<<endl;
2.nullptr–指针的空值类型
取代NULL 给指针赋空值,防止野指针的出现(没什么特别的)
3.constexpr 修饰常量表达式
主要作用:constexpr修饰的常量表达式的计算在编译阶段 提高程序效率
void myConstexpterUse()
{
constexpr int a = 12;//相当于const,其值不可修改
struct useConexpter
{
int b;
};
constexpr useConexpter T1{ 12 };//对b初始化后不能修改b的值
useConexpter T2{ 13 };//可以修改b的值
T2.b = 12;
cout << "T1的值为:" << T1.b << " " << "T2的值为:" << T2.b;
}
constexpr int addNum()
{//此函数在编译阶段就进行了计算
using myInt = int;//using 定义新的类型
constexpr myInt a= 1;
constexpr myInt b=2;
return a+b;
}
//修饰模板函数
template <typename T>
constexpr T display(T t)
{
return t;
}
//使用模板函数
void useDisplay()
{
int b = display(10);//此时模板函数前的constexpr无效
constexpr int c = display(10);
}
//修饰构造函数
struct T
{
constexpr T() :a(10) {}
int a;
};
//使用修饰的构造函数
void useT()
{
constexpr T t;
cout << t.a<<endl;//a=10
}
4.auto 自动类型推导
当变量不是指针或者引用类型时,结果不会保留const,volatile关键字
当变量是指针或者引用类型时,结果会保留const,volatile关键字
auto 不能用于函数的参数 不能用于类的非静态成员变量的初始化 不能使用auto定义数组 无法使用auto推导模板类型
不过我auto一般就在遍历容器的时候使用一下
class myAuto
{
public:
static void useAuto();
};
void myAuto::useAuto()
{
auto a = 1;
auto b = 1.1;
auto c = 'a';
auto d = "avc";
int temp = 110;
auto e = &temp;
auto& f = temp;
auto* g = &temp;
//const修饰
int temp2 = 120;
const auto a1 = temp2;
//a2=int
auto a2 = a1;
const auto& a3 = temp2;
//a4=const int
auto &a4 = a3;
//auto最常使用的就是容器遍历
vector<int> v = { 1,2,3,4,5,6,7,8,9 };
cout << "遍历vector容器" << endl;
for (auto it = v.begin();it != v.end();it++)
{
cout << *it << " ";
}
}
5.decltype 它用于推导表达式类型
decltype();括号里面的表达式用它就能推断是什么类型
class Container
{//主要用于遍历容器
public:
void print(T& t)
{
cout << "\n" << "遍历结果:" << endl;
for (auto it = t.begin(); it != t.end(); ++it)
{
cout << *it << "\t" ;
}
cout << endl;
}
};
class myDecltype
{
public:
static void useDecltype();
static string compareNum(int a, int b);
};
void myDecltype::useDecltype()
{
decltype(1 + 2.22) a = 3.24;
}
string myDecltype::compareNum(int a, int b)
{
if (a >= b)
return "a大于等于b";
else
return "a小于b";
}
6.返回值类型后置 多用于泛型编程 感觉挺好用的以后有机会试试
template <typename T1,typename T2>
auto add(T1 t1, T2 t2)->decltype(t1 + t2)
{//(这样就不需要用户指定返回结果类型)
return t1 + t2;
}
7.final关键字
限制某个类不能被继承 某个函数不能被重写 一般不用在父类中
class Base
{
public:
virtual void test()
{
cout << "这是父类" << endl;
}
};
class child final:public Base
{
public:
void test() final
{
cout << "子类继承了父类,这个函数不能再被后代重写,且子类不能再被继承" << endl;
}
8.override 关键字
对某个函数进行重写时加上override 编译器会帮我看看重写的函数名有没有写错
class child2 :public Base
{
void test() override
{
cout << "子类重写了父类函数" << endl;
}
};
9.对模板右尖括号的优化
感觉就是对Bug就行了修复
10.函数模板的默认参数
要加默认参数 模板就得提前指明类型
template <typename T1=int ,typename T2=string >
void myTest(T1 t1=1,T2 t2="默认参数")
{
cout << "t1的默认参数为1 t2的默认参数为默认参数" << endl;
cout << "t1=" << t1 << "\t" << "t2=" << t2 << endl;
}
11.使用using和typedef定义模板
using 和typedef都是取别名 typedef给结构体定义别名感觉不错 using 还没怎么用
template <typename T>
struct myMapType
{
typedef map<int,T> myMap;
};
*/
template <typename T>
using myMapType = map<int, T>;
void useUsingMyMap()
{
myMapType <string> m;
m.insert(make_pair(1, "这是数字1"));
m.insert(make_pair(2, "这是数字2"));
m.insert(make_pair(3, "这是数字3"));
for (auto it = m.begin(); it != m.end(); ++it)
{
cout << it->first << " \t" << it->second<<" ";
}
cout << endl;
}
//12.委托构造函数
主要是可以减少代码量 三个构造函数都是为了打印参数值 在构造函数二中我们可以用构造函数一对参数进行打印在构造函数三中我们可以用构造函数二对参数一和二进行打印操作(构造函数二调用了构造函数一)
class delegateConstru
{
public:
delegateConstru() =default;
delegateConstru(int num1)
{//构造函数一
cout << "这是第一个数:" <<num1<< endl;
}
delegateConstru(int num1, int num2):delegateConstru(num1)
{//构造函数二
cout <<"这是第二个数:"<<num2 << endl;
}
delegateConstru(int num1, int num2, int num3) :delegateConstru(num1, num2)
{//构造函数三
cout << "这是第三个数:" << num3 << endl;
}
};
13.继承构造函数
class Base1
{
public:
Base1(int i) :m_a(i) {}
Base1(int i,string s):m_a(i),m_b(s){}
Base1(int i, string s,double d) :m_a(i), m_b(s),m_c(d) {}
void print(int a)
{
cout << a << endl;
}
void print(int a, string s)
{
cout << a << "\t" << s << endl;
}
int m_a;
string m_b;
double m_c;
};
class Child1:public Base1
{
public:
using Base1::Base1;
void print()
{//虽然参数不一样但也会被覆盖掉
cout << "子类与父类有同名函数时,子类会覆盖掉父类的同名函数" << endl;
}
using Base1::print;//解锁父类的同名函数
};
14.初始化列表 同一初始化方式
编译器遇见{}的时候内部会转化为一个arr数组
class useInitialzationList
{
public:
useInitialzationList(int num):m_a(num){}
useInitialzationList(int num, string s) :m_a(num), m_b(s) {}
void useInitialzatit()
{
int arr[] { 1,2,3,4,5 };
vector<int> v{1,2,3,4,5,7,8,9};
}
private:
int m_a;
string m_b;
};
15.initializer_list
可以不用定义就能传递多个相同类型的值
class useInitialList
{
public:
useInitialList(initializer_list<string> s)
{
for (auto it:s)
{
cout << it << " ";
Names.push_back(it);
}
cout << endl;
}
private:
vector<string> Names;
};
16.基于范围的for循环
简化循环操作
class useFor
{
public:
useFor(initializer_list<int> i)
{
for (const auto &it : i)
{
v.push_back(it);
}
}
void showVectorValue()
{
for (const auto& it : v)
{
cout << it << " ";
}
}
void addValue()
{//不加引用则会对拷贝的数据进行++操作,并不是v里面的数据
for (auto& it : v)
it++;
}
vector<int> v;
};
17.lambda表达式
在qt中相当好用 一般我在[]中一直用= 以后注意一下
[]什么都不写就是不捕获外部变量
[=] 把外部变量以拷贝的方式捕获
[&] 以引用方式捕获外部变量
[this] 这只不会this指针,可以访问内部成员
class useLambda
{//
public:
useLambda(int ii, string ss) :m_id(ii), m_name(ss) {};
void showValue(int i,string s)
{
cout << "\n我的ID:" << m_id << "\t我的名字:" << m_name << endl;
//想要捕获m_is和m_name [=],[&],[this],[m_id,m_name]
//想要捕获i和s [=],[&],[this],[i,s] 构造函数捕获不了
[&]() {m_id++; m_name += "修改"; cout << i<<" "<<s << "我的ID:" << m_id << "\t我的名字:" << m_name << endl; }();
}
private:
int m_id;
string m_name;
};
18.右值引用
右值是不能够取的到地址的即表达式结束不再存在的临时对象
右值可以延长临时对象生命周期 听说效率会变高没用过
class myRValue {
public:
myRValue()
{
cout << "构造函数被调用!" << endl;
}
~myRValue()
{
cout << "析构函数被调用!" << endl;
}
};
myRValue testRvalue()
{//返回临时对象
return myRValue();
}
void useRvalue()
{
//左值
int a = 2;
//左值引用 保存a的地址相当于取别名
int& b = a;
b = 3;
cout << b << endl;
//右值引用 不能用左值初始化
int&& c = 5;
int&& f = move(a);
//常量右值引用
const int&& d = 6;
cout << c << "\t" << d;
}
19.move方法
可以将右值转化为左值 在共享指针中让指针a指向的内存转移给指针b
void useMove()
{
int a = 1;
int&& b = move(a);
}
20.share_ptr
共享智能指针(unique_ptr差不多 就是不能共享)
class useSharePtr
{
public:
useSharePtr() {};
useSharePtr(int a,string s) :num(a),name(s) {};
void showInfor()
{
cout << "num: " << num << "\t" << "name:" << name << endl;
}
~useSharePtr()
{
cout << "析构函数被调用" << endl;
}
private:
int num;
string name;
};
shared_ptr<int> ptr(new int(3));
cout <<"指针引用计数为:" << ptr.use_count() << endl;
shared_ptr <int>ptr2 = move(ptr);
cout << "指针引用计数为:" << ptr2.use_count()<< endl;
shared_ptr <int>ptr3 = ptr2;
cout << "指针引用计数为:" << ptr3.use_count() << endl;
shared_ptr<string> ptr4 = make_shared<string>("共享指针");
shared_ptr<useSharePtr> ptr5 = make_shared<useSharePtr>(1024,"小莫");
ptr5->showInfor();
shared_ptr<useSharePtr> ptr6(new useSharePtr[6], [](useSharePtr* t) {
cout << "自定义删除函数:" << endl;
delete []t;
});
shared_ptr<useSharePtr> ptr7(new useSharePtr[3], default_delete<useSharePtr[]>());//使用自带的默认删除函数
shared_ptr<useSharePtr[]> ptr8(new useSharePtr[3]);//c11之后支持
21.weak_ptr
帮助share_ptr一起管理某一块空间 weak_ptr解决共享指针嵌套问题不会让计数器+1
class useWeakPtr:public enable_shared_from_this<useWeakPtr>
{
public:
shared_ptr<useWeakPtr> getSharePtr()
{
return shared_from_this();
}
~useWeakPtr()
{
cout << "useWeakPtr类的析构函数被调用" << endl;
}
};
//weak_ptr指针的使用
shared_ptr<useWeakPtr> p1(new useWeakPtr);
shared_ptr<useWeakPtr> p2 = p1->getSharePtr();
cout << "useWeakptr的引用计数是:" << p2.use_count() << endl;
weak_ptr<useWeakPtr> p3 = p1;
cout << p3.expired() << endl;
以上仅仅是对c11新特性的浅尝,仅仅是个人理解