IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++ C11新特性 -> 正文阅读

[C++知识库]C++ C11新特性

move移动构造如何实现

class MyString
{
	char* str;
public:
	MyString(const char* p = NULL) :str(NULL)
	{
		if (p != NULL)
		{
			int len = strlen(p) + 1;
			str = new char[len];
			strcpy_s(str, len, p);
		}
	}
	MyString(const MyString& s) :str(NULL)
	{
		if (s.str != NULL)
		{
			int len = strlen(s.str) + 1;
			str = new char[len];
			strcpy_s(str, len, s.str);
		}
	}
	MyString(MyString&& s) :str(s.str)
	{
		s.str = NULL;
	}
	~MyString()
	{
		if (str != NULL)
		{
			delete[]str;
		}
		str = NULL;
	}
};

//泛化版本
template<class _Ty>
struct my_remove_reference
{
	using type = _Ty;
	using _Const_thru_ref_typ = const _Ty;
};
//部分特化版本
template<class _Ty>
struct my_remove_reference<_Ty&>
{
	using type = _Ty;
	using _Const_thru_ref_type = const _Ty&;
};
template<class _Ty>
struct my_remove_reference<_Ty&&>
{
	using type = _Ty;
	using _Const_thru_ref_type = const _Ty&&;
};

//获取原始特性
template<class _Ty>
using my_remove_reference_t = typename my_remove_reference<_Ty>::type;

//原始类型转化右值引用
//并没有去除常性,常性引用调动移动构造,将调动普通构造
template<class _Ty>
my_remove_reference_t<_Ty>&& my_move(_Ty&& _Arg)
{
	return static_cast<my_remove_reference_t<_Ty&&>>(_Arg);	
}


int main()
{
	MyString s1("zyq");
	MyString s0("hello");
	const MyString& s2 = s0;    // lvalue reference
	MyString&& ss = MyString("hello"); //rvalue reference -> 具名 lvalue
	
	MyString s3(my_move(s1));
	MyString s4(my_move(s2));
	//MyString s3(MyString(&&s1));
}

my_remove_reference 主要作用是消除引用,保留原生类型

template<class _Ty>
my_remove_reference_t<_Ty>&& my_move(_Ty&& _Arg)
{
	return static_cast<my_remove_reference_t<_Ty&&>>(_Arg);
	
}

这一部分,首先消除引用特质,保留原生状态,再进行强转为右值引用,若对常量进行移动拷贝,则调用的实际为拷贝构造

在这里插入图片描述
加入const 后意义会改变

int&& r = 10;        // 右值引用
const int&& x = 100; //const int & 左值常性引用

C++ 类型强转

c语言中的类型强转

int main()
{
	int a = 10;
	const int b = 20;
	int *pa = &a;
	int *pb = (int*) &b;

	float ft = 12.23;
	a = (int)ft;

	float* fp = &ft;
	int* ip = (int *) fp;
}

所有的转换都是一个括号强转,但是我们不清楚这样做的目的

继而有了C++的类型转换

  • 数据类型的转换(值的转换) static_cast
int main()
{t
	int a = 10;
	float ft = 12.23;

	a = static_cast<int>(ft);
	ft = static_cast<float>(a); //等价 ft = (float)a;
}
  • 去除常性的转换 const_cast
int main()
{
	const int a = 10;
	int* p = const_cast<int*> &a;
	//p = static_cast<int*>(&a); 错误!!!

	p = (int*)&a;
}
  • 重新解释转换 reinterpret_cast
int main()
{
	int a = 10;
	int* p = &a;
	char* cp = reinterpret_cast<char*>(&a);
	//使用char类型对&a重新解释
}
  • 动态转换 dynamic_cast
class Object
{
public:
	virtual void fun(){}
};
class Base: public Object
{
public:
	virtual void fun(){}
};

int main()
{
	Object* op = NULL;
	Base* bp = NULL;
	
	Object obj;
	Base base;
	
	op = dynamic_cast<Object*> (&base);
	//bp = &obj  error!!!
	//bp = dynamic_cast<Base*>(&obj)  error!!!
}

模板编译分裂性

template<int inst>
class Base
{
protected:
	static int num;
public:
	Base()
	{
		num += 1;
	}
	int GetNum()
	{
		return num;
	}
};
template<int inst>
int Base<inst>::num = 0;
int main()
{
	Base<0> b1;
	Base<0> b2;
	cout << b1.GetNum() << endl;
	Base<1> c1;
	Base<1> c2;
	Base<1> c3;
	cout << c1.GetNum() << endl;
}

编译器在编译过程中,首先根据Base<0> b1; 产生0版本的模板类型

class Base<0>
{
protected:
	static int num;
public:
	Base()
	{
		num += 1;
	}
	int GetNum()
	{
		return num;
	}
};
int Base<0>::num = 0;

紧接着也会产生一个1版本的Base

class Base<1>
{
protected:
	static int num;
public:
	Base()
	{
		num += 1;
	}
	int GetNum()
	{
		return num;
	}
};
int Base<1>::num = 0;

在这里插入图片描述

未定义类型

行为未定义规则,可以区分 _Ty 原有右值与左值

template<class _Ty>
void fun(_Ty&& a) //模板+右值引用 行为未定义
{
	
}
int main()
{
	fun(12);
	int a = 10;
	fun(a);
	const int& b = a;
	int& x = a;
	fun(x);
	fun(b);
}

完美转发如何实现

template<class _Ty>
struct my_remove_reference
{
	my_remove_reference() { cout << "_Ty" << endl; }
	using type = _Ty;
	using _Const_thru_ref_typ = const _Ty;
};
template<class _Ty>
struct my_remove_reference<_Ty&>
{
	my_remove_reference() { cout << "_Ty&" << endl; }
	using type = _Ty;
	using _Const_thru_ref_type = const _Ty&;
};
template<class _Ty>
struct my_remove_reference<_Ty&&>
{
	my_remove_reference() { cout << "_Ty&&" << endl; }
	using type = _Ty;
	using _Const_thru_ref_type = const _Ty&&;
};

template<class _Ty>
using my_remove_reference_t = typename my_remove_reference<_Ty>::type;

template<class _Ty>
my_remove_reference_t<_Ty>&& my_move(_Ty&& _Arg) //未知引用概念
{
	return static_cast<my_remove_reference_t<_Ty>&&>(_Arg); //强转右值引用
}

template<class _Ty>
_Ty&& my_forward(my_remove_reference_t<_Ty>& _Arg)
{
	return static_cast<_Ty&&>(_Arg);
}
template<class _Ty>
_Ty&& my_forward(my_remove_reference_t<_Ty>&& _Arg)
{
	return static_cast<_Ty&&>(_Arg);
}

void print(int &a)
{
	cout << "int a" << endl;
}
void print(const int  &a)
{
	cout << "const int &a" << endl;
}
void print(int &&a)
{
	cout << "int &&a" << endl;
}

template<class _Ty>
void fun(_Ty&& a)
{
	print(my_forward<_Ty>(a));
}
int main()
{
	int a = 10;
	int& b = a;
	int&& c = 10;
	const int& d = a;
	fun(a);
	fun(b);
	fun(c);
	fun(d);
	fun(20);
}

当我们将值类型传入fun(),接着进入完美转发,进入到下面的函数

template<class _Ty>
_Ty&& my_forward(my_remove_reference_t<_Ty>& _Arg)
{
	return static_cast<_Ty&&>(_Arg);
}

紧接着对值类型原始状态提取,并强转与引用叠加依旧是一个值类型

b、c都是左值与上面同理,d属于常左值

最后一个fun(20);则属于右值,右值进入则作为右值传出
在这里插入图片描述

  1. 自身左值,参数为左值引用叠加为左值 (& + & => &)
  2. 自身左值,参数为右值引用叠加为左值 (& + && => &)
  3. 自身右值,参数为左值引用叠加为左值 (&& + & => &)
  4. 自身右值,参数为右值引用叠加为右值 (&& + && => &&)

auto

  • 自动推导类型
int main()
{
	auto x = 10;           //x => int
	auto p = new int(10);  //p => int*
	auto* s = new int(10); //auto = int

	//auto r; error!!!
	//auro int r; error!!!
	//const auto* ip = &x, u; error!!! 不许进行初始化
	//const auto* ip = &x, u = 12.23; error!!! 不允许二义性
}
int main()
{
	int x = 1;
	auto* a = &x;       //auto int
	auto b = &x;		//auto int *
	auto& c = x;		//auto int
	const int e = 10;	
	auto f = e;			//auto int
	auto& f2 = e;		//auto const int
}
  • auto 不能作为函数的参数类型,并且不能直接作为类成员变量类型
class Base
{
	auto val;    //error!!!
	static const auto num = 0;  //ok
	//静态常性,必须初始化 可以使用auto
	static const double dx = 12.23;//error!!!
}
void fun(auto x) //error!!!
{}
  • auto 不能作为集合类型
int main()
{
	auto ar[] = {12,23,34};//error!!!
	return 0; 
}

可以推演出返回的类型,接收迭代器

int main()
{
	std::map<int,string> ismap;
	auto it = ismap.begin();
}

预给值

class Test
{
	int a = 0; //预给值
	char* p = NULL;
public:
	Test() = default;
	Test(int x = 10):a(x){}
};
int main()
{
	Test t1(10);
	Test t2(20);
}

在对象创建,对a、p开辟空间,调动默认构造后才进行赋值

nullptr 和 NULL 的区别

首先看下面的代码

void fun(char*)
{
	cout << "fun(char *)" << endl;
}
void fun(int a)
{
	cout << "fun(int a)" << endl;
}

int main()
{
	fun(0);     //fun(int a); 
	fun(NULL);	//fun(char *);
	return 0;
}

我们推演出的结果应该为,fun(int a) 和 fun(char *) 但是实际情况如下
在这里插入图片描述
在这里插入图片描述

C++中对NULL的定义,C++中为0,否则为无类型指针
但是无论是0还是无类型,对于编译器都具有二义性,并都作为整型看待

而 nullptr 关键字属于一个空指针类型常量,那么nullptr可以为一切指针类型赋值

int main()
{
	fun(0);         //fun(int a); 
	fun(nullptr);	//fun(char *);
	return 0;
}

在这里插入图片描述
nullptr 的诞生就是为了解决 NULL 的二义性

typedef decltype(nullptr) nullptr_r;
nullptr_r a = nullptr;
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-04-26 11:24:29  更:2022-04-26 11:24:34 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 22:35:16-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码