1. 类型转换
静态类型转换-static_cast
使用方式:static_cast< 目标类型>(原始数据)
基础类型转换
void test()
{
char a = 'a';
double d = static_cast<double>(a);//隐式类型转换,将字符型转换为double类型
cout << "d =" << d << endl;//97
}
基类与派生类之间的转换
class Base{};//基类
class Child :public Base{};//派生类
class Other{};//其它类
void test2()
{
Base* base = NULL;
Child* child = NULL;
//把base转为Child*类型,向下转换,不安全
Child* child2 = static_cast<Child*>(base);
//把child转为Base*类型,向上转换,安全
Base* base2 = static_cast<Base*>(child);
//转other类型
//Other* other = static_cast<Other*>(base);类型转换无效
}
/*
子类转换成父类:安全。
父类转换成子类:不安全。
*/
动态类型转换-dynamic_cast
使用方式:dynamic_cast< 目标类型>(原始数据)
基础类型不可以转换
void test3()
{
//基础类型不可以转换
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 test4()
{
Base2* base = NULL;
Child2* child = NULL;
//child转Base2*,向上转,安全
Base2* base2 = dynamic_cast<Base2*>(child);
//base转Child2*,向下转,不安全
//Child2* child2 = dynamic_cast<Child2*>(base);
//dynamic_cast如果发生了多态,那么可以让基类转为派生类,向下转换
Base2* base3 = new Child2;
Child2* child3 = dynamic_cast<Child2*>(base3);
}
/*
子类转换成父类:可以。
父类转换成子类:不可以。
*/
//在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全
常量转换-const_cast
使用方式:const_cast< 目标类型>(原始数据)
void test5()
{
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 = const_cast<const int&>(numRef);
}
重新解释转换-最不安全,不推荐
void test6()
{
int a = 10;
int* p = reinterpret_cast<int*>(a);
Base* base = NULL;
Other* other = reinterpret_cast<Other*>(base);
}
2.异常的基本处理
int myDevide(int a, int b)
{
if (b == 0)
{
//如果b是异常,就抛出异常
//return -1;
throw - 1;//抛出int类型异常
throw 3.14;//抛出double类型异常
throw 'a';//抛出char类型异常,异常必须处理,否则会崩掉
}
return a / b;
}
void test1()
{
int a = 10;
int b = 0;
//int ret = myDevide(a, b);//早期如果返回-1,无法区分到底是结果还是异常
//C++中异常处理
try//试图执行 try{}中的内容
{
myDevide(a, b);
}
catch (int)//捕获异常
{
cout << "int类型异常捕获" << endl;
}
catch (double)//捕获异常
{
//如果不想处理这个异常,可以继续向上抛出
throw;
cout << "double类型异常捕获" << endl;
}
catch (...)//捕获异常
{
cout << "其他类型异常捕获" << endl;
}
}
int main()
{
try
{
test1();
}
catch (double)//如果异常都没有处理,那么成员terminate函数使程序中断
{
cout << "main函数中double类型异常捕获" << endl;
}
catch (...)//捕获异常
{
cout << "main函数中其他类型异常捕获" << endl;
}
system("pause");
return 0;
}
自定义异常类
class myExceotion //自定义异常类
{
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)
{
//栈解旋
//从try开始到throw抛出异常之前,所以栈上的对象都会被释放
//栈上构造和析构顺序相反
Person p1;
Person p2;
throw myExceotion();//匿名对象
}
return a / b;
}
void test1()
{
int a = 10;
int b = 0;
try
{
myDevide(a, b);
}
catch (myExceotion e)
{
e.printError();
}
catch (...)//捕获异常
{
cout << "其他类型异常捕获" << endl;
}
}
异常的接口说明:
如果想抛出特定的类型异常 ,可以利用异常的接口声明
void func() throw (int) 只能抛出 int类型
void func() throw() 不抛出任何类型异常
异常变量的生命周期
class myException
{
public:
myException()
{
cout << "myException的默认构造" << endl;
}
myException(const myException& e)
{
cout << "myException的拷贝构造" << endl;
}
~myException()
{
cout << "myException的析构调用" << endl;
}
};
void dowork()
{
throw new myException();
}
void test1()
{
try
{
dowork();
}
catch (myException *e)//myException e,会多开销一份数据,会调用拷贝构造,然后调用析构
//推荐使用MyException &e,就一份数据
{
cout << "捕获异常" << endl;
delete e;//自觉释放
}
}
异常的多态使用
利用多态来实现 printError同一个接口调用
抛出不同的错误对象,提示不同错误
//异常基类
class BaseException
{
public:
virtual void printError()
{
}
};
class NULLPointer :public BaseException
{
public:
virtual void printError()
{
cout << "空指针异常" << endl;
}
};
class OutofRange :public BaseException
{
public:
virtual void printError()
{
cout << "越界异常" << endl;
}
};
void dowork()
{
throw NULLPointer();
throw OutofRange();
}
void test1()
{
try
{
dowork();
}
catch (BaseException &e)
{
e.printError();
}
}
使用系统标准异常
//系统提供标准异常,要包含头文件
#include<stdexcept>
class Person
{
public:
Person(string name,int age)
{
this->m_name = name;
if (age < 0 || age>200)
{
throw out_of_range("年龄越界");
}
}
string m_name;
int m_age;
};
void test1()
{
try
{
Person p("李四", 300);
}
catch (out_of_range &e)
{
cout << e.what() << endl;
}
}
编写自己的异常类
class myOutOgRangException :public exception
//自己的异常类需要继承于系统提供的异常基类exception
{
public:
myOutOgRangException(string errorInfo)
{
this->m_ErrorInfo = errorInfo;
}
virtual ~myOutOgRangException()
{
}
virtual const char* what() const
{
//构造时候传入错误信息字符串,what返回这个字符串
//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 myOutOgRangException(string("年龄越界"));
}
}
string m_name;
int m_age;
};
void test1()
{
try
{
Person p("李四", 300);
}
catch (myOutOgRangException &e)
{
cout << e.what() << endl;
}
}
3.标准输入/输出流
cin.get 缓冲区中读取一个字符
void test()
{
//输入as
char c = cin.get();
cout << "c = " << c << endl;//a
c = cin.get();
cout << "c = " << c << endl;//s
c = cin.get();
cout << "c = " << c << endl;//换行
c = cin.get();
cout << "c = " << c << endl;//等待下一次输入
}
cin.get(两个参数) 不读换行符
void test1()
{
char buf[1024];
cin.get(buf, 1024);
char c = cin.get();
if (c == '\n')
{
cout << "换行还在缓冲区" << endl;
}
else
{
cout << "换行不在缓冲区" << endl;
}
cout << buf << endl;
}//cin.get(两个参数)读取字符串时,不会拿走换行符
cin.getline () 读取换行 并且扔掉
void test2()
{
char buf[1024];
cin.getline(buf, 1024);
char c = cin.get();
if (c == '\n')
{
cout << "换行还在缓冲区" << endl;
}
else
{
cout << "换行不在缓冲区" << endl;
}
cout << buf << endl;
}
cin.ignore 忽略 (N) N代表忽略字符数
void test3()
{
//输入ass,输出s
cin.ignore(2);//没有参数代表忽略一个字符,带参数N,忽略N个字符
char c = cin.get();
cout << "c=" << c << endl;
}
cin.peek 偷窥 偷看1个字符然后放回去
void test4()
{
//输入as
char c = cin.peek();//偷看a,再放回缓冲区
cout << "c=" << c << endl;//a
c = cin.get();
cout << "c=" << c << endl;//a
}
cin.putback 放回 把字符放回缓冲区
void test5()
{
char c = cin.get();
cin.putback(c);
char buf[1024];
cin.getline(buf, 1024);
cout << buf << endl;
}
案例1 判断输入的是字符串还是数字
void test6()
{
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;
}
}
案例2 输入1到10的数字,如果输入有误,重新输入
void test7()
{
int num;
while (true)
{
cin >> num;
if (num > 0 && num <= 10)
{
cout << "数字为:" << num << endl;
break;
}
//cout << "重新输入" << endl;
//重置标志位
cin.clear();
cin.ignore(numeric_limits<std::streamsize>::max(),'\n');//清空缓冲区
//vs新版本不支持cin.syne()清空缓冲区
cout << "标志位:" << cin.fail() << endl;//标志位0是正常的,1是不正常的
}
}
cout.put()和cout.write()
void test1()
{
cout.put('a').put('b');
char buf[1024] = "hello";
cout.write(buf,strlen(buf));
}
流对象的成员函数
void test2()
{
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);//强制输出整数基数,0/0x
cout.unsetf(ios::hex);//卸载十六进制
cout.setf(ios::oct);//安装八进制
cout << number << endl;
}
使用控制符
#include <iomanip>//使用控制符的头文件
void test3()
{
int number = 99;
cout << setw(20)//宽度格式设置20
<< setfill('~')//填充~
<< setiosflags(ios::showbase)//强制输出整数基数
<< setiosflags(ios::left)//设置格式,输出内容左对齐
<< hex
<< number
<< endl;
}
4.文件操作
#include <fstream>//文件读写头文件
//写文件
void test1()
{
//以输出的方式打开文件
//ofstream ofs("./test.txt", ios::out | ios::trunc);
//后期指定打开方式
ofstream ofs;
ofs.open("./test.txt", ios::out | ios::trunc);
if (ofs.is_open())
{
cout << "打开成功" << endl;
}
else
{
cout << "打开失败" << endl;
}
ofs << "姓名:李四" << endl;
ofs << "年龄:94" << endl;
ofs << "性别:男" << endl;
}
//读文件
void test2()
{
ifstream ifs;
ifs.open("./test.txt", ios::in);
if (ifs.is_open())
{
cout << "打开成功" << endl;
}
else
{
cout << "打开失败" << endl;
}
//第一种读的方式
//char buf[1024];
//while (ifs >> buf)//按行读
//{
// cout << buf << endl;
//}
//第二种读的方式
//char buf[1024];
//while (!ifs.eof())//eof读到文件尾部
//{
// ifs.getline(buf, sizeof(buf));
// cout << buf << endl;
//}
//第三种读的方式
//char c;
//while ((c = ifs.get()) != EOF)//按照单个字符读取,EOF文件尾
//{
//cout << c;
//}
}