C++核心编程Day07

1.C++类型转换

1.1静态转换1.用于类层次结构中基类(父类)和派生类(子类)之间指针或引用的转换。2.进行上行转换(把派生类的指针或引用转换成基类表示)是安全的;3.进行下行转换(把基类指针或引用转换成派生类表示)时,由于没有动态类型检
查,所以是不安全的。4.用于基本数据类型之间的转换,如把int转换成char,把char转换成int。这种转换的
安全性也要开发人员来保证。
//1.基础类型转换
void test01()
{char a = 'a';//static_cast<要转换的类型>(谁要转换)double d = static_cast<double>(a);
}
//2.有层次类的指针或引用转换
class Father
{};
class Son :public Father
{};
class A
{};
//2.指针转换
void test02()
{Father* f = NULL;Son* s = NULL;//向下转换,不安全Son* s1 = static_cast<Son*>(f);//向上转换,安全Father* f1 = static_cast<Father*>(s);//类之间必须有关系才能进行强转,否则是不可以的//A* a = static(f);//error//A* a = static(s);//error
}
1.2动态转换1.ynamic_cast主要用于类层次间的上行转换和下行转换;2.在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的;3.在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全;

//2.动态转化
class Father
{};
class Son :public Father
{};
class A
{};//1.基础类型转换(不允许)
void test04()
{//char a = 'a';//double d = dynamic_cast(a);//动态类型转化不允许基础的数据类型
}//2.指针转换
void test05()
{Father* f = NULL;Son* s = NULL;//向下转换,不安全//Son* s1 = dynamic_cast(f);//error必须是多态类型才可以转换,因此会报错//向上转换,安全Father* f1 = dynamic_cast<Father*>(s);//类之间必须有关系才能进行强转,否则是不可以的//A* a = static(f);//error//A* a = static(s);//error
}
1.3 常量转换1.该运算符用来修改类型的const属性。。2.常量指针被转化成非常量指针,并且仍然指向原来的对象;3.常量引用被转换成非常量引用,并且仍然指向原来的对象;
//常量转换
//1.常量指针转换
void test06()
{//常量转普通const int* p = NULL;int* tmp_p = const_cast<int*>(p);//普通转常量int* p1 = NULL;const int* tmp_p1 = const_cast<const int*>(p1);
}
//2.常量引用转换
void test07()
{//常量转普通int a = 10;const int& p = a;int& tmp_p = const_cast<int&>(p);//普通转常量int b = 20;int& p1 = a;const int& tmp_p1 = const_cast<const int&>(tmp_p1);
}
1.4重新解释转换(最不安全的一种转换,容易出现问题)
class Father
{};
class Son :public Father
{};
class A
{};void test08()
{int a = 10;int* p = reinterpret_cast<int*>(a);Father* f = NULL;A* p_a = reinterpret_cast<A*>(f);
}

2. C++异常

2..1 异常基本概念异常处理就是处理程序中的错误。所谓错误是指在程序运行的过程中发生的一些异常
事件(如:除0溢出,数组下标越界,所要读取的文件不存在,空指针,内存不足等等)之前处理异常的缺陷:1.之前处理问题是通过返回值判断,但是返回值意思不明确2.而且返回值只能返回一个信息3.并且返回值可以忽略
#define _CRT_SECURE_NO_WARNINGS
#include
#include
using namespace std;int printArr(int arr[], int len)
{//之前处理异常的缺陷//1.之前处理问题是通过返回值判断,但是返回值意思不明确//2.而且返回值只能返回一个信息//3.并且返回值可以忽略if (arr == NULL)return -1;if (arr == 0)return 0;
}int func1(int a, int b)
{if (b == 0){//2.抛出异常throw 10;//抛出一个int类型的异常cout << "throw后程序" << endl;}return a / b;
}void test01()
{int a = 10;int b = 0;//1.把有可能出现异常的代码块放入try中try{func1(a, b);cout << "func后程序" << endl;}catch(int){cout << "接收一个INT类型的异常" << endl;}
}int main()
{test01();system("pause");return 0;
}
2.2 异常的优势
1.用户不知道返回值是什么意思,异常可以抛出对象,对象中可以包含很多成员函数,可
以有很多信息
2.返回值可以返回一条信息,但是对象有成员函数可以包含多种信息,返回值可以忽略,
但是异常不可以忽略,必须要进行后续的处理
#define _CRT_SECURE_NO_WARNINGS
#include
#include
using namespace std;//1.用户不知道返回值是什么意思,异常可以抛出对象,对象中可以包含很多成员函数,可以有很多信息
class Distake
{
public:void printViews(){cout << "除数不能为0" << endl;}
};int func1(int a, int b)
{if (b == 0){//2.抛出异常//Distake d;//throw d;//抛出一个int类型的异常throw 1.11;//test3();}return a / b;
}void test01()
{int a = 10;int b = 0;try{func1(a, b);}catch (int){cout << "接收一个INT类型的异常" << endl;}catch (Distake d){d.printViews();}
}//3.返回值可以返回一条信息,但是对象有成员函数可以包含多种信息,返回值可以忽略,但是异常不可以忽略,必须要进行后续的处理,
void test02()
{int a = 10;int b = 0;try{func1(a, b);}catch (int){cout << "接收一个INT类型的异常" << endl;}//catch (Distake d)//{//	d.printViews();//}
}
//3.不想处理异常,可以网上抛出,抛给调用本函数的函数
void test03()
{int a = 10;int b = 0;try{func1(a, b);}catch (int){cout << "接收一个INT类型的异常" << endl;}catch (Distake d){d.printViews();}catch (double d){throw;}
}int main()
{//test01();//test02();try{test03();}catch (double d){cout << "接收一个double类型的异常" << endl;}system("pause");return 0;
}
2.3 异常严格类型匹配异常机制和函数机制互不干涉,但是捕捉方式是通过严格类型匹配。
#define _CRT_SECURE_NO_WARNINGS
#include
#include
using namespace std;int func1(int a, int b)
{if (b == 0){//throw 'c';//抛出的值必须严格类型匹配,否则会报错throw 1.11;}return a / b;
}void test01()
{int a = 10;int b = 0;try{func1(a, b);}catch (int){cout << "接收一个INT类型的异常" << endl;}catch (double d){cout << "接收一个double类型的异常" << endl;}catch (...){//...表示所有类型,当前2个条件不满足时,就会接收所有的类型的异常cout << "接收一个所有类型的异常" << endl;}
}int main()
{//test01();//test02();try{test03();}system("pause");return 0;
}
2.4 栈解旋异常被抛出后,从进入try块起,到异常被抛掷前,这期间在栈上构造的所有对象,都
会被自动析构。析构的顺序与构造的顺序相反,这一过程称为栈的解旋
#define _CRT_SECURE_NO_WARNINGS
#include
#include
using namespace std;class Test
{
public:Test(){cout << "构造函数" << endl;}Test(const Test &t){cout << "拷贝构造函数" << endl;}~Test(){cout << "析构函数" << endl;}
};void func()
{//在抛出异常的函数中,如果抛出异常之后,但函数没有结束,这时栈上申请的对象都会被释放,这就叫栈解旋Test t;throw t;//这里的t是上面的Test t拷贝出来的一份cout << "Func函数结束!" << endl;
}void test01()
{try{func();}catch (Test){cout << "Test类型的异常" << endl;}
}int main()
{test01();system("pause");return 0;
}
2.5 异常对象的生命周期1.throw的异常是有类型的,可以是数字、字符串、类对象。2.throw的异常是有类型的,catch需严格匹配异常类型。
#define _CRT_SECURE_NO_WARNINGS
#include
#include
using namespace std;class Test
{
public:Test(){cout << "构造函数" << endl;}Test(const Test& t){cout << "拷贝构造函数" << endl;}~Test(){cout << "析构函数" << endl;}
};
//这里会产生三个对象
void func()
{Test t;//在异常接收前产生第一个对象,在异常接收前被释放throw t;//抛出异常的时候,拷贝构造产生第二个对象
}void test01()
{try{func();}catch (Test t)//检测异常的时候,拷贝构造第三个对象{cout << "Test类型的异常" << endl;}
}//这里会产生两个对象
void func2()
{throw Test();//匿名函数产生第一个
}void test02()
{try{func();}catch (Test t)//检测异常的时候,拷贝构造第二个对象{cout << "Test类型的异常" << endl;}
}//这里会产生一个对象
void func3()
{throw Test();//匿名函数产生第一个
}void test03()
{try{func3();}catch (Test &t){cout << "Test类型的异常" << endl;}
}//注:用指针接抛出的异常
void func4()
{//编译器不允许对栈上的匿名对象取地址操作//throw Test();//匿名函数产生第一个//编译器允许对堆上的匿名对象取地址操作throw new Test();
}
void test04()
{try{func4();}catch (Test* t){cout << "Test类型的异常" << endl;delete t;}
}int main()
{//test01();//test02();//test03();test04();system("pause");return 0;
}
2.6 异常的多态
#define _CRT_SECURE_NO_WARNINGS
#include
#include
using namespace std;//多错误类型多态实现
class Father
{
public://1.虚函数重写virtual void printF() {};
};class Son1 :public Father
{
public://2.有继承virtual void printF(){cout << "错误1" << endl;}
};class Son2 :public Father
{
public:virtual void printF(){cout << "错误2" << endl;}
};void func()
{//throw Son1();throw Son2();}void test01() 
{try{func();}catch(Father& f)//3.有父类指针指向子类对象{f.printF();}
}int main()
{test01();system("pause");return 0;
}
2.7 系统的标准异常端1.所有的异常类都有一个what()方法,返回const char* 类型(C风格字符串)的值,
描述异常信息。2.父类都为exception类。
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include//系统的标准异常类的头文件
using namespace std;//自己的异常类
class MyException :public exception
{
public:MyException(const char* e_views){this->m_Views = string(e_views);}MyException(const string e_views){this->m_Views = e_views;}char const* what() const{return this->m_Views.c_str();}string m_Views;
};class Test
{
public:Test(int age){if (age < 0 || age>150){//throw out_of_range("年龄范围有误!");throw MyException("年龄范围有误!");}this->age = age;}int age;
};void test01()
{try{Test t(151);}catch (out_of_range &ex){cout << ex.what() << endl;;}catch (MyException& ex){cout << ex.what() << endl;;}
}int main()
{test01();system("pause");return 0;
}

3. 文件操作

C++输入输出包含以下三个方面的内容:1.对系统指定的标准设备的输入和输出。即从键盘输入数据,输出到显示器屏幕。
这种输入输出称为标准的输入输出,简称标准I/O。2. 以外存磁盘文件为对象进行输入和输出,即从磁盘文件输入数据,数据输出到磁
盘文件。以外存文件为对象的输入输出称为文件的输入输出,简称文件I/O。3.对内存中指定的空间进行输入和输出。通常指定一个字符数组作为存储空间(实际
上可以利用该空间存储任何信息)。这种输入和输出称为字符串输入输出,简称串I/O。3.1 标准的输入流标准输入流标准输入流对象cin,重点掌握的函数cin.get() //一次只能读取一个字符cin.get(一个参数) //读一个字符cin.get(两个参数) //可以读字符串cin.getline()cin.ignore()cin.peek()cin.putback()
#define _CRT_SECURE_NO_WARNINGS
#include
#include
using namespace std;void test01()
{/*//1.cin.get();//一次只能读取一个字符char c = cin.get();//一次只能读取一个字符cout << c << endl;*/2.cin.get(一个参数);//一次只能读取一个字符//char ch1, ch2, ch3, ch4;//cin.get(ch1).get(ch2).get(ch3).get(ch4);//cout << ch1 << ch2 << ch3 << ch4 << endl;3.cin.get(一个参数,两个参数);//一次能读取一个字符串//char buffer[1024] = {0};//cin.get(buffer,1024);//读取缓冲区的时候,换行符不拿走,即读取到换行符之前//cout << buffer<< endl;4.按行读取,换行符丢弃//char buffer[1024] = { 0 };//cin.getline(buffer,1024);//cout << buffer << endl;5.忽略前n个字符,默认值为1	cin.ignore(参数);//cin.ignore(3);//char c = cin.get();//cout << c << endl;6.cin.peek();//char c = cin.peek();//拷贝第一个字符//cout << c << endl;//c = cin.get();//cout << c << endl;//7.cin.putback,返回读取的字符char c = cin.get();cout << c << endl;cin.putback(c);char buffer[1024] = { 0 };cin.getline(buffer,1024);cout << buffer << endl;
}//判断用户输入的是字符串还是数字
void test02()
{cout << "输入!\n" ;char c = cin.peek();if (c >= '\0' && c <= '9'){cout << "数字" << endl ;}elsecout << "String!" << endl;}int main()
{//test01();test02();system("pause");return 0;
}
3.2 标准的输出流1 字符输出2.格式化输出3.使用流对象的有关成员函数4.控制符格式化输出
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
using namespace std;void test01()
{1.打印一个字符//cout.put('c');//cout.put('c').put('c').put('c').put('c').put('c');2.打印一行//char buf[] = "hello world";//cout.write(buf, strlen(buf));3.占位符,实现格式化输出//int num = 99;//cout.width(20);//输出宽度为20,默认为空格//cout.fill('*');//没有数字占位的地方用*填充//cout.setf(ios::left);//默认占位从右开始,使用该命令后改为默认占位从左开始默认打印为十进制,改为其他进制的话需要先卸载//cout.unsetf(ios::dec);//卸载//cout.setf(ios::hex);//安装十六进制//cout.setf(ios::showbase);//显示基数(0x,0)//cout << num << endl;//4.通过控制符来格式化输出,引入头文件iomanipint num = 99;cout << setw(20);//设置宽度cout << setfill('~');//填充cout << setiosflags(ios::showbase);//显示基数cout << setiosflags(ios::left);//数据默认在左边cout << hex;//十六进制显示cout << oct;//八进制显示cout << num << endl;
}int main()
{test01();system("pause");return 0;
}
3.3 文件读写
1.把程序中的信息输出到缓冲区中,然后写道文件中
2.把磁盘信息输入到缓冲区,读到程序中,读文件1.逐行读取2.判断是否到文件尾部3.单个字符方式读取
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
using namespace std;
//1.把程序中的信息输出到缓冲区中,然后写道文件中
void test01()
{ofstream ofs;ofs.open("1234.txt", ios::out | ios::trunc);if (!ofs.is_open())cout << "打开失败!" << endl;ofs << "姓名:悟空!" << endl;ofs << "年龄:24" << endl;ofs << "身高:180" << endl;ofs.close();
}
//2.把磁盘信息输入到缓冲区,读到程序中
void test02()
{ifstream ifs;ifs.open("1234.txt", ios::in);if (!ifs.is_open())cout << "打开失败!" << endl;第一种方式读文件,逐行读取//char buffer[1024] = { 0 };//while (ifs >> buffer)//{//	cout << buffer << endl;//}第二种方式,判断是否到文件尾部//char buffer[1024] = { 0 };//while (!ifs.eof())//{//	ifs.getline(buffer, sizeof(buffer));//	cout << buffer << endl;//}//第三种方式,单个字符方式读取//char c;//while ((c = ifs.get()) != EOF)//{//	cout << c;//}ifs.close();
}int main()
{//test01();test02();system("pause");return 0;
}
3.4 二进制读取文件1.用成员函数read和write读写二进制文件2.它将内存中数据存储形式不加转换地传送到磁盘文件,因此它又称为内存数据的映
像文件。3.因为文件中的信息不是字符数据,而是字节中的二进制形式的信息,因此它又称为
字节文件。4.对二进制文件的操作也需要先打开文件,用完后要关闭文件。在打开时要ios::binary
指定为以二进制形式传送和存储。5.二进制文件除了可以作为输入文件或输出文件外,还可以是既能输入又能输出的文件。6.当文件读写的时候,类中的成员变量不要有string类型,因为string类中有一个成
员指针char*,该指针指向存储字符串的空间,当我们把string类的数据储存到文件中,
再读出文件的时候,不能保证指针有效。
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
using namespace std;class Student
{
public:Student(){}Student(const char* name,int age){this->age = age;strcpy(this->name, name);}char name[64];int age;
};//1.写
void test01()
{Student s1("张三", 18);Student s2("李四", 18);ofstream ofs;ofs.open("1234.txt",ios::out|ios::trunc|ios::binary);if (!ofs.is_open())cout << "打开失败!" << endl;ofs.write((const char*)&s1, sizeof(Student));ofs.write((const char*)&s2, sizeof(Student));ofs.close();}
//2.读
void test02()
{ifstream ifs;ifs.open("1234.txt", ios::in | ios::binary);if(!ifs.is_open())cout << "打开失败!" << endl;Student s1;Student s2;ifs.read((char*)&s1, sizeof(Student));ifs.read((char*)&s2, sizeof(Student));cout << s1.name <<s1.age<< endl;cout << s2.name << s2.age << endl;ifs.close();
}int main()
{//test01();test02();system("pause");return 0;
}


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部