C++ 11

发布于:2025-06-05 ⋅ 阅读:(16) ⋅ 点赞:(0)

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

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的原生类型属性。

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;

捕捉列表的使用:

//捕捉列表
//	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 <class ...Args>  void Func(Args... args) { }

代码示例:

template <class ...Args>
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是在头文件<functional>,它的优势就是统⼀类型,

std::function 是⼀个类模板,也是⼀个包装器。 std::function 的实例对象可以包装存储其他的可以调⽤对象,包括函数指针、仿函数、 lambda 等。

用法如下:

#include<functional>
#include<iostream>
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<int(int, int)> fc1 = f;//包装函数指针
	function<int(int, int)> fc2 = Functor();//包装仿函数
	function<int(int, int)> 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用法:

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<A[]> sp1(new A[10]);//A是自定义类型

share_ptr<int>  sp2(new int[10])

 share_ptr(共享指针)智能指针的实现:

pcount统计访问该资源的个数。

template<class T>
class shared_ptr
{
public:
	shared_ptr(T* ptr)
		:_ptr(ptr)
		, _pcount(new atomic<int>(1))
	{}

	// sp2(sp1)
	shared_ptr(const shared_ptr<T>& sp)
		:_ptr(sp._ptr)
		, _pcount(sp._pcount)
	{
		(*_pcount)++;
	}

	void release()
	{
		if (--(*_pcount) == 0)
		{
			// 如果是最后一个管理的对象,释放资源
			delete _ptr;
			delete _pcount;
		}
	}

	// sp1 = sp3;
	shared_ptr<T>& operator=(const shared_ptr<T>& 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<int>* _pcount;//使用指针是因为所有对象都需要访问,可能多个对象访问同一个count。
};

特殊类的设计:

单例模式:全局只有唯一的对象
1.饿汉模式;2.懒汉模式

饿汉模式的缺点:问题1:很多单例类,都是饿汉模式,有些单例对象初始化资源很多,导致程序启动慢,迟迟进不了main函数,问题2: 如果两个单例类有初始化依赖关系,饿汉也无法解决。

// 饿汉模式 : 一开始就(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;//静态成员类里面声明,类外面定义。

懒汉模式:

// 懒汉:第一次调用GetInstance时创建单例对象,后面就不需要了。
class ConfigInfo
{
public:
	static ConfigInfo* GetInstance()
	{
		if (_spInfo == nullptr)     //双线程设计
		{
			unique_lock<mutex> 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的转换用法(隐式和强制)

内置类型 -> 自定义类型

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提供的:

int i = 1;
// 隐式类型转换 : static_cast
double d = static_cast<double>(i);

int* p = &i;
// 显示的强制类型转换 : reinterpret_cast
int address = reinterpret_cast<int>(p);
//const_cast<int*>主要是处理const修饰的对象
const int a = 1;
int* ptr = const_cast<int*>(&a);
(*ptr)++;
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<B*>(pa);//前提是父类必须是虚函数
	if (pb)
	{
		cout << pb << endl;
		pb->_b1++;
	}
	else
	{
		cout << "转换失败" << endl;
	}
}