C++基础09_类型转换-静态(动态,常量)类型, 异常的基本(标准异常,自定义异常),标准输入输出流,文件的读写操作

01类型转换-静态类型

1.基础类型
2.父子之间的转换

#include<iostream>
using namespace std;

//静态转换
//基础类型
void test01()
{
	char a = 'a';
	double d = static_cast<double>(a);

	cout << "d = " << d << endl;
}

// 父子之间的转换
class Base {};
class Child :public Base {};
class Other {};

void test02()
{
	Base* base = NULL;
	Child* child = NULL;

	//把base*转为Child* 类型,向下,不安全
	Child* child2 = static_cast<Child*>(base);

	//把Child*转为base* 类型,向上,安全
	Base* base2 = static_cast<Base*>(child);

	//转Other*类型  类Other与类Base之间不存在父子关系,不可以转换类型
	//Other* other = static_cast<Other*>(base);
}
//static_cast 的使用   static_cast<目标类型>(原始对象)

int main(void)
{
	test01();

	system("pause");
	return EXIT_SUCCESS;
}

02 类型转换-动态类型

1.基础类型不可以动态转换
2.Base转Child 不安全

//动态转换
void test03()
{
	//基础类型不可以动态转换
	char c = 'a';
	//dynamic_cast 非常严格 ,失去精度或者 不安全,都不可以转换
	//double d = dynamic_cast<double>(c);
}

class Base2 {
	virtual void func() {}
};
class Child2 :public Base2 {
	virtual void func() {}
};
class Other2 {};

void test04()
{
	Base2* base = NULL;
	Child2* child = NULL;
	//Child*转Base*  安全
	Base2* base2 = dynamic_cast<Base2*>(child);

	//Base*转Child*  不安全
	//Child2* child2 = dynamic_cast<Child2*>(base);

	//如果发生了多态,那么可以让基类转为派生类,向下转换
	Base2* base3 = new Child2;
	Child2* child3 = dynamic_cast<Child2*>(base3);
}

03 类型转换-静态和重新解释转换(常量转换

常量转换(const_cast):
该运算符用来修改类型的const属性。

  • 常量指针被转换成非常量指针,并且仍然指向原来的对象。
  • 常量引用被转换成非常量指针,并且仍然指向原来的对象。
    注意:不能直接对非指针和非引用的变量使用const_cast操作符去直接移除它的const。
//常量转换(const_cast)
void test05()
{
	const int* p = NULL;
	//去除const
	int* newP = const_cast<int*>(p);

	int* p2 = NULL;
	const int* newP2 = const_cast<const int*>(p2);

	//不能对非指针 或者 非引用的变量进行转换
	//const int a = 10;
	//int b = const_cast<int>(a);

	//引用
	int num = 10;
	int& numRef = num;
	const int& numRef2 = static_cast<const int&>(numRef);
}

//重新解释转换(reinterpret_cast)
void test06()
{
	int a = 10;
	int* p = reinterpret_cast<int*>(a);

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

	//最不安全,不推荐
}

04 异常的基本使用

try 试图执行 try{} 中的内容
在可能出现已成的地方 抛出异常 throw
try下面 catch 捕获异常
catch(捕获类型) …代表 所有其他的类型
如果不想处理异常,继续向上抛出,throw
如果没有任何处理异常的地方,那么程序调用terminate函数中断程序

跳级原理:
在这里插入图片描述

#include<iostream>
using namespace std;

int myDevide(int a, int b)
{
	if (b == 0)
	{
		//throw -1;//抛出int类型异常,异常必须处理,如果不处理,就会挂掉
		throw 3.14;
	}
	return a / b;
}

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

	//int ret = myDevide(a, b);//早期如果返回-1,无法区分到底是结果还是异常

	//C++中异常处理

	try
	{
		cout << myDevide(a, b) << endl;

	}
	catch (int)
	{
		cout << "int类型异常捕获" << endl;
		cout << "除数为0,无解" << endl;
	}
	catch (double)
	{
		//如果不想处理这个异常,可以继续向上抛出
		throw; //如果此处不抛出,此被此函数捕获,main函数则不会被捕获
		cout << "double类型异常捕获" << endl;
		cout << "除数为0,无解" << endl;
	}
	catch (...)
	{
		cout << "其他类型异常捕获" << endl;
	}
}

int main(void)
{
	try
	{
		test01();
	}
	catch (double) //如果异常都没有处理,那么成员terminate函数,使程序中断
	{
		cout << "main函数中 double类型异常捕获!" << endl;
	}

	system("pause");
	return EXIT_SUCCESS;
}

在这里插入图片描述

05 对自定义异常进行捕获

自定义异常类,可以抛出自定义的对象,捕获自定义的异常

#include<iostream>
using namespace std;

class myException//自定义异常类
{
public:
	void printError()
	{
		cout << "自定义的异常" << endl;
	}
};

int myDevide(int a, int b)
{
	if (b == 0)
	{
		//throw -1;//抛出int类型异常,异常必须处理,如果不处理,就会挂掉
		//throw 3.14;

		throw myException(); //匿名对象
	}
	return a / b;
}

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

	//int ret = myDevide(a, b);//早期如果返回-1,无法区分到底是结果还是异常

	//C++中异常处理

	try
	{
		cout << myDevide(a, b) << endl;

	}
	catch (int)
	{
		cout << "int类型异常捕获" << endl;
		cout << "除数为0,无解" << endl;
	}
	catch (double)
	{
		//如果不想处理这个异常,可以继续向上抛出
		throw; //如果此处不抛出,此被此函数捕获,main函数则不会被捕获
		cout << "double类型异常捕获" << endl;
		cout << "除数为0,无解" << endl;
	}
	catch (myException e)
	{
		e.printError();
	}
	catch (...)
	{
		cout << "其他类型异常捕获" << endl;
	}
}

int main(void)
{
	try
	{
		test01();
	}
	catch (double) //如果异常都没有处理,那么成员terminate函数,使程序中断
	{
		cout << "main函数中 double类型异常捕获!" << endl;
	}

	system("pause");
	return EXIT_SUCCESS;
}

在这里插入图片描述

06 栈解旋

从try开始,到throw抛出异常之前,所有栈上的对象,都会被释放,这个过程为栈解旋

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

class myException//自定义异常类
{
public:
	void printError()
	{
		cout << "自定义的异常" << endl;
	}
};

class Person {
public:
	Person()
	{
		cout << "Person构造" << endl;
	}
	~Person()
	{
		cout << "Person析构" << endl;
	}
};


int myDevide(int a, int b)
{
	if (b == 0)
	{
		//throw -1;//抛出int类型异常,异常必须处理,如果不处理,就会挂掉
		//throw 3.14;
		
		//栈解旋
		//从try开始,到throw抛出异常之前,所有栈上的对象,都会被释放,这个过程为栈解旋
		//构造和析构顺序相反
		Person p1;
		Person p2;
		throw myException(); //匿名对象
	}
	return a / b;
}

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

	//int ret = myDevide(a, b);//早期如果返回-1,无法区分到底是结果还是异常

	//C++中异常处理

	try
	{
		cout << myDevide(a, b) << endl;

	}
	catch (int)
	{
		cout << "int类型异常捕获" << endl;
		cout << "除数为0,无解" << endl;
	}
	catch (double)
	{
		//如果不想处理这个异常,可以继续向上抛出
		throw; //如果此处不抛出,此被此函数捕获,main函数则不会被捕获
		cout << "double类型异常捕获" << endl;
		cout << "除数为0,无解" << endl;
	}
	catch (myException e)
	{
		e.printError();
	}
	catch (...)
	{
		cout << "其他类型异常捕获" << endl;
	}
}

int main(void)
{
	try
	{
		test01();
	}
	catch (double) //如果异常都没有处理,那么成员terminate函数,使程序中断
	{
		cout << "main函数中 double类型异常捕获!" << endl;
	}

	system("pause");
	return EXIT_SUCCESS;
}

在这里插入图片描述

07 异常的接口声明

QT或Linux下测试

#include "mainwindow.h"

#include <QApplication>
#include<QDebug>

//异常的接口声明
//void func()throw() 不抛出任何类型异常
void func()throw(int){ //只抛出int类型异常
    throw 1;
}

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();

    try {
        func();
    } catch (int) {
        qDebug()<<"int类型异常";
    }
    catch(...){
        qDebug()<<"其他类型异常";
    }

    return a.exec();
}

08 异常变量生命周期

  • 如果MyException e,会多开销一份数据,调用拷贝构造
  • 如果MyException* e ,不new 提前释放对象,new 的话需要自己管理 delete
  • 推荐MyException& e,容易些,而且不会创建多余的数据

1.MyException e,会多开销一份数据,调用拷贝构造

#include<iostream>
#include<string>

using namespace std;

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

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

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

void doWork() {
	throw myExecption();
}

void test01() {
	try {
		doWork();
	}
	catch (myExecption e) {
		cout << "捕获异常" << endl;
	}
}

int main() {
	test01();

	system("pause");
	return 0;
}

在这里插入图片描述

2.MyException& e,容易些,而且不会创建多余的数据(推荐)

#include<iostream>
#include<string>

using namespace std;

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

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

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

void doWork() {
	throw myExecption();
}

void test01() {
	try {
		doWork();
	}
	catch (myExecption &e) {
		cout << "捕获异常" << endl;
	}
}

int main() {
	test01();

	system("pause");
	return 0;
}

在这里插入图片描述

3.MyException* e ,不new 提前释放对象,new 的话需要自己管理 delete

new myExecption() 返回一个指针

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>

using namespace std;

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

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

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

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

void test01() {
	try {
		doWork();
	}
	catch (myExecption *e) {
		cout << "捕获异常" << endl;
		delete e; //靠自觉释放对象
	}
}

int main() {
	test01();

	system("pause");
	return 0;
}

没有delete:
在这里插入图片描述
添加detele:
在这里插入图片描述

09 异常的多态使用

利用多态来实现printError同一个接口调用。
抛出不同的错误对象。

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

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

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

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

void doBusiness() {
	throw NullPointerException();
}

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

int main() {
	test01();

	system("pause");
	return 0;
}

在这里插入图片描述

10 使用系统标准异常

在这里插入图片描述

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
#include<stdexcept> //需要导入
#include<string>

class Person
{
public:
	Person(string name, int age)
	{
		this->m_Name = name;
		if (age < 0 || age>200)
		{
			//抛出越界异常
			throw out_of_range("年龄越界了!");
		}
		this->m_Age = age;
	}


	string m_Name;
	int m_Age;
};

void test01()
{
	Person p("张三", 500);
}

int main(void)
{
	try
	{
		test01();
	}
	catch (out_of_range& e)
	{
		cout << e.what() << endl;
	}

	system("pause");
	return EXIT_SUCCESS;
}

在这里插入图片描述

11 编写自己的异常类

  • 自己的异常类 , 需要继承于 exception
  • 需要重写 虚析构 和 what()
  • 内部维护一个错误信息字符串
  • 构造时候传入 错误信息字符串 ,what()返回 错误信息字符串
  • string 转 char* c_str()
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
#include<string>

class myOutOfRangeException :public exception
{
public:

	myOutOfRangeException(string errorInfo)
	{
		this->m_ErrorInfo = errorInfo;
	}

	virtual ~myOutOfRangeException()
	{

	}
	virtual const char* what() const
	{
		//返回 错误信息
		//string 转char*    c_str()
		return this->m_ErrorInfo.c_str();
	}
	string m_ErrorInfo;
};

class Person
{
public:
	Person(string name, int age)
	{
		this->m_Name = name;
		if (age < 0 || age>200)
		{
			//抛出异常
			throw myOutOfRangeException("年龄越界了!");
		}
		this->m_Age = age;
	}


	string m_Name;
	int m_Age;
};

void test01()
{
	try {

		Person p("张三", 500);
	}
	catch (myOutOfRangeException& e)
	{
		cout << e.what() << endl;
	}
}

int main(void)
{
	test01();

	system("pause");
	return EXIT_SUCCESS;
}

在这里插入图片描述

12 标准输入流

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

cin.get() //一次只能读取一个字符
cin.get(一个参数) //读一个字符
cin.get(两个参数) //可以读字符串
cin.getline() //读取换行,并且扔掉
cin.ignore(N) //N代表忽略的字符数, 没有参数时忽略一个字符
cin.peak() //偷窥 偷看一个字符,然后放回去
cin.putback() //放回 把字符放回缓冲区

test01:

void test01()
{
	//cin.get() //一次只能读取一个字符
	// 输入as  缓存区中 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;
}

在这里插入图片描述
test02:

void test02()
{
	//cin.get(两个参数) //可以读字符串
	char buf[1024];
	cin.get(buf, 1024);
	char c = cin.get();

	if (c == '\n')
	{
		cout << "换行还在缓冲区" << endl;
	}
	else
	{
		cout << "换行不在缓冲区了" << endl;
	}

	cout << buf << endl;
}
//cin.get(两个参数)读取字符串时,不会把换行符拿走,遗留在缓冲区中

在这里插入图片描述test03:

void test03()
{
	//cin.getline();
	char buf[1024];
	cin.getline(buf, 1024);

	char c = cin.get();
	if (c == '\n')
	{
		cout << "换行还在缓冲区" << endl;
	}
	else
	{
		cout << "换行不在缓冲区了" << endl;
	}
	//cin.getline把换行符读取,并且扔掉
}

在这里插入图片描述
test04:

void test04()
{
	//cin.ignore() 忽略
	cin.ignore(2);//没有参数代表忽略一个字符,带参数N表示忽略N个字符

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

在这里插入图片描述
test05:

void test05()
{
	//cin.peek() 偷窥
	//输入as 偷看一眼a,然后再放回缓冲区

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

在这里插入图片描述
test06:

void test06()
{
	//cin.putback();放回
	char c = cin.get();
	cin.putback(c);
	cout << "c = " << c << endl;

	char buf[1024];
	cin.getline(buf, 1024);

	cout << "buf = " << buf << endl;

}

在这里插入图片描述

13 标准输入流案例

案例1:判断用户输入的是数字还是字符串

void test07()
{
	cout << "请输入一串数字或者字符串" << endl;

	//偷窥
	char c = cin.peek();

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

		cout << "你输入的是字符串:输入的字符串为" << buf << endl;
	}
}

在这里插入图片描述
案例二:让用户输入 1-10 的数字,如果输入有误 重新输入

void test08()
{
	int num;
	cout << "请输入 1到10 的数字:" << endl;

	while (true)
	{
		cin >> num;
		if (num > 0 && num <= 10)
		{
			cout << "输入的数字为:" << num << endl;
			break;
		}
		cout << "对不起,输入的数字有误,请重新输入:" << endl;
		cout << "标志位" << cin.fail() << endl;//标志位为0 是正常的,1 不正常
	}
}

在这里插入图片描述
解决上述问题:

void test08()
{
	int num;
	cout << "请输入 1到10 的数字:" << endl;

	while (true)
	{
		cin >> num;
		if (num > 0 && num <= 10)
		{
			cout << "输入的数字为:" << num << endl;
			break;
		}
		cout << "对不起,输入的数字有误,请重新输入:" << endl;
		//重置标志位
		cin.clear();
		//清空缓冲区
		cin.sync();
		cin.ignore();//vs2013以上版本加入
		cout << "标志位" << cin.fail() << endl;//标志位为0 是正常的,1 不正常
	}
}

在这里插入图片描述

14 标准输出流

流对象的成员函数:

int number = 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 << number << endl;
#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;
}

test01:
在这里插入图片描述
test02:
在这里插入图片描述
test03:
在这里插入图片描述

15 文件的读写操作

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
//文件读写头文件
#include<fstream>

//写文件
void test01()
{
	//以输出的方式打开文件
	//ofstream ofs("./test.txt", ios::out | ios::trunc);

	//后期指定打开方式
	ofstream ofs;
	ofs.open("./test.txt", ios::out | ios::trunc);
	//判断是否打开成功
	if (!ofs.is_open())
	{
		cout << "打开失败!" << endl;
	}
	ofs << "姓名:abc" << endl;
	ofs << "年龄:10" << endl;
	ofs << "性别:男" << endl;

	ofs.close();
}

//文件写操作
void test02()
{
	ifstream ifs;
	ifs.open("./test.txt", ios::in);

	//判断是否打开成功
	if (!ifs.is_open())
	{
		cout << "打开失败" << endl;
	}
	//第一种方式
	//char buf[1024];
	//while (ifs >> buf)//按行读取
	//{
	//	cout << buf << endl;
	//}

	//第二种方式
	//char buf2[1024];
	//while (!ifs.eof())//eof 读到文件尾部
	//{
	//	ifs.getline(buf2, sizeof(buf2));
	//	cout << buf2 << endl;
	//}

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

int main(void)
{
	//test01();
	test02();

	system("pause");
	return EXIT_SUCCESS;
}

test01:
在这里插入图片描述
test02:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值