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: