一、类型转换
在c++中类型转换不可以像在c语言中那样强制使用。
1)静态类型转换
函数原型: static_cast <目标原型>(原对象);
void test01()
{
char a = 'a';
double d = static_cast<double>(a);
cout << d << endl;
}
class Base{
public:
void fun(){};
};
class Son:public Base{
public:
void fun(){};
};
class Other{
};
void test2(){
Base*base=nullptr;
Son*son=nullptr;
Son*son2=static_cast<Son*>(base);
Base*base2=static_cast<Base*>(son);
}
总结:
- 语法 static_cast<目标类型>(原对象)
- 对于内置数据类型 是可以转换的
- 对于自定义数据类型,必须是父子之间的指针或者引用可以转换成功
2)动态类型转换
函数原型:dynamic_cast<目标类型>(原对象)
void test03()
{
Base * base = NULL;
Son * son = NULL;
Base * base2 = dynamic_cast<Base*>(son);
Base * base3 = new Son;
Son * son3 = dynamic_cast<Son*>(base3);
}
总结:
- 对于内置数据类型 不可以转换
- 对于自定义数据类型
- 父转子 不安全 转换失败
- 子转父 安全 转换成功
- 如果发生多态 ,那么总是安全的,都可以成功
3)常量转换
函数原型:const_cast<目标类型>(原对象)
void test04()
{
const int * p = NULL;
int * p2 = const_cast<int *>(p);
const int * p3 = const_cast<const int *>(p2);
const int a = 10;
const int & aRef = a;
int & aRef2 = const_cast<int &>(aRef);
}
总结:
二、异常处理
什么是异常处理呢???其实就是程序运行时出现异常的地方先去处理然后再继续执行程序(听君一席话如听一席话???)。
1)基本语法
异常的三个关键字 try throw catch
try 试图执行一段可能会出现异常的代码
throw出现异常后 抛出异常的关键字 throw + 类型
catch 捕获异常 catch(类型)
int myDivide(int a , int b)
{
if ( b == 0)
{
return -1;
}
return a / b;
}
void test01()
{
int a = 10;
int b = 0;
int c= myDivide(a,b);
}
当b=0时,c就会被赋值-1,而当b=-10时,c也会被赋值-1,这样情况在众多数据运算时就很难判断b是否真的是为0,得出结论C语言处理异常缺陷在于 返回的值 没有统一,返回的值可以是异常的结果,也可以是正确的结果,所以应该用异常处理来解决。
int myDivide(int a , int b)
{
if ( b == 0)
{
throw 1;
}
return a / b;
}
void test01()
{
int a = 10;
int b = 0;
try
{
int ret = myDivide(a, b);
cout << "ret 结果为: " << ret << endl;
}
catch (int )
{
cout << "int类型的异常的捕获" << endl;
}
}
class MyException
{
public:
void printError()
{
cout << "我自己的异常类的错误" << endl;
}
};
int myDivide(int a , int b)
{
if ( b == 0)
{
throw MyException();
}
return a / b;
}
void test01()
{
int a = 10;
int b = 0;
try
{
int ret = myDivide(a, b);
cout << "ret 结果为: " << ret << endl;
}
catch (int )
{
cout << "int类型的异常的捕获" << endl;
}
catch(MyException x){
x.printError();
}
class Person
{
public:
Person()
{
cout << "Person的构造函数" << endl;
}
~Person()
{
cout << "Person的析构函数" << endl;
}
};
int myDivide(int a , int b)
{
if ( b == 0)
{
Person p1;
Person p2;
throw MyException();
}
return a / b;
}
void test01()
{
int a = 10;
int b = 0;
try
{
int ret = myDivide(a, b);
cout << "ret 结果为: " << ret << endl;
}
catch(...){
cout<<"出现异常"<<endl;
}
}
结果:
Person的构造函数
Person的构造函数
Person的析构函数
Person的析构函数
出现异常
代码中catch(…){}这样写的好处就是不用写抛出异常的类型是啥,这样就可以直接捕获其他类型的异常。
- 栈解旋: 从try代码块开始起,到 throw抛出异常前,所有栈上的对象都被释放掉,释放的顺序和构造的顺序是相反的,这个过程称为栈解旋
总结:
- 如果想捕获其他类型的异常 catch( … )
- 如果捕获到的异常不想处理,想继续向上抛出 throw
- 异常必须要有人处理,如果没有处理,程序会自动调用 terminate函数,使程序中断
- 可以抛出一个自定义类型的异常 myException
- 栈解旋:从try代码块开始起,到 throw抛出异常前,所有栈上的对象都被释放掉,释放的顺序和构造的顺序是相反的,这个过程称为栈解旋
2)异常变量生命周期
class MyException
{
public:
MyException()
{
cout << "MyException构造函数调用" << endl;
}
MyException(const MyException & e)
{
cout << "MyException拷贝构造函数调用" << endl;
}
~MyException()
{
cout << "MyException的析构函数调用" << endl;
}
};
void doWork()
{
throw MyException();
}
void test01()
{
try
{
doWork();
}
catch (MyException &e)
{
cout << "MyException的异常捕获" << endl;
}
}
总结:
- MyException e会调用拷贝构造
- MyException &e 引用方式 接受 建议用这种方式 节省开销
- MyException *e 指针方式 接受 抛出 &MyException();匿名对象,对象被释放掉,不可以再操作e了
- MyException *e 指针方式 接受 抛出 new MyException(); 堆区创建的对象 记得手动释放 delete e;
- 建议使用 引用的方式 去接受对象
3)异常的多态使用
class BaseException
{
public:
virtual void printError() = 0;
};
class NULLPointException :public BaseException
{
public:
virtual void printError()
{
cout << "空指针异常" << endl;
}
};
class OutOfRangeException :public BaseException
{
public:
virtual void printError()
{
cout << "越界异常" << endl;
}
};
void doWork()
{
throw OutOfRangeException();
}
void test01()
{
try
{
doWork();
}
catch ( BaseException & e)
{
e.printError();
}
}
4)使用标准异常库
#include <stdexcept>
class Person
{
public:
Person(int age)
{
if (age < 0 || age > 150)
{
throw out_of_range("年龄必须在 0 到 150之间!");
}
this->m_Age = age;
}
int m_Age;
};
void test01()
{
try
{
Person p1(151);
}
catch (exception & e)
{
cout << e.what() << endl;
}
}
总结:
- 标准异常头文件 #include< std except>
- 使用系统异常类 out_of_range(“char *”)
- 捕获 catch( exception & e ) { cout << e.what() ; };
5)编写自己的异常类
class myOutOfRange :public exception
{
public:
myOutOfRange(char * errorInfo)
{
this->m_ErrorInfo = string(errorInfo);
}
myOutOfRange(string errorInfo)
{
this->m_ErrorInfo = errorInfo;
}
virtual ~myOutOfRange()
{
}
const char * what() const
{
return this->m_ErrorInfo.c_str();
}
string m_ErrorInfo;
};
class Person
{
public:
Person(int age)
{
if (age < 0 || age > 150)
{
throw myOutOfRange( "我的异常类 ---- 年龄必须在 0 到 150 之间");
}
this->m_Age = age;
}
int m_Age;
};
void test01()
{
try
{
Person p1(1111);
}
catch (exception & e)
{
cout << e.what() << endl;
}
}
总结:
- 自己编写的异常类myOutOfRange : public exception需要继承基类并且要重写虚函数what, 函数原型(const char * what() const)
- char * 和 string之间的转换
- char * 转 string string的有参构造 string(char *)
- string 转 const char * 需要用到 .c_str();
三、标准输入输出流
输入输出流中的结构图
1)标准输入流
void test01()
{
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;
}
void test02()
{
char buf[1024] = { 0};
cin.get(buf, 1024);
char c = cin.get();
if (c == '\n')
{
cout << "换行符遗留在缓冲区了" << endl;
}
else
{
cout << "换行符不在缓冲区了" << endl;
}
cout << "buf = " << buf << endl;
}
void test03()
{
char buf[1024] = { 0 };
cin.getline(buf, 1024);
char c = cin.get();
if (c == '\n')
{
cout << "换行符遗留在缓冲区了" << endl;
}
else
{
cout << "换行符不在缓冲区了" << endl;
}
cout << "buf = " << buf << endl;
}
void test04()
{
cin.ignore();
char c = cin.get();
cout << "c = " << c << endl;
}
void test05()
{
char c = cin.peek();
cout << "c = " << c << endl;
c = cin.get();
cout << "c = " << c << endl;
}
void test06()
{
char c = cin.get();
cin.putback(c);
char buf[1024];
cin.getline(buf, 1024);
cout << "buf = " << buf << endl;
}
void test07()
{
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;
}
}
void test08()
{
cout << "请输入 0 ~ 10 之间的数字" << endl;
int num;
while (true)
{
cin >> num;
if (num > 0 && num < 10)
{
cout << "输入正确 --- 数字为:" << num << endl;
break;
}
cout << "输入有误,请重新输入:" << endl;
cin.clear();
cin.sync();
cin.ignore();
}
}
总结:
- cin.get() 从缓冲区读取一个字符
- cin.get( 两个参数) 读取字符串, 换行符 遗留在缓冲区
- cin.getline(两个参数 ) 读取字符串 ,换行符 不会读取换行符,并且将换行符从缓冲区中扔掉
- cin.ignore() 忽略 ,默认忽略1个字符,如果(N)代表忽略N个字符
- cin.peek() 偷窥,从缓冲区中偷窥第一个字符,并不会取走
- cin.putback()放回,放回到缓冲区原来的位置
2)标准输出流
#include <iomanip>
void test01()
{
cout << "hello world" << endl;
}
void test02()
{
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;
}
void test03(){
int number = 99;
cout << setw(20)
<< setfill('~')
<< setiosflags(ios::showbase)
<< setiosflags(ios::left)
<< hex
<< number
<< endl;
}
总结:
- cout.put() cout.write() 利用成员函数 输出内容
- 通过流成员函数
- cout.width(20); //预留20空间
- cout.fill(’*’); //填充
- cout.setf(ios::left); //左对齐
- out.unsetf(ios::dec); //卸载十进制
- cout.setf(ios::hex); //安装十六进制
- cout.setf(ios::showbase); //设置显示进制 基数
- cout.unsetf(ios::hex); //卸载十六进制
- cout.setf(ios::oct); //安装八进制
|