C++[异常与IO]

2023-3-17首次编辑

Unit 10:异常

一.概念

  • 异常处理就是处理程序中的错误
  • 错误是指在程序运行的过程中发生的一些异常事件

二.作用

解决C语言处理异常的方法缺陷:

  1. 返回值意思不明确
  2. 返回值只能返回一条信息
  3. 返回值可以忽略

三.基本语法与执行流程

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

int func(int a, int b)
{
	if (b==0)
	{
		//第二步:抛出异常
		throw 10; //抛出一个int类型的异常
		cout << "throw后的代码" << endl;
	}
}

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

	//第一步:把有可能出现异常的代码块放到try中
	try
	{
		func(a, b);
		cout << "func后的代码" << endl;
	}
	//第三步:接受一个int类型的异常
	catch (int)
	{
		cout << "接收到一个int类型的异常" << endl;
	}
}

int main()
{
	test();
	system("pause");
	return 0;
}

四.异常的优势

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

class Maker
{
public:
	void printMaker()
	{
		cout << "除数不能为0" << endl;
	}
};

int func(int a, int b)
{
	if (b == 0)
	{
		//Maker m;
		//throw m; //抛出一个Maker类型的异常
		throw 20.22; //抛出一个double类型的异常
	}
	return a / b;
}

void test()
{
	int a = 10;
	int b = 0;
	try
	{
		func(a, b);
	}
	catch (int)
	{
		cout << "接收到一个int类型的异常" << endl;
	}
	catch (Maker maker)
	{
		cout << "接收到一个Maker类型的异常" << endl;
		maker.printMaker();
	}
	catch (double)
	{
		//如果不想处理异常,可以往上抛出,抛给调用本函数的函数
		throw;
	}
}

int main()
{
	try
	{
		test();
	}
	catch (double)
	{
		cout << "接收一个double类型的异常" << endl;
	}
	system("pause");
	return 0;
}
  • 用户可以忽略返回值,但不能忽略异常,如果忽略将会报错
  • 返回值只能返回一条信息,但对象有成员函数,可以包含多个信息
  • 可以逐层依赖处理异常

五.异常的严格类型匹配

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

class Maker
{
public:
	
};

int func(int a, int b)
{
	if (b == 0)
	{
		//Maker m;
		//throw m; //抛出一个Maker类型的异常
		//throw 20.22; //抛出一个double类型的异常
		//throw 'c'; //抛出一个char类型的异常
		throw 20.0f; //抛出一个float类型的异常
	}
}

void test()
{
	int a = 10;
	int b = 0;
	try
	{
		func(a, b);
	}
	catch (Maker)
	{
		cout << "接受一个Maker类型的异常" << endl;
	}
	catch (double)
	{
		cout << "接受一个double类型的异常" << endl;
	}
	catch (char)
	{
		cout << "接受一个char类型的异常" << endl;
	}
	catch (...) //接受其他类型的异常
	{
		cout << "接受一个其他类型的异常" << endl;
	}
}

int main()
{
	test();
	system("pause");
	return 0;
}

六.异常的接口声明

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

void func() throw(int, char) //只允许抛出int或者char异常
{
	throw 10; //抛出一个double类型的异常,Qt上程序会阻挡
}

int main()
{
	try
	{
		func();
	}
	catch (int)
	{
		cout << "int" << endl;
	}
	catch (...)
	{
		cout << "..." << endl;
	}
	system("pause");
	return 0;
}

七.栈解旋

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

class Maker
{
public:
	Maker()
	{
		cout << "Maker的构造" << endl;
	}
	Maker(const Maker &m)
	{
		cout << "Maker的拷贝构造" << endl;
	}
	~Maker()
	{
		cout << "Maker的析构" << endl;
	}
};

void func()
{
	//栈解旋:
	//在抛出异常的函数中,如果抛出异常之后,但函数没有结束,此时栈上申请的对象都会被释放
	Maker m;
	throw m; //这个m是Maker m拷贝的一份
	cout << "func函数结束" << endl;
}

void test()
{
	try
	{
		func();
		cout << "func代码后" << endl;
	}
	catch (Maker)
	{
		cout << "接收一个Maker类型的异常" << endl;
	}
}

int main()
{
	test();
	system("pause");
	return 0;
}

八.异常变量的生命周期

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

class Maker
{
public:
	Maker()
	{
		cout << "Maker的构造" << endl;
	}
	Maker(const Maker &m)
	{
		cout << "Maker的拷贝构造" << endl;
	}
	~Maker()
	{
		cout << "Maker的析构" << endl;
	}
};

//产生三个对象
void func1()
{
	Maker m; //第一个对象,在异常接收前被释放
	throw m; //第二个对象,是第一个对象拷贝过来的
}

void test1()
{
	try
	{
		func1();
	}
	catch (Maker m1) //第三个对象,是第二个对象拷贝过来的
	{
		cout << "接收一个Maker类型的异常" << endl;
		//第二个对象和第三个对象在catch结束时释放
	}
}

//产生两个对象
void func2()
{
	throw Maker(); //第一个对象,匿名对象
}

void test2()
{
	try
	{
		func2();
	}
	catch (Maker m1) //第二个对象,是第一个对象拷贝过来的
	{
		cout << "接收一个Maker类型的异常" << endl;
		//第一个对象和第二个对象在catch结束时释放
	}
}

//产生一个对象(常用)
void func3()
{
	throw Maker(); //匿名对象
}

void test3()
{
	try 
	{
		func3();
	}
	catch (Maker &m1) //引用匿名对象
	{
		cout << "接收一个Maker类型的异常" << endl;
	}
}

//注意:
void func4()
{
	//编译器不允许对栈中的匿名对象取地址操作
	//throw Maker(); //err

	//编译器允许对堆区中的匿名对象取地址操作
	throw new Maker();
}

void test4()
{
	try
	{
		func4();
	}
	catch (Maker* m1) //对匿名对象取地址
	{
		cout << "接收一个Maker类型的异常" << endl;
		delete m1;
	}
}

int main()
{
	test1();
	test2();
	test3();
	test4();
	system("pause");
	return 0;
}

九.异常的多态

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

//异常的基类
class Father
{
public:
	virtual void printM()
	{

	}
};

//1.有继承
class SonNULL :public Father
{
public:
	virtual void printM() //2.重写父类的虚函数
	{
		cout << "空指针异常" << endl;
	}
};

class SonOut :public Father
{
public:
	virtual void printM()
	{
		cout << "越位溢出" << endl;
	}
};

void func(int a, int b)
{
	if (a==0)
	{
		throw SonNULL();
	}
	if (b==0)
	{
		throw SonOut();
	}
}

void test()
{
	int a = 0;
	int b = 10;
	try
	{
		func(a, b);
	}
	catch (Father &f) //3.父类引用指向子类对象
	{
		f.printM();
	}
}

int main()
{
	test();
	system("pause");
	return 0;
}

十.系统提供的标准异常

#define _CRT_SECIRE_NO_WARNINGS
#include <iostream>
#include <string>
#include <stdexcept> //标准异常库(Vs2013可以不需要写)
using namespace std;

//1.系统的标准异常类
class Maker1
{
public:
	Maker1(int age)
	{
		if (age<0||age>150)
		{
			throw out_of_range("系统的标准异常类:年龄不在范围内");
		}
		else
		{
			this->age = age;
		}
	}
public:
	int age;
};

void test1()
{
	try
	{
		Maker1 m(200);
	}
	catch (out_of_range &ex)
	{
		cout << ex.what() << endl;
	}
}

//2.自己编写的异常类
class MyOut_of :public exception
{
public:
	MyOut_of(const char* errorinfo)
	{
		//const char*转换string
		this->m_Info = string(errorinfo);
	}
	MyOut_of(const string errorinfo)
	{
		this->m_Info = errorinfo;
	}
	const char* what() const
	{
		//把string转换成const char*
		return this->m_Info.c_str();
	}
public:
	string m_Info;
};

class Maker2
{
public:
	Maker2(int age)
	{
		if (age<0 || age>150)
		{
			throw MyOut_of("自己编写的异常类:年龄不在范围内");
		}
		else
		{
			this->age = age;
		}
	}
public:
	int age;
};

void test2()
{
	try
	{
		Maker2(200);
	}
	catch (MyOut_of &ex)
	{
		cout << ex.what() << endl;
	}
}

int main()
{
	test1();
	test2();
	system("pause");
	return 0;
}

Unit 11:IO

流的概念和流泪库的结构

  • 标准IO:对系统的标准输入输出设备进行读写
  • 文件IO:对磁盘进行输入输出读写
  • 串IO:对内存进行读写

一.系统标准的输入流

成员函数:

  • cin.get() //一次只能读取一个字符
  • cin.get(一个参数) //读取一个字符
  • cin.get(两个参数) //可以读取字符串
  • cin.getline() //取一行,换行符丢弃
  • cin.ignore() //忽略
  • cin.peek() //偷窥
  • cin.putback() //放回
#define _CRT_SECIRE_NO_WARNINGS
#include <iostream>
using namespace std;

//单个输入
void test1()
{
	//输入ab
	char c = cin.get(); //读取a
	cout << c << endl;
	c = cin.get(); //读取b
	cout << c << endl;
	c = cin.get(); //读取换行符
	cout << c << endl;

	//其他形式
	cin.get(c); //阻塞
	cout << c << endl;
	cin.get(c); //读取换行符
	cout << c << endl;

	char ch1, ch2, ch3, ch4;
	cin.get(ch1).get(ch2).get(ch3).get(ch4);
	cout << ch1 << ch2 << ch3 << ch4 << endl;
}

//按行输入
void test2()
{
	char buf[1024] = { 0 };
	cin.get(buf, 1024); //读取缓冲区时,换行符不拿走
	char c = cin.get();
	if (c=='\n')
	{
		cout << "换行符还在缓冲区中" << endl;
	}
	cout << buf << endl;

	cin.getline(buf, 1024); //读取缓冲区时,换行符丢弃
	char ch = cin.get(); //阻塞
	if (ch == '/n')
	{
		cout << "换行符还在缓冲区中" << endl;
	}
	cout << buf << endl;
}

//忽略(参数为N,表示忽略N个字符)
void test3()
{
	输入ab
	//cin.ignore(); //默认忽略缓冲区内第一个字符
	//char c = cin.get(); //b
	//cout << c << endl;

	//输入abcde
	cin.ignore(3); //忽略缓冲区内前三个字符
	char ch = cin.get(); //d
	cout << ch<< endl;
}

//偷窥(只看不拿)
void test4()
{
	//输入a
	char c = cin.peek(); //偷窥第一个字符a
	cout << "c:" << c << endl;

	char ch = cin.get(); //拿走a
	cout << "ch:" << ch << endl;
}

//返回(拿走后,放回去)
void test5()
{
	//输入a
	char c = cin.get(); //拿走a
	cout << c << endl;
	cin.putback(c); //放回a

	char buf[1024] = { 0 };
	cin.getline(buf, 1024); //拿走放回的a
	cout << buf << endl;
}

//综合案例一:判断用户输入的是字符串还是数字
void test6()
{
	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;
	}
}

//综合案例二:输入0~10的数字,直到输入正确为止
void test7()
{
	int num;
	while (1)
	{
		cin >> num;
		if (num >= 0 && num <= 10)
		{
			cout << "输入正确!!!" << endl;
			break;
		}
		cout << "重新输入:" << endl;

		//重置标志位
		cin.clear();
		
		//拿走缓冲区内容
		char buf[1024] = { 0 };
		cin.getline(buf, 1024);

		//打印标志位
		//0表示正常,无数据
		//1表示不正常,有数据
		cout << cin.fail() << endl;
	}
}

int main()
{
	//test1();
	//test2();
	//test3();
	//test4();
	//test5();
	//test6();
	test7();
	system("pause");
	return 0;
}

二.系统标准的输出流

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

//单个输出
void test1()
{
	cout.put('c');

	//链式编程
	cout.put('a').put('b').put('c');
}

//按行输出
void test2()
{
	char buf[] = "Hello World";
	cout.write(buf, strlen(buf));
}

//通过流成员函数实现格式化的输出
void test3()
{
	int num = 99;

	//设置宽度
	cout.width(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 << num << endl;
}

//通过控制符格式化输出(引入头文件iomanip)
#include <iomanip>

void test4()
{
	int num = 99;

	//设置宽度
	cout << setw(20);

	//填充
	cout << setfill('~');

	//显示基数
	cout << setiosflags(ios::showbase);

	//让数据在左边
	cout << setiosflags(ios::left);

	//十六进制
	cout << hex;

	//八进制
	cout << oct;

	//十进制
	cout << dec;

	cout << num << endl;
}

//打印浮点数后面的小数点
void test5()
{
	double d = 20.22;

	//设置显示浮点数
	cout << setiosflags(ios::fixed);

	//显示小数点后10位
	cout << setprecision(10) << endl;

	cout << d << endl;
}

int main()
{
	//test1();
	//test2();
	//test3();
	//test4();
	test5();
	system("pause");
	return 0;
}

三.文件读写操作

在这里插入图片描述

C++文件读写:

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

//1.引入头文件
#include <fstream>

//把程序中的信息输出到缓冲区,然后写到文件(写文件)
void test1()
{
	//2.定义流对象
	ofstream ofs;

	//3.打开文件,以写的方式打开(如果没有文件,就创建)
	ofs.open("test.txt", ios::out | ios::trunc);

	//4.判断是否打开成功
	if (!ofs.is_open())
	{
		cout << "打开文件" << endl;
	}

	//5.写信息
	ofs << "姓名:悟空" << endl;
	ofs << "年龄:18" << endl;
	ofs << "身高:180cm" << endl;

	//6.关闭文件
	ofs.close(); //关闭文件,并刷新缓冲区
}

//把磁盘信息输入到缓冲区,然后读到程序中(读文件)
void test2()
{
	ifstream ifs;
	ifs.open("test.txt", ios::in);
	if (ifs.is_open()==false)
	{
		cout << "打开失败" << endl;
	}

	//第一种方式读取文件
	//一行一行读取
	/*char buf[1024] = { 0 };
	while (ifs >> buf)
	{
		cout << buf << endl;
	}*/

	//第二种方式读文件
	/*char buf[1024] = { 0 };
	while (!ifs.eof()) //判断是否读到文件尾部
	{
		ifs.getline(buf, sizeof(buf));
		cout << buf << endl;
	}*/

	//第三种方式读取文件
	//单个字符读取
	char c;
	while ((c=ifs.get())!=EOF)
	{
		cout << c;
	}

	ifs.close();
}

int main()
{
	//test1();
	test2();
	system("pause");
	return 0;
}

四.二进制文件读写

#define _CRT_SECIRE_NO_WARNINGS
#include <iostream>
#include <fstream>
using namespace std;

class Maker
{
public:
	Maker()
	{

	}
	Maker(const char* name, int age)
	{
		this->age = age;
		strcpy(this->name, name);
	}
public:
	char name[64];
	int age;
};

//写文件
void test1()
{
	Maker m1("悟空", 18);
	Maker m2("贝吉塔", 22);

	ofstream ofs;
	ofs.open("test.txt", ios::out | ios::trunc | ios::binary);
	if (!ofs.is_open())
	{
		cout << "打开失败" << endl;
	}

	//写
	ofs.write((const char *)&m1, sizeof(Maker));
	ofs.write((const char *)&m2, sizeof(Maker));

	ofs.close();
}

//读文件
void test2()
{
	ifstream ifs;
	ifs.open("test.txt", ios::in | ios::binary);
	if (!ifs.is_open())
	{
		cout << "打开失败" << endl;
	}

	//读
	Maker m1;
	Maker m2;

	ifs.read((char*)&m1, sizeof(Maker));
	ifs.read((char*)&m2, sizeof(Maker));

	cout << "Name:" << m1.name << " Age:" << m1.age << endl;
	cout << "Name:" << m2.name << " Age:" << m2.age << endl;

	ifs.close();
}

//注意:当文件读写时,类中的成员变量不要有string类型
class Maker2
{
public:
	Maker2()
	{

	}
	Maker2(string name, int age)
	{
		this->name = name;
		this->age = age;
	}
public:
	string name;
	//string类中有一个成员指针char*,该指针指向存储字符串的空间
	//当我们把string类的数据存储到文件中,再读出来时,不能保证指针有效
	//string 开辟的空间如果大于16个字节就在堆区,小于就在栈区
	int age;
};

int main()
{
	test1();
	test2();
	system("pause");
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Cforikl_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值