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++2.0特性 -> 正文阅读

[C++知识库]C++2.0特性

C++11/14


提示:这里可以添加本文要记录的大概内容:

Header files

C++标准库的header files不带副档名(.h),例如#include<vector>
新型C header files 不带副名称.h,例如#include<cstdio>
旧型C header files 带副名称,仍可用,例如#include<stdlib.h>

简单测试VS2018的支持C++版本

#include<vector>   //C++标准库
#include<iostream>
#include<cstdio>  //新式c header files
#include<stdlib.h> //旧式c header files仍然可用

using namespace std;
int main() {
	cout << __cplusplus << endl;
}

在这里插入图片描述
调节项目属性,改起支持C++14:
在这里插入图片描述

Variadic Templates

可以很方便的完成recursive function call

void print() {

} //相当于递归的终止
template<class T, typename... Type>
void print(const T first, const Type&... args) {
	cout << first << endl;
	print(args...);  //调用自身 类似于递归
}

template<typename... Type>
void print(const Type& ... args) {
	//
}

int main() {
	//cout << __cplusplus << endl;
	print(1, "hello", 'c', bitset<16>(377));
}

成功输出:
在这里插入图片描述

应用于Hash映射

class Customer {
public:
	string fname;
	string lname;
	int no;
};

template<typename T>
inline void hash_combine(size_t& seed, const T& val) {
	seed ^= std::hash<T>() + 0x9e3779b9
		+ (seed << 6) + (seed >> 2);  //建立哈希映射
}

template<typename T, typename... Type>
inline void hash_val(size_t& seed, const Type&... args) {
	hash_combine(seed, val);
	hash_val(seed, args...);
}

template<typename... Type>
inline size_t hash_val(const Type& ... args) {
	size_t seed = 0;
	hash_val(seed, args...);
	return seed;
}

class CustmerHash {
public:
	std::size_t operator()(const Customer& c) const {
		return hash_val(c.fname, c.lname, c.no);
	}
};

Tuple的实现

template<typename... Values> class  tuple;
template<> class tuple<> {};

template<typename Head, typename... Tail>
class tuple<Head, Tail...>
	:private tuple<Tail...> 
{
	typedef tuple<Tail...> inherited;
public:
	tuple() {}
	tuple(Head v, Tail... vtail)
		:m_Head(v), inherited(vtail...) {}
	typename Head::type head() { return m_Head; }
	inherited& tail() { return *this; }
protected:
	Head m_Head;
};

部分细节

Spaces in Template Expressions

vector<list<int> >;  //OK in each C++ Version
vector<list<int>>;  //OK since C++11

nullptr and std::nullptr_t

C++允许使用nullptr代替0NULL

void f(int);
void f(void*);
f(0); //调用第一个函数
f(NULL); //如果NULL为0 调用第一个 否则会产生歧义
f(nullptr); //调用第二个

\include\stddef.h

typedef declttype(nullptr) nullptr_t;

auto用法

auto可以让编译器进行自行推导;
type比较复杂时可以进行使用

	vector<string> v;
	auto pos = v.begin();
	auto l = [](int x)->bool {
		//do someting   lambda表达式
	};

Uniform Initialization

其实编译器看到{t1,t2,t3....}都在做一件事情,做出来一个initializer_list<T>,它关联到一个array<T, n>,调用函数时候该array元素可以被编译器分解逐一传给函数,但如果函数参数是一个initializer_list<T>,调用者却不能给予

	int values[]{ 1,2,3 };
	vector<int> v{ 2,3,5,7 };
	vector<string> cities{
		"Berlin", "Beijing", "London"
	};
	complex<double>c{ 4.0,3.0 }; // equivalend to c(4.0, 4.0);

Initializer Lists

int i;   // undefined value
int j{};  // j = 0
int* p;   //undefined value
int* q{}; // q = 0;

但是,编译器不允许进行类型转换

int x1(5.3);
int x2 = 5.2;
int x3{5.0};   //Error narrowing 在GCC上warning
int x4 = {5.2}; //Error narrowing

例子使用:


class P 
{
public:
	P(int a, int b) {
		cout << "P(int, int), a = " << a << " , b = " << b << endl;
	}
	P(initializer_list<int> initlist) {
		cout << "P(initializer_list<int>), values= ";
		for (auto i : initlist) {
			cout << i << endl;
		}
	}

};

P p(77, 5);  //调用第一个
P q{77, 5};  //调用第二个
P r{3, 77, 5};  //调用第二个
P s = {77, 5};  //调用第二个

如果只有构造函数1,那么编译器会将list个数为2的拆解,调用构造函数1,例如q与s会正常运行,利用构造函数1被赋值。

explicit for ctors taking more than one argument

主要用于构造函数,防止隐式的转换

class P 
{
public:
	P(int a, int b) {
		cout << "P(int, int), a = " << a << " , b = " << b << endl;
	}
	
	P(initializer_list<int> initlist) {
		cout << "P(initializer_list<int>), values= ";
		for (auto i : initlist) {
			cout << i << endl;
		}
	}
	explicit P(int a, int b, int c) {
		cout << "explicit(int a, int b, int c)\n";
	}
};

	P p1(77, 5);
	P p2{ 77, 4 };
	P P5 = (33, 2, 1); //Error 不存在合适的构造函数

range-based for statement

for( decl : coll){
    statement;
}

实际上编译器会这样做:

forauto _pos = coll.begin(), _end = coll.end(); _pos != _end; ++_pos){
    decl = *_pos;
    statement;
}
class C {
public:
	explicit C(const string& s);
};
	
vector<string> vs;
for (const C& elem : vs) {
	cout << elem << endl;
}  //error 无法进行类型转换

=default, = delete

=delete是需要这个函数;
=default是使用编译器给的版本;

class Zoo 
{
private:
	int d1, d2;
public:
	Zoo(int i1, int i2) {}
	Zoo(const Zoo&) = delete;
	Zoo(Zoo&&) = default;
	Zoo& operator=(const Zoo&) = default;
	Zoo& operator=(const Zoo&&) = delete;
	virtual ~Zoo() {}
};

C++编译器会给类的一些函数提供默认版本,拷贝构造函数、复制构造函数、无参数构造函数以及析构函数。

如果一个类带有pointer则一定需要Big-Three(拷贝构造、复制构造以及析构),如果没有指针,则大部分都不需要进行复写Big- Three;

对于string,一定有Big-Three,而且有Big-Five;

No-Copy and Private-Copy

struct NoCopy
{
	NoCopy() = default;
	NoCopy(const NoCopy&) = delete;
	NoCopy& operator=(const NoCopy&) = delete;
	~NoCopy() = default;
	//other members
};
class PrivateCopy {
private:
	PrivateCopy(const PrivateCopy&);
	PrivateCopy& operator=(const PrivateCopy&);
	//把拷贝构造、赋值构造放在private中
	//friends和members可以进行copy
public:
	PrivateCopy() = default;
	~PrivateCopy();
};
struct NoDtor 
{
	NoDtor() = default;
	~NoDtor() = delete;
};
	NoDtor nd;
	NoDtor* p = new NoDtor();
	delete p;
	//都会报错 析构函数已经被删除

Alias Template

template <typename T>
using Vec = std::vector<T, Myalloc<T>>;
Vec<int> coll;//等同于 std::vector<int, Mylloc<int>>

下面的程序会报错:
Error:Container is not a template

template<typename Container, typename T>
void test_moveable(Container cntr, T elem) {
	Container<T> c;
	for (int long i = 0; i < 1000; ++i) {
		c.insert(c.end(), T());
	}
	Container<T> c1(c);
	Container<T> c2(std::move(c));
	c1.swap(c2);
}

采用function template + iterator + traits解决:

 template<typename Container>
void test_moveable(Container c) {
	typedef typename iterator_traits<typename Container::iterator>::value_type Valtype;
	for (int long i = 0; i < 1000; ++i) {
		c.insert(c.end(), Valtype());
	}
	Container c1(c);
	Container c2(std::move(c));
	c1.swap(c2);
}

template template parameter

template<typename T>
using Vec = vector<T, allocator<T>>;

template <typename T>
using Lst = list<T, allocator<T>>;

template <typename T>
using Deq = deque<T, allocator<T>>;
template<typename T, template<typename>typename Container>
class XCls
{
private:
	Container<T> c;
public:
	XCls() {
		for (long i = 0; i < 1000; ++i) {
			c.insert(c.end(), T());
		}
		Container<T> c1(c);
		Container<T> c2(std::move(c));
		c1.swap(c2);
	}				  
};
Xcls<MyString, vector> c1; //报错 因为vector参数是两个第一个是元素类型,
               //第二个是内存分配器,在这种情况下(模板模板参数)编译器没有办法推导
 //加上最上面的Alias Template
 XCls<MyString, Vec>v1;
 XCls<MyStrNoMove, Vec>v2;         

Type Alias

using func = void(*)(int, int);
void example(int, int){}
func fn = example;

using

//1.using-directives for namespaces and using-declearations for namespace members
using namespace std; //打开命名空间
using std::cout; //打开std::cout

//2.using-declearations for class members
//再定义一个类的时候 使用其他类里的定义的一些东西
protected:
   using _Base::_M_allocate;
   using _Base::_M_deallocate;

//3.type alias and alias template declaration(since C++11)
using func = void(*)(int, int);

noexcept

函数后面加上这个关键字,可以保证这个函数不会丢出异常;
如果有异常没有处理,会向上调用,程序终止

void foo() noexcept  -> void foo() noexcept(true);

移动构造函数不能抛出异常,这样才会被调用

class MyString 
{
private:
	char* _data;
	size_t _len;
public:
	MyString(MyString&& str) noexcept
		: _data(str._data), _len(str._len) {}
	MyString& operator=(MyString&& str)noexcept {
	    //...
		return *this;
	}

override

struct Base
{
	virtual void vfunc(float) {}
};

struct Derived1 :Base {
	virtual void vfunc(int) {}
};

struct Derived2:Base
{
	virtual void vfunc(float) override {} //覆盖基类虚函数
};

final

final表示最后,表示类不能被继承;虚函数不能被覆盖

struct Base1 final {};
struct  Derived3:Base1{}; //Error

struct Base2{
   virtual void f() final;
}
struct Derrived2:Base2{
   void f(); // Error
}

decltype

使用关键字,可以知道表达式的类型(typeof)

map<string, float> coll;
decltpye(coll)::value_type elem;

//1.to declare return types
template<typename T1, typename T2>
decltype(x + y) add(T1 x, T2 y); //先后顺序 编译不通过 C++2.0提供另一种方式

template<typename T1, typename T2>
auto add(T1 x, T2 y)->decltype(x + y); 

//2.in metaprogramming
tyoedef typename decltype(obj)::iterator iType;
//等同于
typedef typename T::iterator iType;

//3.pass the type of a lambda
auto cmp = [](const Person& p1, const Person& p2){
             //比较方式
             return .....//自定义比较方式
}

std::set<Person, decltype(cmp)> coll(cmp);

Lambdas

[...](...)mutable throw -> retType{...}

[]{
   std::cout<<"hello lambda"<<std::endl;
}(); //()直接调用

auto l = []{
   std:: cout << "hello lambda" << endl;
};

l(); //调用lambda表达式

//必须加上mutable关键字才能在局部范围内修改id,因为是pass by value,真正的id并不会改变
int id = 0;
	auto f = [id]()mutable {
		std::cout << id << std::endl;
		++id;
	};

//调用时候实际类似于如下效果
class Functor{
private:
    int id;
public:
    void oprator()(){
        std::cout << id << std::endl;
        ++id;
    }
}

Variadic Templates

利用函数参数个数(类型)的逐渐递减来完成函数的递归
例1:如上

void print() {

} //相当于递归的终止
template<class T, typename... Type>
void print(const T first, const Type&... args) {
	cout << first << endl;
	print(args...);  //调用自身 类似于递归
}

template<typename... Type>
void print(const Type& ... args) {
	//
}

int main() {
	//cout << __cplusplus << endl;
	print(1, "hello", 'c', bitset<16>(377));
}

例子2:

int* pi = new int;
printf("%d %s %p %f\n", 15, "This is Ace", "pi", "3.1415926");

void printf(const char* s) {
	while (*s) {
		if (*s == '%' && *(++s) != '%') {
			throw std::runtime_error("invalid format string :: missing argument");
		}
		std::cout << *s++;
	}
}
template<typename T, typename... Args>
void printf(const char* s, T value, Args... args) {
	while (*s) {
		if (*s == '%' && *(s++) != '%') {
			std::cout << value;
			printf(++s, args...);
			return;
		}
		std::cout << *s++;
	}
	throw std::logic_error("extra arguments provided to printf()");
}

例子3:
参数类型一样,个数不定,直接使用initializer_list就可以。

cout << max({57, 48, 60, 100, 20, 18}); //底层实现是*max_element(begin(), end());

例子4:

int maxinum(int n) {
	return n;
}
template<typename... Args>
int maxinum(int n, Args... args) {
	return std::max(n, maxinum(args...));
}

cout << maxinum(57, 48, 60, 100, 20, 18) << endl;

例子5:递归输出
sizeof...()可以获得元素个数

template<typename... Args>
ostream& operator<<(ostream& os, const tuple<Args...>& t) {
	os << "[";
	PRINT_TUPLE<0, sizeof...(Args), Args...>::print(os, t);
	os << "]";
}

template<int IDX, int MAX, typename... Args>
struct PRINT_TUPLE
{
	static void print(ostream& os, const tuple<Args...>& t) {
		os << get<IDX>(t) << (IDX + 1 == MAX ? "" : ",");
		PRINT_TUPLE<IDX + 1, MAX, Args...>::print(os, t);
	}
}; 

template<int MAX, typename...Args>
struct PRINT_TUPLE
{
	static void print(std::ostream& os, const tuple<Args...>& t) {}
}; 

cout<<make_tuple<7.5, string("hello")22>;
//效果 输出 [7.5,heelo,22]

例子6:递归继承

template<typename... Values> class  tuple;
template<> class tuple<> {};

template<typename Head, typename... Tail>
class tuple<Head, Tail...>
	:private tuple<Tail...> 
{
	typedef tuple<Tail...> inherited;
public:
	tuple() {}
	tuple(Head v, Tail... vtail)
		:m_Head(v), inherited(vtail...) {}
	auto head()->decltype(m_Head) { return m_Head; }
	inherited& tail() { return *this; }
protected:
	Head m_Head;
};

Rvalue references

右值引用

class MyString {
public:
	static size_t DCtor;  //累计default-ctor次数
	static size_t Ctor;   //累计ctor呼叫次数
	static size_t CCtor;  //累计copy-ctor呼叫次数
	static size_t CAsgn;  //累计copy-assign
	static size_t MCtor;  //累计move-ctor
	static size_t MAsgn;  //累计move-assign
	static size_t Dtor;   //累计dtor
private:
	char* _data;
	size_t _len;
	void init_data(const char* s) {
		_data = new char[_len + 1];
		memcpy(_data, s, _len);
		_data[_len] = '\0';
	}
public:
	MyString() :_data(nullptr), _len(0) { ++Dtor; }

	MyString(const char* p) :_len(strlen(p)) {
		++Ctor;
		init_data(p);
	}
	MyString(const MyString& str) : _len(str._len) {
		++CCtor;
		init_data(str._data);  //Copy
	}
	MyString(MyString&& str) :_data(str._data), _len(str._len){
		str._data = nullptr;  //很重要
		str._len = 0;
	}
	MyString& operator=(MyString& str) noexcept {
		++CAsgn;
		if (this != &str) {
			if (_data) delete _data;
			_len = str._len;
			init_data(str._data);
		}
		else {}
		return *this;
	}

	MyString& operator=(MyString&& str) noexcept {
		++MAsgn;
		if (this != &str) {
			if (_data) delete _data;
			_len = str._len;
			_data = str._data;
			str._data = NULL;
			str._len = 0;
		}
		return *this;
	}
	virtual ~MyString() {
		++Dtor;
		if (_data) {
			delete _data;
		}
	}
};
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-09-19 07:48:45  更:2021-09-19 07:48:52 
 
开发: 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年12日历 -2024/12/28 12:28:07-

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