C++ 11

一切皆可以用列表初始化。

cpp 复制代码
struct Point
{
	int _x;
	int _y;
};

class A
{
public:
	//explicit A(int x, int y)
	A(int x, int y)
		:_x(x)
		,_y(y)
	{}

	A(int x)
		:_x(x)
		,_y(x)
	{}
private:
	int _x;
	int _y;
};
//int main()
//{
//	// c
//	int array1[] = { 1, 2, 3, 4, 5 };
//	int array2[5] = { 0 };
//	int array3[5]{ 0 };
//
//	Point p = { 1, 2 };
//
//	// 单参数的隐式类型转换
//	A aa2 = 1;
//
//	A aa4 = { 1 };
//	A aa5 { 1 };
//
//	// 多参数的隐式类型转换
//	A aa1 = { 2,2 };

//=也可以省略
//	A aa6 { 2,2 };
}

x自定义类型 = Y类型(叫做隐式类型转换);x支持y为参数类型的构造函数就可以;

容器想用不固定的{}数据个数初始化,就用initializer_list支持。

右值引用:
左值是⼀个表⽰数据的表达式(如变量名或解引⽤的指针),⼀般是有持久状态,存储在内存中,我 们可以获取它的地址,左值可以出现赋值符号的左边,也可以出现在赋值符号右边。定义时const 修饰符后的左值,不能给他赋值,但是可以取它的地址。

以下都是左值:

右值也是⼀个表⽰数据的表达式,要么是字⾯值常量、要么是表达式求值过程中创建的临时对象 、匿名对象等 ,右值可以出现在赋值符号的右边,但是不能出现出现在赋值符号的左边,右值不能取地址。

以下都是左值:

左值引用给左值起别名(Type& r1 = x),右值引用给右值起别名( Type&& rr1 = y)。

左值引⽤不能直接引⽤右值,但是const左值引⽤可以引⽤右值。

const string& ref1 = string("1111");

右值引⽤不能直接引⽤左值,但是右值引⽤可以引⽤move(左值)

string&& rref5 = move(s1);

引用的意义是减少拷贝,提高效率。

完美转发:

右值引用,引用后,右值引用本身属性变成左值,所以使用完美转发std::forward<T>(t)在传参的过程中保持了t的原生类型属性。

cpp 复制代码
void Fun(int& x) { cout << "
左值引⽤
" << endl; }
 void Fun(const int& x) { cout << "const 
左值引⽤
" << endl; }
 void Fun(int&& x) { cout << "
右值引⽤
" << endl; }
 void Fun(const int&& x) { cout << "const 
右值引⽤
" << endl; }

 template<class T>
void Function(T&& t)
 {
 Fun(t);
 //Fun(forward<T>(t));//完美转发:传左值调左值函数,传右值调右值函数
 }

c++11新加了两个默认函数:移动构造函数和移动赋值运算符重载(没有实现移动构造,且没有实现拷贝构造,拷贝赋值重载,析构函数三者任意一个则会自动生成)。

lambda(本质是仿函数):

lambda表达式的格式: [capture-list] (parameters)-> return type {function boby }

capture-list\] :捕捉列表 (parameters) :参数列表 -\>return type :返回值类型 {function boby} :函数体 **lambda使用:** auto add1 = \[\](int a, int b)-\>int {return a + b; }; cout \<\< add1(1, 2) \<\< endl; 捕捉列表的使用: ```cpp //捕捉列表 // auto swap2 = [a, b]() mutable // { // int tmp = a; // a = b; // b = tmp; // }; // // 引用方式捕捉 // auto swap3 = [&a, &b]() // { // int tmp = a; // a = b; // b = tmp; // }; //int main() //{ // int a = 1, b = 2, c = 3, d = 4, e = 5; // // 传值捕捉所有对象 // auto func1 = [=]() // { // return a + b + c * d; // }; // // // 传引用捕捉所有对象 // auto func2 = [&]() // { // a++; // b++; // c++; // d++; // e++; // }; // 混合捕捉,传引用捕捉所有对象,但是d和e传值捕捉 // auto func3 = [&, d, e]() // { // a++; // b++; // c++; // //d++; // //e++; // }; // // a b传引用捕捉,d和e传值捕捉 // auto func4 = [&a, &b, d, e]() mutable // { // a++; // b++; // d++; // e++; // }; // return 0; //} ``` **模板的可变参数:** C++11⽀持可变参数模板,也就是说⽀持可变数量参数的函数模板和类模板,可变数⽬的参数被称 为参数包,存在两种参数包:模板参数包,表⽰零或多个模板参数;函数参数包:表⽰零或多个函 数参数。 template \ void Func(Args... args) { } 代码示例: ```cpp template void Cpp_Printf(Args... args) { // 计算参数包的数据个数 cout << sizeof...(args) << endl; } int main() { Cpp_Printf(1); Cpp_Printf(1, 'A'); Cpp_Printf(1, 'A', std::string("sort"));//参数是可变的。 return 0; } ``` 编译时递归推导。 **包装器:** function是在头文件\,它的优势就是统⼀类型, std::function 是⼀个类模板,也是⼀个包装器。 std::function 的实例对象可以包装存储其他的可以调⽤对象,包括函数指针、仿函数、 lambda 等。 用法如下: ```cpp #include #include using namespace std; int f(int a, int b) { return a + b; } struct Functor { public: int operator() (int a, int b) { return a + b; } }; int main() { //不是定义可调用对象,而是包装可调用对象,也需要定义对象,例如fc1,fc2,fc3。 // 返回值类型 形参类型 function fc1 = f;//包装函数指针 function fc2 = Functor();//包装仿函数 function fc3 = [](int a, int b) {return a + b; };//包装lambada cout << fc1(1, 2) << endl; cout << fc2(1, 2) << endl; cout << fc3(1, 2) << endl; return 0; } ``` bind用法: ```cpp auto f5 = bind(&Sub::sub, &sub, placeholders::_1, placeholders::_2); cout << f5(10, 5) << endl; //placeholders::_1是第一个参数,placeholders::_2是第二个参数 //也可以将某个参数绑死。函数只传两个参数, placeholders::_1仍是第一个参数,placeholders::_2是第二个参数 auto f6 = bind(fx, "王昭君", placeholders::_1, placeholders::_2); f6(80, 20); ``` **智能指针:** unique_ptr\ sp1(new A\[10\]);//A是自定义类型 share_ptr\ sp2(new int\[10\]) share_ptr(共享指针)智能指针的实现: pcount统计访问该资源的个数。 ```cpp template class shared_ptr { public: shared_ptr(T* ptr) :_ptr(ptr) , _pcount(new atomic(1)) {} // sp2(sp1) shared_ptr(const shared_ptr& sp) :_ptr(sp._ptr) , _pcount(sp._pcount) { (*_pcount)++; } void release() { if (--(*_pcount) == 0) { // 如果是最后一个管理的对象,释放资源 delete _ptr; delete _pcount; } } // sp1 = sp3; shared_ptr& operator=(const shared_ptr& sp) { //if (this != &sp) if (_ptr != sp._ptr) { this->release(); _ptr = sp._ptr; _pcount = sp._pcount; ++(*_pcount); } return *this; } ~shared_ptr() { release(); } int use_count() { return *_pcount; } T& operator*() { return *_ptr; } T* operator->() { return _ptr; } private: T* _ptr; atomic* _pcount;//使用指针是因为所有对象都需要访问,可能多个对象访问同一个count。 }; ``` 特殊类的设计: 单例模式:全局只有唯一的对象 1.饿汉模式;2.懒汉模式 饿汉模式的缺点:问题1:很多单例类,都是饿汉模式,有些单例对象初始化资源很多,导致程序启动慢,迟迟进不了main函数,问题2: 如果两个单例类有初始化依赖关系,饿汉也无法解决。 ```cpp // 饿汉模式 : 一开始就(main函数之前)就创建对象 class ConfigInfo { public: static ConfigInfo* GetInstance() { return &_sInfo; } string GetIp() { return _ip; } void SetIp(const string& ip) { _ip = ip; } private://构造私有化 ConfigInfo() { cout << "ConfigInfo()" << endl; } ConfigInfo(const ConfigInfo&) = delete;//不进行拷贝构造 ConfigInfo& operator=(const ConfigInfo&) = delete; private: string _ip = "127.0.0.1"; int _port = 80; // 声明 static ConfigInfo _sInfo;//创建一个静态对象 }; ConfigInfo ConfigInfo::_sInfo;//静态成员类里面声明,类外面定义。 ``` 懒汉模式: ```cpp // 懒汉:第一次调用GetInstance时创建单例对象,后面就不需要了。 class ConfigInfo { public: static ConfigInfo* GetInstance() { if (_spInfo == nullptr) //双线程设计 { unique_lock lock(_mtx); if (_spInfo == nullptr) // 线程安全 { _spInfo = new ConfigInfo; } } return _spInfo; } string GetIp() { return _ip; } void SetIp(const string& ip) { _ip = ip; } private: ConfigInfo() { cout << "ConfigInfo()" << endl; } ConfigInfo(const ConfigInfo&) = delete; ConfigInfo& operator=(const ConfigInfo&) = delete; private: string _ip = "127.0.0.1"; int _port = 80; //... static ConfigInfo* _spInfo; static mutex _mtx; }; ConfigInfo* ConfigInfo::_spInfo = nullptr; mutex ConfigInfo::_mtx; ``` **类型转换:** C语言: 隐式类型转换:整形之间 浮点数和整形之间 强制类型转换:指针之间 整形和指针 没有关联类型是不支持转换的 c++: 兼容C的转换用法(隐式和强制) 内置类型 -\> 自定义类型 ```cpp class A { public: A(int a1) :_a1(a1) {} A(int a1, int a2) :_a1(a1) , _a2(a2) {} operator int()//转int类型需要重载 { return _a1 + _a2; } int get() const { return _a1 + _a2; } private: int _a1 = 1; int _a2 = 1; }; class B { public: B(const A& aa)//构造函数进行自定义类型之间的转换 :_b1(aa.get()) {} private: int _b1; }; int main() { // 内置类型 -> 自定义类型 A aa1 = 1; A aa2 = {2,2}; // 自定义类型 -> 内置类型 int x = aa1; cout << x << endl; // 自定义类型 -> 自定义类型 B bb = aa1; return 0; } ``` c++11提供的: ```cpp int i = 1; // 隐式类型转换 : static_cast double d = static_cast(i); int* p = &i; // 显示的强制类型转换 : reinterpret_cast int address = reinterpret_cast(p); ``` ```cpp //const_cast主要是处理const修饰的对象 const int a = 1; int* ptr = const_cast(&a); (*ptr)++; ``` ```cpp class A { public: virtual void f() {} int _a1 = 1; }; class B : public A { public: int _b1 = 1; }; void fun(A* pa) { // pa指向B对象,转换成功 // pa指向A对象,转换失败,返回空 B* pb = dynamic_cast(pa);//前提是父类必须是虚函数 if (pb) { cout << pb << endl; pb->_b1++; } else { cout << "转换失败" << endl; } } ```

相关推荐
_r0bin_几秒前
前端面试准备-7
开发语言·前端·javascript·fetch·跨域·class
zhang98800001 分钟前
JavaScript 核心原理深度解析-不停留于表面的VUE等的使用!
开发语言·javascript·vue.js
Fanxt_Ja2 小时前
【JVM】三色标记法原理
java·开发语言·jvm·算法
蓝婷儿2 小时前
6个月Python学习计划 Day 15 - 函数式编程、高阶函数、生成器/迭代器
开发语言·python·学习
love530love2 小时前
【笔记】在 MSYS2(MINGW64)中正确安装 Rust
运维·开发语言·人工智能·windows·笔记·python·rust
南郁2 小时前
007-nlohmann/json 项目应用-C++开源库108杰
c++·开源·json·nlohmann·现代c++·d2school·108杰
slandarer3 小时前
MATLAB | 绘图复刻(十九)| 轻松拿捏 Nature Communications 绘图
开发语言·matlab
狐凄3 小时前
Python实例题:Python计算二元二次方程组
开发语言·python
roman_日积跬步-终至千里3 小时前
【Go语言基础【3】】变量、常量、值类型与引用类型
开发语言·算法·golang
roman_日积跬步-终至千里3 小时前
【Go语言基础】基本语法
开发语言·golang·xcode