alin的学习之路(C++篇)(类型转换,异常,标准输入输出,文件操作)

alin的学习之路(C++篇)(类型转换,异常,标准输入输出,文件操作)

1.类型转换

  1. 静态类型转换

    • 静态类型转换用于内置数据类型的转换和子类和父类之间的转换

    • static_cast<目标>(源)

    void test01()
    {
    	char a = 'a';
    	double d = static_cast<double>(a);
    	cout << d << endl;
    }
    class Base{};
    class Son : public Base{};
    class Other{};
    
    void test02()
    {
    	Base* base = NULL;  
    	Son* son = static_cast<Son*>(base);   //向下 不安全
    	Base* base2 = static_cast<Base*>(son);   //向上 安全
    
    	//Other* other = static_cast<Other*>(base2);   //无效
    
    }
    
  2. 动态类型转换

    • 动态类型转换不能进行内置数据类型的转换,只能做父类和子类间向上类型转换和发生多态后的转换**(即只能做安全的转换)**
    void test03()
    {
    	char a = 'a';
    	//double d = dynamic_cast<double>(a);    //报错,不能转换
    	//cout << d << endl;
    }
    
    class Base2 { virtual void func() {} };
    class Son2 : public Base2 { virtual void func() {} };
    class Other2 {};
    
    void test04()
    {
    	Base2* base = NULL;
    	//Son2* son = dynamic_cast<Son2*>(base);   报错,向下类型转换不可以
    	Son2* son = NULL;
    	Base2* base2 = dynamic_cast<Base2*>(son);   //向上类型转换成功
    
    	Base2* base3 = new Son2;
    	Son2* son2 = dynamic_cast<Son2*>(base3);
    
    }
    
  3. 常量转换

    • 使用于指针和引用间的类型转换 用于卸掉和加上const
    void test05()
    {
    	int a = 10;
    	const int* b = &a;
    	int* c = const_cast<int*>(b);
    
    	const int* d = const_cast<const int*>(c);
    
    	int& e = a;
    	const int& f = const_cast<const int&>(e);
    }
     
    
  4. 重新解释转换

    • 可以任意转换,但不安全
    void test06()
    {
    	int a = 10;
    	int* b = reinterpret_cast<int*>(a);
    }
    

2.异常

1.异常简介

  1. 异常的语法

    • throw 抛出异常 抛出的是一个类型,不是具体的值
    • try 代码块中放可能发生异常的语句
    • catch 捕获异常并执行操作
  2. 代码示例

    //自定义异常
    class myException {
    public:
    	void printError()
    	{
    		cout << "自定义类型捕获" << endl;
    	}
    };
    
    int myDivision(int a, int b)
    {
    	if (b == 0) {
    		//throw - 1;  //抛出的是一个类型异常
    		//throw 'a';
    		throw myException();   //抛出自定义异常的匿名对象,捕获时要用对象去接收
    	}
    	return a / b;
    }
    
    void test01()
    {
    	int a = 10;
    	int b = 0;
    
    	//将可能发生异常的代码放在try代码块中
    	try {
    		int ret = myDivision(a, b);
    	}
    	//如果没有捕获对应类型的异常,那么代码会崩
    	catch (int)
    	{
    		throw;  //catch中使用throw会向上继续抛出异常,待外层捕获
    		cout << "int异常发生" << endl;
    	}
    	catch (myException e)
    	{
    		e.printError();
    	}
    	catch (...)   //代表上面所有分支判断以外的类型
    	{
    		cout << "其他类型异常发生" << endl;
    	}
    }
    int main()
    {
    	try {
    		test01();
    	}
    	catch (int)
    	{
    		cout << "main中捕获了int异常" << endl;
    	}
    	
    	system("pause");
    	return EXIT_SUCCESS;
    }
    

2.自定义异常多态

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

void func()
{
	//throw NULLPtrException();
	throw OutOfRangeException();   //抛出自定义异常
}
void test01()
{
	try {
		func();
	}
	catch (BaseException & e)     //使用父类的引用去接收子类的对象,发生多态
	{
		e.printError();
	}
}

3.系统标准异常

  1. 系统标准异常简介
class Person {
public:
	Person(int age)
	{
		if (age < 0 || age>150)
		{
			throw out_of_range("年龄必须在0-150之间");    //系统标准越界异常
		}
	}
};

void test01()
{
	try {
		Person p(1000);   //年龄越界
	}
	catch (exception& e)
	{
		cout << e.what() <<endl;    //what()函数返回抛出异常时的字符串
	}
}
  1. 自定义异常继承在exception下
    • 需要重写virtual char const* what() const
    • 继承在exception下
    • string->const char* 使用str.c_str();
class MyOutOfRange : public exception{
public:
	MyOutOfRange(const char* errInfo)
	{
		this->m_errInfo = errInfo;    //const char*可以隐式转为string
	}
	MyOutOfRange(const string& errInfo)
	{
		this->m_errInfo = errInfo;
	}

	virtual char const* what() const
	{
		//.c_str() 函数用于将string转为const char*,string不能隐式转换为const char*
		return this->m_errInfo.c_str();     
	}

	string m_errInfo;
};

void func()
{
	throw MyOutOfRange("越界异常");
}
void test01()
{
	try {
		func();
	}
	catch (exception & e)
	{
		cout << e.what() << endl;
	}
}

4.异常的接口以及栈解旋

  1. 使用异常的接口可以指定用什么类型去接收异常,如果抛出的类型与接收的不同,则代码崩掉

    throw(int)代表抛出int,throw()表示什么都不抛

  2. 栈解旋:异常被抛出后,在try块开始到throw前所有的对象都会被释放,不会等到函数结束

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

};

void func() throw()//表示不允许抛出异常         //throw(int)  //指定只能用int去接收异常
{
	//栈解旋:在try块开始到throw前所有的对象都会被释放
	Person p;

	//throw 1;
}
void test01()
{
	try {
		Person p;
		func();
	}
	catch (int)
	{
		cout << "int异常" << endl;
	}
	catch (double)
	{
		cout << "double异常" << endl;
	}
}

5.异常的生命周期

异常抛出与接收的4种方式:

  • 抛出myException() 接收:myException e 相当于值传递,会调用拷贝构造函数,产生一个新的对象
  • 抛出myException() 接收:myException& e e是匿名对象的左值是一个别名,延长了该匿名对象生命周期 (推荐)
  • 抛出&myException() 接收:myException* e 不能够使用catch中的指针去操作,原对象是匿名对象已释放
  • 抛出new myException() 接收:myException e 将myException的对象创建在堆上,延长了生命周期,要手动delete (推荐)
class myException {
public:
	myException()
	{
		cout << "myException构造函数调用" << endl;
	}
	myException(const myException& e)
	{
		cout << "myException拷贝构造函数调用" << endl;
	}
	~myException()
	{
		cout << "myException析构函数调用" << endl;
	}
};

void func()
{
	throw new myException();
}
void test01()
{
	try {
		func();
	}
	//抛出myException()  接收:myException e   相当于值传递,会调用拷贝构造函数,产生一个新的对象
	//抛出myException()  接收:myException& e  e是匿名对象的左值是一个别名,延长了该匿名对象的生命周期
	//抛出&myException()  接收:myException* e  不能够使用catch中的指针去操作,原对象是匿名对象已释放
	//抛出new myException()  接收:myException e  将myException的对象创建在堆上,延长了生命周期,要手动delete
	catch (myException* e)
	{
		cout << "自定义异常" << endl;
		delete e;
	}
}

3.标准输入输出

1.标准输入

  1. cin.get():从缓冲区读一个字符。注意:键盘输入的\n也放入缓冲区中

    void test01()
    {
    	char ch;
    	ch = cin.get();
    	cout << "ch = "<< ch << endl;
    
    	ch = cin.get();
    	cout << "ch = " << ch << endl;
    
    }
    
    void test02()
    {
    	//cin.get(一个参数)   相当于cin.get()其中这个参数是传入传出参数
    	/*char ch;
    	cin.get(ch);
    	cout << "ch = " << ch << endl;
    
    	cin.get(ch);
    	cout << "ch = " << ch << endl;*/
    
    	char buf[1024] = { 0 };
    	cin.get(buf, 1024);    //1.空格被包含进字符串,与cin>>区分。2.缓冲区中的\n会遗留在缓冲区中
    	cout << "buf = " << buf << endl;
    
    	char ch;
    	cin.get(ch);
    	cout << "ch = " << ch << endl;
    
    }
    
  2. cin.getline():读缓冲区中的字符串

    void test03()
    {
    	char buf[1024] = { 0 };
    	cin.getline(buf,1024);    //与字符串一起输入缓冲区中的\n会被自动舍弃掉
    	cout << "buf = " << buf << endl;
    	char ch;
    	cin.get(ch);
    	cout << "ch = " << ch << endl;
    
    }
    
  3. cin.ignore:忽略缓冲区中的字符(可加参数忽略多个)

    void test04()
    {
    	cin.ignore();   //忽略一个字符
    	char ch;
    	cin.get(ch);
    	cout << "ch = " << ch << endl;
    }
    
  4. cin.peek():“偷窥”缓冲区的一个字符,不会将看到的那个字符取出来

    void test05()
    {
    	cin.peek();
    	char ch;
    	cin.get(ch);
    	cout << "ch = " << ch << endl;
    }
    
  5. cin.pushback():将字符放回其在缓冲区的原位置

    void test06()
    {
    	char buf[1024] = { 0 };
    	char ch;
    	cin.get(ch);
    	cout << "ch = " << ch << endl;
    	cin.putback(ch);
    	cin.getline(buf, 1024);
    	cout << "buf = " << buf << endl;
    }
    
  6. 案例1:判断用户输入是数字还是字符串

    //案例1:判断用户输入是数字还是字符串
    void test07()
    {
    	cout << "请输入一个数字或字符串:" << endl;
    	char ch;
    	ch = cin.peek();
    
    	if (ch >= '0' && ch <= '9')
    	{
    		int num;
    		cin >> num;
    		cout << "num = " << num << endl;
    	}
    	else {
    		char buf[1024] = { 0 };
    		cin.getline(buf, 1024);
    		cout << "buf = " << buf << endl;
    	}
    }
    
  7. 案例2:用户输入0-9的数字,如果不是0-9则重新输入

    void test08()
    {
    	while (true)
    	{
    		int num;
    		cout << "请输入一个0-9的数字" << endl;
    		cin >> num;
    		if (num >= 0 && num <= 9)
    		{
    			cout << "执行后面的代码" << endl;
    			break;
    		}
    		else {
    			cout << "输入有误,请重新输入" << endl;
    			//1.重置标志位 (置0是缓冲区正常,置1是缓冲区异常)
    			cin.clear();
    			//2.刷新缓冲区
    			//cin.sync();   VS低版本可用,VS高版本用getline刷新缓冲区
    			char buf[1024] = { 0 };
    			cin.getline(buf, 1024);
    		}
    
    	}
    }
    

2.标准输出

  1. cout.put():向缓冲区写字符

  2. cout.write():从buf中写n个字符到当前输入流中

    void test01()
    {
    	cout.put('h').put('\n');
    
    	char buf[1024] = "hello world";
    	cout.write(buf, 1024);   //默认带换行
    }
    
  3. 通过流成员函数

    //通过流成员函数输出
    void test02()
    {
    	int number = 99;
    	cout.width(5);     //设置宽度
    	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;		//输出number
    }
    
    
  4. 使用控制符

    //通过控制符
    void test03()
    {
    	int number = 99;
    	cout << setw(5)		//设置宽度
    		<< setfill('*')	//设置填充
    		<< setiosflags(ios::showbase)	//显示进制基数
    		<< setiosflags(ios::left)		//设置左对齐
    		<< hex			//十六进制
    		<< number		//输出数字
    		<< endl;		//换行
    }
    

4.文件操作

1.写文件

//写文件
void test01()
{
	ofstream ofs("test.txt", ios::out | ios::trunc);    //默认单独使用ios::out的时候会隐藏的加上ios::trunc

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

	ofs << "姓名:Tom" << endl;
	ofs << "年龄:18" << endl;
	ofs << "性别:男" << endl;

	ofs.close();
}

2.读文件

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

	
	//方法1
	/*char buf[1024] = { 0 };
	while (ifs >> buf)    //当buf中没有内容时即文件读完时,循环结束
	{
		cout << buf << endl;;
	}*/


	//方法2
	/*char buf[1024] = { 0 };
	while (ifs.getline(buf,sizeof(buf)))
	{
		cout << buf << endl;
	}*/

	//方法3
	//string buf;
	//while (getline(ifs, buf))   //getline(src,dest)
	//{
	//	cout << buf << endl;
	//}

	//方法4
	char ch;
	while ((ch = ifs.get()) != EOF)   //ifs.get()每次读一个字符
	{
		cout << ch;
	}

	ifs.close();
}

3.二进制读写文件

class Person {
public:
	Person(){}
	Person(string name,int age) 
	{
		this->m_Name = name;
		this->m_Age = age;
	}

	string m_Name;
	int m_Age;
};

void test01()
{
	ofstream ofs("person.txt", ios::out | ios::binary);

	Person p1("TOM",18);
	Person p2("Jerry",19);

	ofs.write((const char*)&p1, sizeof(p1));
	ofs.write((const char*)&p2, sizeof(p2));

	ofs.close();

	ifstream ifs("person.txt", ios::in | ios::binary);
	if (!ifs.is_open())
	{
		cout << "文件打开失败" << endl;
	}
	Person p3;
	Person p4;

	ifs.read((char*)&p3, sizeof(p3));
	ifs.read((char*)&p4, sizeof(p4));

	cout << "姓名:" << p3.m_Name << " 年龄:" << p3.m_Age << endl;
	cout << "姓名:" << p4.m_Name << " 年龄:" << p4.m_Age << endl;

	ifs.close();
}

猜你喜欢

转载自blog.csdn.net/qq_41775886/article/details/106973370