C++09 Posted on 2020-04-20 Words count in article: 3.3k | Reading time ≈ 14 Day09总结类型转换123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142/* * 类型转换——静态类型和动态类型转换(static cast) * 类型转换——常量类型——重新解释类型转换 * * 一般情况下,尽量少的去使用类型转换,除非来解决非常特殊的问题 * * 1.静态转换 * 1.1用于类层次结构中基类(父类)和派生类(子类)之间引用或者指针的转换 * 1.1.1进行上行转换(派生类引用转换成基类)是安全的 * 1.1.2进行下行转换(基类指针引用转换成派生类)是不安全的* 1.2 用于基本数据类型之间的转换,如把int转换成char。 * 这种转换的安全性也要开发人员来保证 * * * 静态类型转换 static_cast * 语法 static_cast<目标类型>(原对象) * 对于内置数据类型是可以转换的 * 对于自定义数据类型,必须是父子之间的指针或者引用可以转换成功 * 2.动态类型转换 * 语法 dynamic_cast<目标类型>(原对象) * 对于内置数据类型是不可以转换的 * 对于自定义数据类型 * 父转子:不安全,转换失败 * 子转父:安全,转换成功 * 如果发生堕胎,总是安全的 * 3.常量转换(const_cast) * 该运算符用来修改类型的const属性 * 常量指针被转化为非常量指针,并且仍然指向原来的对象 * 常量引用被转化为非常量引用,并且仍然指向原来的对象 * 注意:不能直接对非指针和非引用的变量使用const_cast 操作符去直接移除其const * *//*******************************************************///1.静态类型转换#include<bits/stdc++.h>using namespace std;//1.1 内置数据类型的静态类型转换void test01(){ //内置数据类型 char a='a'; //static_cast<目标类型>(原对象) double d = static_cast<double>(a); cout<<d<<endl;}//1.2 (指针实现)自定义数据类型的静态类型转换class Base{ virtual void func(){}};class Son:public Base{ virtual void func(){}};class Other{};void test02(){ //自定义数据类型 Base*base =NULL; Son *son =NULL; //base转为Son*类型 向下类型转换 不安全 Son*son2 = static_cast<Son*>(base); //Son 转为Base*类型 向上类型转换 安全 Base*base2 = static_cast<Base*>(son); //base 转为Other* 是不会成功的 //因为没有父子关系 /*Other*other = static_cast<Base*>(Other);*/}//1.3(引用实现)静态类型转换void test03(){ Base base; Son son; Base& base1 =base; Son& son1 = son; //Son 转为Base*类型 向上类型转换 安全 Base& base2 = static_cast<Base&>(son1); //base转为Son*类型 向下类型转换 不安全 Son& son2 = static_cast<Son&>(base1); //无继承关系之间的转换 是不成功的 /*Other&other = static_cast<Base&>(Other);*/}/*********************************************************///2.动态类型转换void test04(){ //内置数据类型,是不允许内置数据类型之间的转换的 char c = 'c'; //以下代码会报错 /* double d = dynamic_cast<double>(c);*/}void test05(){ //base转为Son*类型 向下类型转换 不安全 //不安全,转换失败 Base*base =NULL; Son *son =NULL; /*Son*son2 = dynamic_cast<Son*>(base);*/ //Son 转为Base*类型 向上类型转换 安全 Base*base2 = dynamic_cast<Base*>(son); //如果发生多态,那么父子之间转换总是安全的 Base *base3 = new Son; //将base3转为Son* Son*son3 = dynamic_cast<Son*>(base3);}/*********************************************************///3.常量转换//3.1指针类型的转换void test06(){ const int *p =NULL; //将const int*转为int* int *p2 = const_cast<int *>(p); //将 p2转为const int* const int *p3 = const_cast<const int *>(p2);}//3.2 指针类型的转换void test07(){ const int a = 10;//放在符号表中,直接拿掉不可以!! const int &aRef = a; int &aRef2 = const_cast<int&>(aRef); //注意:不能直接对非指针和非引用的变量使用const_cast 操作符去直接移除其const /*int b = const_cast<int>(a);*/}/********************************************************///4.重新解释转换 最不安全 不建议用void test08(){ int a = 10; int *p = reinterpret_cast<int*>(a); //将base*转为Other* Base*base = NULL; Other *other = reinterpret_cast<Other*>(base);//是可以转换成功的,就会引起很多操作问题 //不建议使用} 异常的基本语法 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101/* * 三个关键字 try throw catch * try:试图执行一段可能会出现异常的代码 * throw:出现异常后,抛出异常的关键字 throw+类型 * catch :捕获异常,catch(类型) * 如果在try段执行期间没有异常,那么跟在try后面的catch字句就不会执行 * catch字句会根据出现的先后顺序被检查,匹配的catch语句捕获并处理异常(或继续抛出异常) * 如果匹配的处理未找到,则于宁函数terminate 将自动被调用,其缺省功能调用abort 终止程序 * 如果处理不了的异常,可以在catch的最后一个分支,使用throw,向上抛 * * 可以自定义自己的异常类MyError * */#include<bits/stdc++.h>using namespace std;class MyError{public: void printError() { cout<<"我自己的异常类错误"<<endl; }};class Person{public: Person() { cout<<"Person的构造函数的调用"<<endl; } ~Person() { cout<<"Person的析构函数的调用"<<endl; }};int myDivide(int a, int b){ if(b==0) { /*return -1;*///C语言处理异常缺陷在于,返回值没有统一,返回的值可以是异常的结果,也可以是正确的结果 /*throw 3.14*/;//抛出一个1也可以,3.14也可以,不过需要捕获double类型 //有throw,必要catch Person p1; Person p2; cout<<"AAA"<<endl; //可以发现,Person p1,p2在throw之间,就已经被释放掉了 /*这就叫栈解旋:从try代码块开始其,到throw抛出异常前 所有栈上的对象都被释放掉,释放的顺序和构造的顺序都是相反的。*/ throw MyError(); } return a/b;//当a/b=-1时,无法判断是否出错}void test01(){ int a = 10; int b= 0; //尝试执行一段可能会出现异常的代码 try { int ret = myDivide(a,b); cout<<"ret的结果为 "<<ret<<endl; } catch (double) { //捕获到double以后,不想处理这个异常,想继续往上抛,直接加throw throw ; cout<<"double 类型异常的捕获"<<endl; } catch (MyError) { cout<<"找到啦"<<endl; } catch (...) { cout<<"其他 类型异常的捕获"<<endl; }}int main(){ try { test01(); }// catch (double)// {// cout<<"double 类型异常的捕获"<<endl;// } catch (int) { cout<<"MAin 函数Int 类型异常的捕获"<<endl; } catch (...) { cout<<"Main 函数其他 类型异常的捕获"<<endl; } //异常必须要有人处理,如果 system("pause"); return 0;} 异常变量的声明周期1234567891011121314151617181920212223242526272829303132333435363738394041/* *异常变量的生命周期 * 1.catch (MyException e)会用拷贝构造 2.catch (MyException &e) 引用方式,建议用这种方式,节省开销 3.catch (MyException *e)指针方式,接收抛出 new MyException();堆区创建的对象,记得手动释放delete e; * */#include<bits/stdc++.h>using namespace std;class MyException{public: MyException() { cout<<"MyException构造函数的调用"<<endl; } MyException(const MyException&myException) { cout<<"MyException拷贝函数的调用"<<endl; } ~MyException() { cout<<"MyException析构函数的调用"<<endl; }};void doWork(const char *string1){ throw MyException();}void test01(){ try { doWork(nullptr); }// catch (MyException e)会用拷贝构造// catch (MyException &e) 引用方式,建议用这种方式,节省开销// catch (MyException *e)指针方式,接收抛出 new MyException();堆区创建的对象,记得手动释放delete e; catch (MyException &e) { cout<<"MyException异常捕获"<<endl; }} 异常多态的使用1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950/* * 异常的多态使用 * 提供基类异常类:BaseException 纯虚函数 virtual void printError()=0; * 提供两个子类继承异常基类,重写父类中的纯虚函数 * 测试 利用父类引用去接受子类对象,实现多态 * 抛出那种一场就打印哪种异常的printError函数 * * */#include<bits/stdc++.h>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(const char *string1){// throw NullPointerException(); throw OutOfRangeException();}void test01(){ try { doWork(nullptr); } catch (BaseException&baseException) { baseException.printError(); }} 系统标准异常类 123456789101112131415161718192021222324252627282930313233343536/* * 使用系统标准异常类 * 标准异常头文件#include <stdexcept> * 使用系统异常类 out_of_range("char*)等 * 捕获:catch (exception &e)或者对应类 * * */#include<bits/stdc++.h>using namespace std;//使用系统标准依然需要引用一个头文件//#include <stdexcept>class Person{public: Person(int age) { if(age<0||age>150) { //年龄越界异常抛出 throw out_of_range("年龄必须在100-150之间"); } this->m_Age = age; } int m_Age;};void test01(){ try { Person p1(151); } catch (out_of_range&e)//也可以catch(exception&e) { cout<<e.what()<<endl; }} 标准输入流123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129/* * 输入输出流 * cin.get()一次只能读取一个字符 * cin.get(一个参数)读取一个字符 * cin.get(两个参数)可以读取字符串,不会读取换行符 * cin.getline()读取一行,会读取换行符 * cin.ignore() 忽略字符 * cin.peek()偷窥,偷看一个字符然后再放回缓冲区 * cin.putback()把字符放回缓冲区 * * */using namespace std;/********************************************************/void test01(){ //输入as 缓冲区中有 a s \n 第一个拿a,第二个拿s 第三个拿\n //第四个等待输入 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;}/*********************************************************///cin.get(两个参数)读取字符串的时候,不会读取换行符。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.getline()void test03(){ char buf[1024]; cin.getline(buf,1024); char c = cin.get(); if(c=='\n') { cout<<"换行还在缓冲区"<<endl; }else cout<<"换行不在缓冲区"<<endl;// cin.getline 把换行符读取,并且扔掉 cout<<buf<<endl;}/*********************************************************///cin.ignore ()void test04(){ cin.ignore(2);//没有参数代表忽略一个字符 //带参数,则说明忽略了n个字符 char c =cin.get(); cout<<"c ="<<c<<endl;}/*********************************************************///cin.peek()void test05(){ //输入as 看一眼 a,然后再放回缓冲区 缓冲区中还是as char c = cin.peek(); cout<<"c = "<<endl; 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]; cin.getline(buf,1024); cout<<buf<<endl; //先拿走,后来又放回去了}/******************************************************///判断用户输入的内容,是字符串还是数字void test07(){ cout<<"请输入一个字符串或者数字:"<<endl; char c = cin.peek(); if(c>='0'&&c<='9') { int num; cin>>num; cout<<"您输入的是数字"<<num<<endl; } else if(c>='a'&&c<='z') { char buf[1024] = {0}; cin>>buf; cout<<"您输入的是字符串"<<buf<<endl; }else { cout<<"您输入的是啥玩意??"<<endl; }}/********************************************************///让用户输入一个数字,必须在0-10之间的数字,如果输入有误,重新输入void test08(){ cout<<"请输入0-10之间的数字"<<endl; int num; while(1) { cin >> num; if (num > 0 && num <= 10) { cout << "输入正确——数字为" << num << endl; break;//输入正确就退出 } cout << "输入有误"<<endl; //缓冲区中的标志位 cin.clear(); cin.sync();//清空标志位,并且刷新缓冲区// cout<<"Cin.fail = "<<cin.fail()<<endl; }} 标准输出流1234567891011121314151617181920212223242526272829303132333435363738394041424344454647/* * 标准输出流 * cout.put() 缓冲区写字符 * cout.write()从buffer中写num个字节到当前输出流中 * * * */#include<bits/stdc++.h>using namespace std;void test01(){ /* cout.put('a').put('b'); char buf[] = "helloworld"; cout.write(buf,strlen(buf)); */}//格式化输出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);//卸载十六0进制 cout.setf(ios::oct);//安装八进制 cout<<number<<endl;//打印}//使用控制符void test03(){ int number = 88; cout<<setw(20) <<setfill('*') <<setiosflags(ios::showbase)//显示基数 <<setiosflags(ios::left)//左对齐 <<hex //安装十六进制 <<number <<endl;} -------------本文结束,感谢您的阅读------------- Post author: Jason Post link: https://jasonxqh.github.io/2020/04/20/C-09/ Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 3.0 unless stating additionally.