04C++核心编程(二-泛型编程)

Day08

笔记

1	函数模板
	1.1	泛型编程 – 模板技术 特点:类型参数化
	1.2	template< typename T >  告诉编译器后面紧跟着的函数或者类中出现T,不要报错,T是一个通用的数据类型
	1.3	实现通用两个数进行交换函数
	1.4	使用
		1.4.1	自动类型推导   必须要推导出一致的T才可以使用
		1.4.2	显示指定类型   mySwap<int>(a,b);
2	实现对char和 int类型数组进行排序
	2.1	利用模板技术 实现对char和int类型数组通用排序函数
3	函数模板和普通函数的区别以及调用规则
	3.1	区别
		3.1.1	如果使用自动类型推导,是不可以发生隐式类型转换的
		3.1.2	普通函数 可以发生隐式类型转换
	3.2	调用规则
		3.2.1	如果函数模板和普通函数都可以调用,那么优先调用普通函数
		3.2.2	如果想强制调用函数模板,可以使用空模板参数列表
		3.2.2.1	myPrint<>(a, b);
		3.2.3	函数模板也可以发生函数重载
		3.2.4	如果函数模板能产生更好的匹配,那么优先使用函数模板
4	模板的实现机制
	4.1	编译器并不是把函数模板处理成能够处理任何类型的函数
	4.2	函数模板通过具体类型产生不同的函数 ---  通过函数模板产生的函数 称为模板函数
	4.3	编译器会对函数模板进行两次编译,在声明的地方对模板代码本身进行编译,在调用的地方对参数替换后的代码进行编译。
5	模板局限性
	5.1	模板并不是真实的通用,对于自定义数据类型,可以使用具体化技术,实现对自定义数据类型特殊使用
	5.2	template<> bool myCompare(Person &a, Person &b)
6	类模板
	6.1		类模板和函数模板区别:
	6.2		1、类模板不可以使用自动类型推导,只能用显示指定类型
	6.3		2、类模板中 可以有默认参数
7	类模板中成员函数创建时机
	7.1	类模板中的成员函数  并不是一开始创建的,而是在运行阶段确定出T的数据类型才去创建
8	类模板做函数参数
	8.1	1、指定传入类型
		8.1.1	void doWork(Person <string, int>&p)
	8.2	2、参数模板化
		8.2.1	template<class T1, class T2>
		8.2.2	void doWork2(Person <T1, T2>&p)
	8.3	3、整个类 模板化
		8.3.1	template<class T>
		8.3.2	void doWork3( T &p)
	8.4	查看T数据类型
		8.4.1	typeid(T).name()
9	类模板碰到继承的问题以及解决
	9.1	必须要指定出父类中的T数据类型,才能给子类分配内存
	9.2	template<class T1 ,class T2>
	9.3	class Son2 :public Base2<T2>
10	类模板中的成员函数类外实现
	10.1	void Person<T1, T2>::showPerson()
11	类模板的分文件编写问题以及解决
	11.1	类模板中的成员函数,不会一开始创建,因此导致分文件编写时连接不到函数的实现,出现无法解析的外部命令错误
	11.2	解决方式1:
		11.2.1	直接包含.cpp文件 (不推荐)
	11.3	解决方式2:
		11.3.1	将类声明和实现写到同一个文件中,将文件的后缀名改为 .hpp 即可
12	类模板碰到友元的问题以及解决
	12.1	友元类内实现
		12.1.1		friend void printPerson(Person<T1, T2> &p)
	12.2	友元类外实现
	12.3	声明: 
		12.3.1	friend void printPerson2<>(Person<T1, T2> &p);
	12.4	实现:	
		12.4.1	template<class T1,class T2>
		12.4.2	void printPerson2(Person<T1, T2> &p){ 。。。}
	12.5	template<class T1,class T2>
	12.6	class Person;
	12.7	
	12.8	template<class T1,class T2>
	12.9	void printPerson2(Person<T1, T2> &p);
13	类模板应用 – 数组类封装
	13.1	将类写到 myArray.hpp中
	13.2	属性:
		13.2.1	T  * pAddress; 指向堆区数组指针
		13.2.2	int m_Capacity 数组容量
		13.2.3	int m_Size ;数组大小
	13.3	行为
		13.3.1	myArray(int capacity)
		13.3.2	myArray(const MyArray & arr)
		13.3.3	operator= 
		13.3.4	operator[] 
		13.3.5	~myArray()
		13.3.6	getCapacity 
		13.3.7	getSize
		13.3.8	pushback
14	

Code

01函数模板.c

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

// 利用模板实现通用交换函数
// T代表一个通用的数据类型,告诉编译器如果下面紧跟着的函数
// 或者类中出现T不要报错
template <typename T>   
void mySwap(T &a, T &b)
{
	T temp = a;
	a = b;
	b = temp;
}

// 模板不能单独使用,必须指定出T才可以使用
template <typename T>
void mySwap2()
{

}

void test01()
{
	int a = 10;
	int b = 20;
	char c = 'a';  // char 可以转成int类型 不可以转成int 类型引用

	// 1.自动类型推到,必须推导出一致的T数据类型,才可以正常使用模板
	mySwap(a, b);

	// 2.显示指定类型
	mySwap<int>(a, b);

	cout << "a = " << a << endl;
	cout << "b = " << b << endl;

	double d_a = 10.14;
	double d_b = 20.25;
	mySwap(d_a, d_b);

	cout << "d_a = " << d_a << endl;
	cout << "d_b = " << d_b << endl;


	mySwap2<int>();  // 必须告诉编译器T类型才可以调用
}

int main()
{
	test01();
	system("pause");
	return EXIT_SUCCESS;
}

02char和int类型数组进行排序.cpp

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

// 从大到小 选择排序
template <class T>   // typename 和 class 一样
void mySort(T arr[], int len)
{
	for (size_t i = 0; i < len; i++)
	{
		int max = i;  // 记录交换的下标
		for (size_t j = i + 1; j < len; j++)
		{
			if (arr[max] < arr[j])
			{
				max = j;
			}
		}
		if (i != max)
		{
			// 进行交换
			T temp = arr[max];
			arr[max] = arr[i];
			arr[i] = temp;
		}
	}
}

// 遍历打印
template <class T>
void foreachSort(T arr[], int len)
{
	for (size_t i = 0; i < len; i++)
	{
		cout << arr[i] << endl;
	}
}

void test01()
{
	char charArray[] = "helloworld";
	int length = strlen(charArray);
	mySort<char>(charArray, length);
	foreachSort<char>(charArray, length);

	//int intArray[] = {5, 7, 1, 4, 2, 3};
	//int len = sizeof(intArray) / sizeof(int);
	//mySort(intArray, len);
	//cout << len << endl;
	//foreachSort(intArray, len);
}

int main()
{
	test01();
	system("pause");
	return EXIT_SUCCESS;
}

02char和int类型数组进行排序.cpp

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

// 从大到小 选择排序
template <class T>   // typename 和 class 一样
void mySort(T arr[], int len)
{
	for (size_t i = 0; i < len; i++)
	{
		int max = i;  // 记录交换的下标
		for (size_t j = i + 1; j < len; j++)
		{
			if (arr[max] < arr[j])
			{
				max = j;
			}
		}
		if (i != max)
		{
			// 进行交换
			T temp = arr[max];
			arr[max] = arr[i];
			arr[i] = temp;
		}
	}
}

// 遍历打印
template <class T>
void foreachSort(T arr[], int len)
{
	for (size_t i = 0; i < len; i++)
	{
		cout << arr[i] << endl;
	}
}

void test01()
{
	char charArray[] = "helloworld";
	int length = strlen(charArray);
	mySort<char>(charArray, length);
	foreachSort<char>(charArray, length);

	//int intArray[] = {5, 7, 1, 4, 2, 3};
	//int len = sizeof(intArray) / sizeof(int);
	//mySort(intArray, len);
	//cout << len << endl;
	//foreachSort(intArray, len);
}

int main()
{
	test01();
	system("pause");
	return EXIT_SUCCESS;
}

03函数模板和普通函数的区别以及调用规则.cpp

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

//1、函数模板和普通函数的区别
template<class T>
T myAdd(T a, T b)
{
	return a + b;
}

int myAdd2(int a, int b)
{
	return a + b;
}
void test01()
{
	int a = 10;
	int b = 20;
	char c = 'c';
	//myAdd(a, c); //如果使用自动类型推导,是不可以发生隐式类型转换的

	cout << myAdd2(a, c) << endl; //普通函数 可以发生隐式类型转换
}


//2、函数模板和普通函数的调用规则
template<class T>
void myPrint(T a, T b)
{
	cout << "函数模板调用" << endl;
}

/*
函数模板通过具体类型产生不同的函数  --- 通过函数模板产生的函数  称为 模板函数
void myPrint(int a ,int b)
{
cout << "函数模板调用" << endl;
}

void myPrint(double a ,double b)
{
cout << "函数模板调用" << endl;
}
*/

template<class T>
void myPrint(T a, T b, T c)
{
	cout << "函数模板(T a, T b ,T c)调用" << endl;
}

void myPrint(int a, int b)
{
	cout << "普通函数调用" << endl;
}



void test02()
{
	//1、如果函数模板和普通函数都可以调用,那么优先调用普通函数
	int a = 10;
	int b = 20;
	//myPrint(a, b);

	//2、如果想强制调用函数模板,可以使用空模板参数列表
	myPrint<>(a, b);

	//3、函数模板也可以发生函数重载
	myPrint(a, b, 10);

	//4、如果函数模板能产生更好的匹配,那么优先使用函数模板
	char c = 'c';
	char d = 'd';
	myPrint(c, d);

}

int main() {

	//test01();

	test02();

	system("pause");
	return EXIT_SUCCESS;
}

04模板局限性.cpp

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
#include <string>
class Person
{
public:
	Person(string name, int age)
	{
		this->m_Name = name;
		this->m_Age = age;
	}
	string m_Name;
	int m_Age;

};

//显示两个变量 对比 函数
template<class T>
bool myCompare(T& a, T& b)
{
	if (a == b)
	{
		return true;
	}
	return false;
}

//利用具体化技术 实现对自定义数据类型 提供特殊模板
template<> bool myCompare(Person& a, Person& b)
{
	if (a.m_Name == b.m_Name && a.m_Age == b.m_Age)
	{
		return true;
	}
	return false;
}

void test01()
{
	//int a = 10;
	//int b = 10;

	//bool ret = myCompare(a, b);

	//if (ret )
	//{
	//	cout << "a == b" << endl;
	//}
	//else
	//{
	//	cout << "a != b" << endl;
	//}

	Person p1("Tom", 19);
	Person p2("Tom", 20);

	bool ret = myCompare(p1, p2);
	if (ret)
	{
		cout << "p1 == p2" << endl;
	}
	else
	{
		cout << "p1 != p2" << endl;
	}
}

int main() {

	test01();

	system("pause");
	return EXIT_SUCCESS;
}

05类模板.cpp

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
#include <string>
template<class NAMETYPE, class AGETYPE = int > //类模板中 可以有默认参数
class Person
{
public:
	Person(NAMETYPE name, AGETYPE age)
	{
		this->m_Name = name;
		this->m_Age = age;
	}

	void showPerson()
	{
		cout << "姓名: " << this->m_Name << " 年龄: " << this->m_Age << endl;
	}
	NAMETYPE m_Name;
	AGETYPE m_Age;
};

void test01()
{

	//类模板和函数模板区别:
	//1、类模板不可以使用自动类型推导,只能用显示指定类型
	//2、类模板中 可以有默认参数
	//Person p1("孙悟空", 100);

	Person<string > p1("孙悟空", 100);
	p1.showPerson();
}

int main() {

	test01();

	system("pause");
	return EXIT_SUCCESS;
}

06 类模板中的成员函数创建时机.cpp

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class Person1
{
public:
	void showPerson1()
	{
		cout << "Person1 show 调用" << endl;
	}
};

class Person2
{
public:
	void showPerson2()
	{
		cout << "Person2 show 调用" << endl;
	}
};


//类模板中的成员函数  并不是一开始创建的,而是在运行阶段确定出T的数据类型才去创建
template<class T>
class MyClass
{
public:
	void func1()
	{
		obj.showPerson1();
	}
	void func2()
	{
		obj.showPerson2();
	}

	T obj;
};

void test01()
{
	MyClass <Person2> p1;
	//p1.func1();
	p1.func2();
}

int main() {

	test01();

	system("pause");
	return EXIT_SUCCESS;
}  

07 类模板做函数参数.cpp

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
#include <string>
template<class T1, class T2> //类模板中 可以有默认参数
class Person
{
public:
	Person(T1 name, T2 age)
	{
		this->m_Name = name;
		this->m_Age = age;
	}

	void showPerson()
	{
		cout << "姓名: " << this->m_Name << " 年龄: " << this->m_Age << endl;
	}
	T1 m_Name;
	T2 m_Age;
};

//1、指定传入类型
void doWork(Person <string, int>& p)
{
	p.showPerson();
}

void test01()
{
	Person <string, int>p("孙悟空", 999);
	doWork(p);
}


//2、参数模板化
template<class T1, class T2>
void doWork2(Person <T1, T2>& p)
{
	cout << "T1数据类型: " << typeid(T1).name() << endl;
	cout << "T2数据类型: " << typeid(T2).name() << endl;
	p.showPerson();
}

void test02()
{
	Person<string, int>p("猪八戒", 998);
	doWork2(p);
}


//3、整个类 模板化
template<class T>
void doWork3(T& p)
{
	cout << "T的数据类型: " << typeid(T).name() << endl;
	p.showPerson();
}

void test03()
{
	Person<string, int>p("唐僧", 10000);
	doWork3(p);  // 均是采用自动推导
}

int main() {

	//test01();
	//test02();
	test03();

	system("pause");
	return EXIT_SUCCESS;
}

08类模板碰到继承的问题及解决.cpp

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

template<class T>
class Base
{
public:
	T m_A;
};

//必须要指定出父类中的T数据类型,才能给子类分配内存
class Son :public Base<int>
{

};



template<class T>
class Base2
{
public:
	T m_A;
};

template<class T1, class T2>
class Son2 :public Base2<T2>
{
public:

	Son2()
	{
		cout << typeid(T1).name() << endl;
		cout << typeid(T2).name() << endl;
	}

	T1 m_B;
};

void test01()
{
	Son2 <int, double> s;

}

int main() {

	test01();

	system("pause");
	return EXIT_SUCCESS;
}

09类模板中的成员函数类外实现.cpp

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
#include <string>

template<class T1, class T2>
class Person
{
public:
	Person(T1 name, T2 age);
	//{
	//	this->m_Name = name;
	//	this->m_Age = age;
	//}

	void showPerson();
	//{
	//	cout << "姓名: " << this->m_Name << " 年龄:" << this->m_Age << endl;
	//}

	T1 m_Name;
	T2 m_Age;
};

template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age)
{
	this->m_Name = name;
	this->m_Age = age;
}

template<class T1, class T2>
void Person<T1, T2>::showPerson()
{
	cout << "姓名: " << this->m_Name << " 年龄:" << this->m_Age << endl;
}


void test01()
{
	Person <string, int>p("Tom", 10);
	p.showPerson();
}

int main() {

	test01();

	system("pause");
	return EXIT_SUCCESS;
}

10类模板中的成员函数分文件编写

头文件

  • person.hpp
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

template <class T1, class T2>
class Person
{
public:
	Person(T1 name, T2 age);
	void showPerson();

	T1 m_Name;
	T2 m_Age;
};



// 将模板函数的声明和实现写在一起



template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age)
{
	this->m_Name = name;
	this->m_Age = age;
}

template<class T1, class T2>
void Person<T1, T2>::showPerson()
{
	cout << "姓名: " << this->m_Name << " 年龄:" << this->m_Age << endl;
}

源文件

  • 10类模板中的成员函数分文件编写.cpp
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
#include"person.hpp"
#include<string>

void test01()
{
	Person<string, int> p("haha", 20);
	p.showPerson();
}

int main()
{
	test01();
	system("pause");
	return EXIT_SUCCESS;
}

11类模板碰到友元函数.cpp

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

template<class T1, class T2>
class Person;

template<class T1, class T2>  // 需要编译器先看到Person
void printPerson2(Person<T1, T2>& p);

template<class T1, class T2>  
void printPerson3(Person<T1, T2>& p)
{
	cout << p.m_Name << p.m_Age << endl;
}



template <class T1, class T2>
class Person
{
public:
	// 1. 友元函数 类内实现
	friend void printPerson(Person<T1, T2> &p)
	{
		cout << p.m_Name << p.m_Age << endl;
	}

	
	// 2. 友元函数 类外实现  --->模板声明需要编译器先看的
	friend void printPerson2<>(Person<T1, T2>& p);

	// 3.类外实现
	friend void printPerson3<>(Person<T1, T2>& p);

	Person(T1 name, T2 age)
	{
		this->m_Name = name;
		this->m_Age = age;
	}

	//void showPerson();
private:
	T1 m_Name;
	T2 m_Age;
};

template <class T1, class T2>
void printPerson2<>(Person<T1, T2>& p)
{
	cout << p.m_Name << p.m_Age << endl;
}


void test01()
{
	Person<string, int> p("haha", 15);
	// printPerson(p);
	printPerson3(p);

}


int main()
{
	test01();
	system("pause");
	return EXIT_SUCCESS;
}

12类模板应用-数组类封装

头文件

  • myArray.hpp
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

template <class T>
class MyArray
{
public:
	MyArray(int capacity)
	{
		this->m_Capacity = capacity;
		this->m_size = 0;
		this->pAddress = new T[this->m_Capacity];  // 如果在堆区开辟空间必须要默认构造
	}

	MyArray(const MyArray& p)
	{
		this->m_Capacity = p.m_Capacity;
		this->m_size = p.m_size;
		this->pAddress = new T[this->m_Capacity];
		for (size_t i = 0; i < p.m_size; i++)
		{
			this->pAddress[i] = p.pAddress[i];
		}
	}

	MyArray& operator=(MyArray& p)
	{
		// 先把原来的值删除掉
		if (this->pAddress)
		{
			delete[] this->pAddress;
			this->pAddress = NULL;
		}
		// 下面的操作同上
		this->m_Capacity = p.m_Capacity;
		this->m_size = p.m_size;
		this->pAddress = new T[this->m_Capacity];
		for (size_t i = 0; i < p.m_size; i++)
		{
			this->pAddress[i] = p.pAddress[i];
		}
		return *this;  // 返回本体
	}

	T& operator[](int index)
	{
		return this->pAddress[index];
	}

	int getCapacity()
	{
		return this->m_Capacity;
	}

	int getSize()
	{
		return this->m_size;
	}

	void pushBack(const T &value)  // 加const防止值修改
	{
		if (this->m_Capacity == this->m_size)
		{
			return;
		}
		this->pAddress[this->m_size] = value;
		this->m_size++;
	}


	~MyArray()
	{
		if (this->pAddress)
		{
			delete[] this->pAddress;
			this->pAddress = NULL;
		}
	}

private:
	T* pAddress;  // 指向堆区真实数组指针
	int m_Capacity;
	int m_size;
};
  • 12类模板应用-数组类封装.cpp
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
#include"myArray.hpp"
#include<string>

class Person
{
public:
	Person() {};  // 在堆区开辟的数组 必须要默认构造
	Person(string name, int age)
	{
		this->m_Name = name;
		this->m_Age = age;
	}

	string m_Name;
	int m_Age;
};



void myPrintInt(MyArray <int>& myIntArr)
{

	for (int i = 0; i < myIntArr.getSize(); i++)
	{
		cout << myIntArr[i] << endl;
	}
}

void test01()
{
	MyArray <int> myIntArr(100);
	for (int i = 0; i < 10; i++)
	{
		myIntArr.pushBack(i + 1);
	}
	myPrintInt(myIntArr);
}

void myPrintPerson(MyArray<Person>& myPersonArr)
{
	for (int i = 0; i < myPersonArr.getSize(); i++)
	{
		cout << "姓名: " << myPersonArr[i].m_Name << " 年龄:" << myPersonArr[i].m_Age << endl;
	}
}


void test02()
{
	MyArray<Person> myPersonArr(100);
	Person p1("孙悟空", 1000);
	Person p2("猪八戒", 800);
	Person p3("唐僧", 500);
	Person p4("沙悟净", 300);
	Person p5("白龙马", 10000);

	myPersonArr.pushBack(p1);
	myPersonArr.pushBack(p2);
	myPersonArr.pushBack(p3);
	myPersonArr.pushBack(p4);
	myPersonArr.pushBack(p5);

	myPrintPerson(myPersonArr);

	cout << "数组容量: " << myPersonArr.getCapacity() << endl;
	cout << "数组大小: " << myPersonArr.getSize() << endl;
}

int main()
{
	// test01();
	test02();
	system("pause");
	return EXIT_SUCCESS;
}

Day09

笔记

1	类型转换
	1.1	静态类型转换  static_cast
		1.1.1	允许内置数据类型转换
		1.1.2	允许父子之间的指针或者引用的转换
		1.1.3	语法 static_cast<目标类型>(原变量/原对象)
	1.2	动态类型转换  dynamic_cast
		1.2.1	不允许内置数据类型转换 
		1.2.2	允许父子之间指针或者引用的转换
			1.2.2.1	父转子  不安全的  转换失败
			1.2.2.2	子转父  安全   转换成功
			1.2.2.3	如果发生多态,总是安全,可以成功
		1.2.3	语法 dynamic_cast<目标类型>(原变量/原对象)
	1.3	常量转换   const_cast
		1.3.1	只允许 指针或者引用 之间转换
		1.3.2	语法 const	_cast<目标类型>(原变量/原对象)
	1.4	重新解释转换
		1.4.1	reinterpret_cast 最不安全一种转换,不建议使用
2	异常的基本语法
	2.1	C++异常的处理关键字
		2.1.1	try  throw  catch
	2.2	可以出现异常的代码 放到 try块
	2.3	利用throw抛出异常
	2.4	利用catch捕获异常
	2.5	catch( 类型) 如果想捕获其他类型 catch(…)
	2.6	如果捕获到的异常不想处理,而继续向上抛出,利用 throw
	2.7	异常必须有函数进行处理,如果都不去处理,程序自动调用 terminate函数,中断掉
	2.8	异常可以是自定义数据类型
3	栈解旋
	3.1	从try代码块开始,到throw抛出异常之前,所有栈上的数据都会被释放掉,
	3.2	释放的顺序和创建顺序相反的,这个过程我们称为栈解旋
4	异常的接口声明
	4.1	在函数中 如果限定抛出异常的类型,可以用异常的接口声明
	4.2	语法: void func()throw(int ,double)
	4.3	throw(空)代表 不允许抛出异常
5	异常变量的生命周期
	5.1	抛出的是 throw MyException();  catch (MyException e) 调用拷贝构造函数 效率低
	5.2	抛出的是 throw MyException();  catch (MyException &e)  只调用默认构造函数 效率高 推荐
	5.3	抛出的是 throw &MyException(); catch (MyException *e) 对象会提前释放掉,不能在非法操作
	5.4	抛出的是 new MyException();   catch (MyException *e) 只调用默认构造函数 自己要管理释放
6	异常的多态使用
	6.1	提供基类异常类
		6.1.1	class BaseException
		6.1.2	纯虚函数  virtual void printError() = 0;
	6.2	子类空指针异常 和  越界异常 继承 BaseException
	6.3	重写virtual void printError()
	6.4	测试 利用父类引用指向子类对象
7	系统标准异常
	7.1	引入头文件  #include <stdexcept>
	7.2	抛出越界异常 throw out_of_range(“…”)
	7.3	获取错误信息  catch( exception & e )     e.what();
8	编写自己的异常类
	8.1	编写myOutofRange 继承 Exception类
	8.2	重写 virtual const char *  what() const
	8.3	将sting 转为 const char * 
		8.3.1	 .c_str()
	8.4	const char * 可以隐式类型转换为 string  反之不可以
	8.5	测试,利用多态打印出错误提示信息
9	标准输入流
	9.1	cin.get() 获取一个字符
	9.2	cin.get(两个参数) 获取字符串
		9.2.1	利用cin.get获取字符串时候,换行符遗留在缓冲区中
	9.3	cin.getline() 获取字符串
		9.3.1	利用cin.getline获取字符串时候,换行符不会被取走,也不在缓冲区中,而是直接扔掉
	9.4	cin.ignore() 忽略 默认忽略1个字符, 如果填入参数X,代表忽略X个字符
	9.5	cin.peek()  偷窥  
	9.6	cin.putback()  放回 放回原位置
	9.7	案例1
		9.7.1	判断用户输入的内容 是字符串还是数字
	9.8	案例2
		9.8.1	用户输入 0 ~ 10 之间的数字,如果输入有误,重新输入
		9.8.2	标志位  cin.fail()   0代表正常  1代表异常
		9.8.3	cin.clear()  cin.sync() 清空缓冲区 重置标志位
10	标准输出流
	10.1	cout.put() //向缓冲区写字符
	10.2	cout.write() //从buffer中写num个字节到当前输出流中。
	10.3	通过 流成员函数 格式化输出
		10.3.1		int number = 99;
		10.3.2		cout.width(20); //指定宽度为20
		10.3.3		cout.fill('*'); //填充
		10.3.4		cout.setf(ios::left);  //左对齐
		10.3.5		cout.unsetf(ios::dec); //卸载十进制
		10.3.6		cout.setf(ios::hex);  //安装十六进制
		10.3.7		cout.setf(ios::showbase);  //显示基数
		10.3.8		cout.unsetf(ios::hex);  //卸载十六进制
		10.3.9		cout.setf(ios::oct);   //安装八进制
		10.3.10		cout << number << endl;
	10.4	通过控制符  格式化输出
		10.4.1	int number = 99;
		10.4.2		cout << setw(20)     //设置宽度
		10.4.3			<< setfill('~')  //设置填充
		10.4.4			<< setiosflags(ios::showbase)  //显示基数
		10.4.5			<< setiosflags(ios::left)  //设置左对齐
		10.4.6			<< hex   //显示十六进制
		10.4.7			<< number
		10.4.8			<< endl;
		10.4.9	引入头文件  #include< iomanip>
11	文件读写
	11.1	头文件  #inlcude < fstream>
	11.2	写文件  
	11.2.1	 ofstream  ofs (文件路径,打开方式  ios::out )
	11.2.2	判断文件是否打开成功  ofs.is_open
	11.2.3	ofs << “…”
	11.2.4	关闭文件  ofs.close();
	11.3	读文件
	11.3.1	ifstream  ifs(文件路径,打开方式  ios::in)
	11.3.2	判断文件是否打开成功  ofs.is_open
	11.3.3	利用4种方式 对文件进行读取
	11.3.4	关闭文件  ifs.close();	

Code

01类型转换.cpp

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

//1、静态类型转换  static_cast
void test01()
{
	//允许内置数据类型之间转换
	char a = 'a';

	double d = static_cast<double>(a);

	cout << d << endl;

}

class Base { virtual void func() {} };
class Son :public Base { virtual void func() {} };
class Other {};

void test02()
{
	Base* base = NULL;
	Son* son = NULL;

	//语法:   static_cast<目标类型>(原对象)
	//父子之间的指针或者引用可以转换
	//将base 转为 Son *   父转子  向下类型转换  不安全
	Son* son2 = static_cast<Son*> (base);

	//son  转为 Base*    子转父  向上类型转换  安全
	Base* base2 = static_cast<Base*>(son);


	//base 转为Other*
	//Other * other = static_cast<Other*>(base);  转换无效

}


//动态类型转换  dynamic_cast
void test03()
{
	//不允许内置数据类型之间转换
	//char c = 'c';
	//double d = dynamic_cast<double>(c);
}

void test04()
{
	Base* base = new Son;
	Son* son = NULL;

	//将base 转为 Son *  父转子 不安全  如果发生了多态,那么转换总是安全的
	Son* son2 = dynamic_cast<Son*>(base);


	//son 转为 Base*  子转父  安全
	Base* base2 = dynamic_cast<Base*>(son);

	//base 转 Other*
	//Other* other = dynamic_cast<Other*>(base); //无法转换
}

//常量转换  const_cast
void test05()
{
	//不可以将非指针或非引用做const_cast转换
	const int* p = NULL;
	int* pp = const_cast<int*>(p);

	const int* ppp = const_cast<const int*>(pp);


	//const int a = 10;
	//int b = const_cast<int>(a);


	int num = 10;
	int& numRef = num;

	const int& num2 = const_cast<const int&>(numRef);

}

//重新解释转换  reinterpret_cast 最不安全一种转换,不建议使用
void test06()
{
	int a = 10;
	int* p = reinterpret_cast<int*>(a);

	Base* base = NULL;
	//base 转 Other *
	Other* other = reinterpret_cast<Other*>(base);
}

int main() {

	test01();

	system("pause");
	return EXIT_SUCCESS;
}

02异常的基本语法.cpp

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
#include <string>

class MyException
{
public:
	void printError()
	{
		cout << "我自己的异常" << endl;
	}
};

class Person
{
public:
	Person()
	{
		cout << "Person的默认构造函数调用" << endl;
	}
	~Person()
	{
		cout << "Person的析构函数调用" << endl;
	}
};

int myDivision(int a, int b)
{
	if (b == 0)
	{
		//return -1;
		//throw 1; //抛出int类型的异常
		//throw 'a'; //抛出char类型的异常
		//throw 3.14; //抛出double类型的异常
		/*string str = "abc";
		throw str;*/


		//从try代码块开始,到throw抛出异常之前,所有栈上的数据都会被释放掉,
		//释放的顺序和创建顺序相反的,这个过程我们称为栈解旋
		Person p1;
		Person p2;


		throw MyException(); //抛出 MyException的匿名对象
	}

	return a / b;
}

void test01()
{
	int a = 10;
	int b = 0;

	//C语言处理异常 有缺陷:返回值不统一,返回值只有一个,无法区分是结果还是异常
	//int ret =myDivision(a, b);
	//if ( ret == -1)
	//{
	//	cout << "异常" << endl;
	//}

	try
	{
		myDivision(a, b);
	}
	catch (int)
	{
		cout << "int类型异常捕获" << endl;
	}
	catch (char)
	{
		cout << "char类型异常捕获" << endl;
	}
	catch (double)
	{
		//捕获到了异常,但是不想处理,继续向上抛出这个异常
		//异常必须有函数进行处理,如果没有任何处理,程序自动调用 terminate 函数,让程序中断
		throw;
		cout << "double类型异常捕获" << endl;
	}
	catch (MyException e)
	{
		e.printError();
	}
	catch (...)
	{
		cout << "其他类型异常捕获" << endl;
	}

}

int main() {

	try
	{
		test01();
	}
	catch (double)
	{
		cout << "double函数中 double类型异常捕获" << endl;
	}
	catch (...)
	{
		cout << "main函数中 其他类型异常捕获" << endl;
	}




	system("pause");
	return EXIT_SUCCESS;
}

03异常变量的生命周期.cpp

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class MyException
{
public:
	MyException()
	{
		cout << "MyException默认构造函数调用" << endl;
	}

	MyException(const MyException& e)
	{
		cout << "MyException拷贝构造函数调用" << endl;
	}

	~MyException()
	{
		cout << "MyException析构函数调用" << endl;
	}

};

void doWork()
{
	throw  new MyException();
}

void test01()
{
	try
	{
		doWork();
	}
	//1. 抛出的是 throw MyException();  catch (MyException e) 调用拷贝构造函数 效率低
	//2. 抛出的是 throw MyException();  catch (MyException &e)  只调用默认构造函数 效率高 推荐
	//3. 抛出的是 throw &MyException(); catch (MyException *e) 对象会提前释放掉,不能在非法操作
	//4. 抛出的是 new MyException();   catch (MyException *e) 只调用默认构造函数 自己要管理释放
	catch (MyException* e)
	{
		cout << "自定义异常捕获" << endl;
		delete e;
	}

}

// 2相当于引用是左值,因此匿名函数不会立刻释放掉
// 3相当于用指针指向那个对象 匿名函数会立刻释放掉

int main() {
	test01();


	system("pause");
	return EXIT_SUCCESS;
}

04异常的多态使用.cpp

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

//异常的基类
class BaseException
{
public:
	virtual void printError() = 0;
};

//空指针异常
class NULLPointerException :public BaseException
{
public:
	virtual void printError()
	{
		cout << "空指针异常" << endl;
	}
};

//越界异常
class OutOfRangeException :public BaseException
{
public:
	virtual void printError()
	{
		cout << "越界异常" << endl;
	}

};

void doWork()
{
	//throw NULLPointerException();
	throw OutOfRangeException();
}

void test01()
{
	try
	{
		doWork();
	}
	catch (BaseException& e)
	{
		e.printError();
	}
}


int main() {

	test01();

	system("pause");
	return EXIT_SUCCESS;
}

05系统标准异常.cpp

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
#include <stdexcept> //  std 标准  except 异常


class Person
{
public:
	Person(int age)
	{
		if (age < 0 || age > 150)
		{
			throw out_of_range("年龄必须在 0 ~ 150之间");
			//throw length_error("年龄必须在 0 ~ 150之间");
		}
		else
		{
			this->m_Age = age;
		}
	}

	int m_Age;
};

void test01()
{
	try
	{
		Person p(151);
	}
	//catch ( out_of_range &e)
	catch (exception& e)  // 使用多态的方式
	{
		cout << e.what() << endl;
	}

}

int main() {
	test01();


	system("pause");
	return EXIT_SUCCESS;
}

06编写自己的异常类.cpp

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class MyOutOfRangeException :public exception
{
public:

	MyOutOfRangeException(const char* str)
	{
		//const char * 可以隐式类型转换为 string  反之不可以
		this->m_errorInfo = str;
	}

	MyOutOfRangeException(string str)
	{
		this->m_errorInfo = str;
	}

	virtual const char* what() const
	{
		//将string 转为 const char * 
		return m_errorInfo.c_str();
	}

	string m_errorInfo;
};

class Person
{
public:
	Person(int age)
	{
		if (age < 0 || age > 150)
		{
			throw MyOutOfRangeException(string("年龄必须在0到150之间"));
		}
		else
		{
			this->m_Age = age;
		}
	}

	int m_Age;
};


void test01()
{
	try
	{
		Person p(1000);
	}
	catch (exception& e)  // 利用多态实现
	{
		cout << e.what() << endl;
	}


}

int main() {

	test01();

	system("pause");
	return EXIT_SUCCESS;
}

07标准输入流.cpp

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

/*
cin.get() //一次只能读取一个字符
cin.get(一个参数) //读一个字符
cin.get(两个参数) //可以读字符串
cin.getline()
cin.ignore()
cin.peek()
cin.putback()
*/
void test01()
{
	//输入  a  s     第一次 a  第二次  s  第三次 换行  第四次 等待下次输入
	char c = cin.get();

	cout << "c = " << c << endl;

	c = cin.get();

	cout << "c = " << c << endl;

	c = cin.get();

	cout << "c = " << c << endl;


	c = cin.get();

	cout << "c = " << c << endl;
}


void test02()
{
	char buf[1024] = { 0 };
	cin.get(buf, 1024);

	char c = cin.get();
	//利用cin.get获取字符串时候,换行符遗留在缓冲区中, 并且cin.get(buf, 1024);不取
	if (c == '
')
	{
		cout << "换行符遗留在缓冲区" << c << endl;
	}
	else
	{
		cout << "换行符不在缓冲区" << endl;
	}
	cout << buf << endl;

}

void test03()
{
	char buf[1024] = { 0 };

	//利用cin.getline获取字符串时候,换行符不会被取走,也不在缓冲区中,而是直接扔掉
	cin.getline(buf, 1024);

	char c = cin.get();
	if (c == '
')
	{
		cout << "换行符遗留在缓冲区" << endl;
	}
	else
	{
		cout << "换行符不在缓冲区" << endl;
	}
	cout << buf << endl;

}

//cin.ignore() 忽略 默认忽略1个字符, 如果填入参数X,代表忽略X个字符
void test04()
{
	cin.ignore(2);
	char c = cin.get();
	cout << "c = " << c << endl;
}

//cin.peek() 偷窥  -- 看一眼但是不拿走缓存区的数据
void test05()
{
	char c = cin.peek();
	cout << "c = " << c << endl;

	c = cin.get();
	cout << "c = " << c << endl;

	c = cin.get();
	cout << "c = " << c << endl;

}

//cin.putback() 放回
void test06()
{
	char c = cin.get();
	cin.putback(c);  // 返回原处
	char buf[1024] = { 0 };

	cin.getline(buf, 1024);
	cout << buf << endl;
}


//案例1、 判断用户输入的内容 是字符串还是数字  12345     abcde
void test07()
{
	cout << "请输入一个字符串或者数字" << endl;
	char c = cin.peek();

	if (c >= '0' && c <= '9')
	{
		int num;
		cin >> num;
		cout << "您输入的是数字 为:" << num << endl;
	}
	else
	{
		char buf[1024] = { 0 };
		cin >> buf;
		cout << "您输入的是字符串 :" << buf << endl;
	}
}

//案例2、 用户输入 0 ~ 10 之间的数字,如果输入有误,重新输入
void test08()
{
	cout << "请输入 0 ~ 10 之间的数字" << endl;

	int num;

	while (true)
	{
		cin >> num;
		
		if (num > 0 && num <= 10)
		{
			cout << "输入正确,输入值为:" << num << endl;
			break;
		}

		//清空缓冲区 重置标志位 
		cin.clear();
		cin.sync();
		cin.ignore();//vs2013以上版本加入 
		//如果标志位为 0  代表缓冲区正常    如果标志位为1   缓冲区异常
		cout << " cin.fail()  = " << cin.fail() << endl;

		cout << "输入有误,请重新输入: " << endl;
	}

}

int main() {
	//test01();
	//test02();
	//test03();
	//test04();
	//test05();
	//test06();
	//test07();
	test08();

	system("pause");
	return EXIT_SUCCESS;
}

08标准输出流.cpp

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
#include <iomanip> //控制符格式化输出  头文件

/*
cout.put() //向缓冲区写字符
cout.write() //从buffer中写num个字节到当前输出流中。
*/
void test01()
{
	//cout.put('h').put('e');

	char buf[] = "hello world";
	cout.write(buf, strlen(buf));

	cout << "hello world" << endl;

}

//1、通过 流成员函数 格式化输出
void test02()
{
	int number = 99;
	cout.width(20); //指定宽度为20
	cout.fill('*'); //填充
	cout.setf(ios::left);  //左对齐
	cout.unsetf(ios::dec); //卸载十进制
	cout.setf(ios::hex);  //安装十六进制
	cout.setf(ios::showbase);  //显示基数
	cout.unsetf(ios::hex);  //卸载十六进制
	cout.setf(ios::oct);   //安装八进制
	cout << number << endl;
}

//2、使用控制符 格式化输出
void test03()
{
	int number = 99;
	cout << setw(20)     //设置宽度
		<< setfill('~')  //设置填充
		<< setiosflags(ios::showbase)  //显示基数
		<< setiosflags(ios::left)  //设置左对齐
		<< hex   //显示十六进制
		<< number
		<< endl;


}

int main() {

	//test01();
	//test02();
	test03();

	system("pause");
	return EXIT_SUCCESS;
}

09文件读写.cpp

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
#include <fstream> //文件流
#include <string>

void test01()
{
	//写文件  o --  输出    
	ofstream  ofs("./test.txt", ios::out | ios::trunc);

	// ofs.open("./test.txt", ios::out | ios::trunc);  //设置打开方式 以及路径

	if (!ofs.is_open())
	{
		cout << "文件打开失败" << endl;
		return;
	}

	ofs << "姓名:孙悟空" << endl;
	ofs << "年龄:999" << endl;
	ofs << "性别:男" << endl;

	//关闭文件
	ofs.close();

}


void test02()
{
	//读文件   i  -- 输入
	ifstream  ifs;
	ifs.open("./test.txt", ios::in);

	if (!ifs.is_open())
	{
		cout << "文件打开失败" << endl;
		return;
	}

	//第一种方式
	char buf[1024] = { 0 };

	while (ifs >> buf)
	{
		cout << buf << endl;
	}


	//第二种方式
	//char buf[1024] = { 0 };
	//while (ifs.getline(buf,sizeof(buf)))
	//{
	//	cout << buf << endl;
	//}

	//第三种方式
	//string buf;
	//while ( getline(ifs,buf) )
	//{
	//	cout << buf << endl;
	//}


	//第四种方式
	//char  c;
	//while ((c = ifs.get()) != EOF)
	//{
	//	cout << c;
	//}

	//ifs.close();
}

int main() {

	// test01();
	test02();

	system("pause");
	return EXIT_SUCCESS;
}
原文地址:https://www.cnblogs.com/zranguai/p/15007529.html