c++类型转化,c++严格遵守类型匹配
静态转换static_cast的用法
1.用于类层次结构中基类和派生类指针或者引用之间的转换
子类---->父类(不安全)
父类----->子类(安全)
2.普通的类型转换
//基本类型转化
#include<iostream>
using namespace std;
int main()
{
char a = 'c';
double b = static_cast<double>(a);
cout << b << endl;
return 0;
}
不存在父子关系的类无法转换
#include<iostream>
using namespace std;
class father{};
class child : public father{};
void test()
{
father *p1 = NULL;
child *p2 = NULL;
//派生类向基类转换(不安全)
father* pp1 = static_cast<father*>(p2);
//基类转派生类(安全)
child* pp2 = static_cast<child*>(p1);
}
int main()
{
test();
return 0;
}
动态类型转换dynamic_cast:
dynamic_cast非常的严格失去精度或者不安全都不可以转换。类似于上面的派生类转基类
#include<iostream>
using namespace std;
class father
{
public:
virtual void func(){} //虚函数
};
class child : public father
{
public:
void func(){}
};
void test()
{
father *p = new child; //父类的指针指向子类的对象
child *b = dynamic_cast<child*>(p); //由父类转为子类是不安全的,但是这里发生了多态,所有就可以使用动态的类型转换
}
int main()
{
test();
return 0;
}
常量转换const_cast:
只能对指针或者引用进行转换,但是一般不用,我们只需要强制类型转换即可
void test2()
{
int* a =NULL;
const int* b = NULL;
//去掉const
int* c = const_cast<int*>(b);
//加上const
const int* d = const_cast<const int*>(a);
int e;
int& f = e;
const int& h = e;
//加上const
const int& g = const_cast<const int&>(f);
//去掉const
int& L = const_cast<int&>(h);
}
重新解释转换reinterpret_cast:(最不安全)
这个不太适用就不解释了
异常的基本使用:
//基本使用
#include<iostream>
using namespace std;
void func(int a,int b)
{
if (b == 0)
{
throw - 1;//抛出异常
}
}
void test()
{
int a = 10;
int b = 0;
try
{
func(a, b);
}
catch (int) //捕获int异常
{
cout << "异常已经被捕获\n";
}
catch (...) //捕获任意类型异常
{
cout << "其他异常被捕获\n";
}
int main()
{
test();
return 0;
}
异常的跳级处理:
#include<iostream>
using namespace std;
void func(int a, int b)
{
if (b == 0)
{
throw - 1;//抛出异常
}
}
void test()
{
int a = 10;
int b = 0;
try
{
func(a, b);
}
catch (int) //捕获int异常
{
cout << "test函数捕获异常\n";
}
}
//main函数包含test()函数,test函数包含func()函数,并且每一层包含下一层的异常捕获 。
//然后main函数开始执行,调用test函数,然后test函数调用func函数,function函数抛出异常,先返回并且被test函数捕获处理
//这时候main函数里面的异常捕获并没有发挥作用
int main()
{
try
{
test();
}
catch (int)
{
cout << "main函数捕获int异常\n";
}
return 0;
}
要是test函数不想处理异常可以把异常抛给下一级
catch (int) //捕获int异常
{
throw; //加上这行代码异常将会抛给main函数
cout << "test函数捕获异常\n";
}
如果throw的异常都没有人处理,那么程序将崩溃。调用terminate函数中断程序。
捕获自定义的类异常:
#include<iostream>
using namespace std;
class person{};
void func(int a,int b)
{
if (b == 0)
throw person();//类名()表示匿名对象
}
void test()
{
int a = 10;
int b = 0;
try //尝试执行这个函数
{
func(a,b);
}
catch (person)
{
cout << "自定义类型异常\n";
}
}
int main()
{
test();
return 0;
}
c++异常处理方式,使得异常的引发和处理不必在一个函数中,这样底层的函数可以着重去解决具体的问题,而不必过多考虑异常的处理。
栈解旋:
栈解旋的定义:从try开始到throw抛出异常之前,所有栈上的对象都会被释放。(出现异常的情况下)
#include<iostream>
using namespace std;
class father{}; //用来抛出异常的自定义类型
class person //用来查看栈解旋的类
{
public:
person()
{
cout << "构造函数\n";
}
~person()
{
cout << "析构函数\n";
}
};
void func(int a, int b)
{
if (b == 0)
{
person p1;
person p2;
throw father();//类名()表示匿名对象,出现错误就抛出father类型对象
}
}
void test()
{
int a = 10;
int b = 0;
try //尝试执行这个函数
{
func(a, b);
}
catch (father) ///捕获father类型的异常
{
cout << "自定义类型异常\n";
}
}
int main()
{
test();
return 0;
}
运行结果:
构造函数
构造函数
析构函数
析构函数
自定义类型异常
请按任意键继续. . .
在处理异常之前就将栈释放,在main函数return之前就释放
异常在多态类的使用:
#include<iostream>
using namespace std;
class father //父类
{
public:
virtual void FUNC()
{}
};
class child1 :public father
{
public:
virtual void FUNC()
{
cout << "壹号异常\n";
}
};
class child2 :public father
{
public:
virtual void FUNC()
{
cout << "贰号异常\n";
}
};
void func(int a, int b)
{
if (b == 0)
{
throw child1(); //这里抛出的是派生类异常
}
}
void test()
{
int a = 10;
int b = 0;
try //尝试执行这个函数
{
func(a, b);
}
catch (father& e) //这里捕获的是父类的对象,用父类的指针或者引用指向子类的对象 ,已经发生了多态
{
e.FUNC(); //既然已经发生了多态就是晚绑定,运行时绑定,那么就会调用类同名函数(FUNC)
}
}
int main()
{
test();
return 0;
}
使用系统自定义的异常类:
c++给我们也提供了很多的异常类,他们都是通过继承的方式组织起来的。
#include<iostream>
#include<stdexcept> //包含头文件
using namespace std;
class person
{
public:
person(string a,int b)
{
this->ages = b;
this->name = a;
if (b > 200 || b < 0)
{
throw out_of_range("年龄越界了\n");
}
}
string name;
int ages;
};
void test()
{
try
{
person p("刘老师", 1000);
}
catch (out_of_range& e) //这里推荐传引用,out_of_range其实也是一个类类型
{
cout <<e.what(); //每个错误类都包含一个what()
}
}
int main()
{
test();
return 0;
}
自己编写异常类:
#include<iostream>
#include<string>
using namespace std;
//_EXCEPTION_INLINE virtual __CLR_OR_THIS_CALL ~exception() _NOEXCEPT;
//_EXCEPTION_INLINE virtual const char * __CLR_OR_THIS_CALL what() const;
//c++中所有的系统自定义异常都是继承exception类,基类中有很多函数,我们要进行重写只需要对用到的函数进行重写就可以了
class perro:public exception //点击F12可以查看基类,现在对上面的两个函数进行重写,因为不会继承到构造函数所以自己写
{
public:
perro(string error)
{
this->error = error;
}
virtual ~perro() //因为也没有在堆上创建对象所以这个析构也就不自己实现了
{
}
virtual const char * what() const
{
return this->error.c_str(); //以为基类的what函数返回值是char* 类所以我们要对string类型进行强转
}
string error;
};
class person
{
public:
person(string name, int ages)
{
this->name = name;
if (ages<0 || ages>200)
{
throw perro("年龄太大了");
}
else
this->ages = ages;
}
string name;
int ages;
};
void test()
{
try
{
person p("猪八戒", 300);
}
catch (perro & p1)
{
cout << p1.what() << endl;
}
}
int main()
{
test();
return 0;
}
C++输入输出流:
C++输入输出包含三方面的内容,标准IO(标准的键盘到屏幕,输出显示到键盘),文件IO(操作的是外存磁盘文件之间的输入输出),串IO(对内存中的指定的空间进行输入输出,通常指数组)
i-o-stream采用的是菱形继承,设计这个的大牛说的是,如果让他再设计一次,他不会再用菱形继承了,因为隐患太大了
标准输入输出:
//cin.get()一次只能读取一个字符
//cin.get(一个参数)读一个字符
//cin.get(两个参数)可以读字符串
//cin.getline()
//cin.ignore()
//cin.peek()
//cin.putback()
#include<iostream>
using namespace std;
void test()
{
char c = cin.get();
cout << "c =" << c << endl;
}
int main()
{
test();
return 0;
}
运行结果:
abc
c =a
请按任意键继续. . .
#include<iostream>
using namespace std;
void test()
{
char c = cin.get();
cout << "c =" << c << endl;
c = cin.get();
cout << "c =" << c << endl;
}
int main()
{
test();
return 0;
}
运行结果:
as
c =a
c =s
请按任意键继续. . .
#include<iostream>
using namespace std;
void test()
{
char c = cin.get();
cout << "c =" << c << endl;
c = cin.get();
cout << "c =" << c << endl;
c = cin.get();
cout << "c =" << c << endl;
}
int main()
{
test();
return 0;
}
运行结果:
as
c =a
c =s
c =
请按任意键继续. . .
//缓冲区有三个,一个a,s,\n,依次将三个字符读取出来
#include<iostream>
using namespace std;
void test()
{
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;
}
int main()
{
test();
return 0;
}
运行结果:
as
c =a
c =s
c =
卡在了这里,程序在等你继续输入,因为缓冲区里面的三个字符都已经被读取完毕了
#include<iostream>
using namespace std;
//cin.get(两个参数)不会把缓冲区中的换行符拿走,也就是说换行符还在缓冲区之中
void test2()
{
char buf[1024];
cin.get(buf, 1024); //等待输入一个字符串
cout << buf << endl;
//关于换行符是否还在缓冲区之中我们来读取一下
char c = cin.get(); //如果缓冲区中有数据就从缓冲区中读取一个字符
if (c == '\n')
{
cout << "换行符还在缓冲区\n";
}
}
int main()
{
test2();
return 0;
}
运行结果:
ahichiaudhv
ahichiaudhv
换行符还在缓冲区
请按任意键继续. . .
cin.get(一个参数)
#include<iostream>
using namespace std;
void test3()
{
char ch;
cin.get(ch);
cout << ch;
cin.get(ch);
cout << ch;
}
int main()
{
test3();
return 0;
}
运行结果:
a
a
换行符还在缓冲区
请按任意键继续. . .
#include<iostream>
using namespace std;
void test4()
{
char buf[1024];
cin.getline(buf,1024); //cin系列函数的意思都是从缓冲区读取多大长度的字符,只是读取,你没让输出的话不会输出
char c;
c = cin.get();
if (c == '\n')
{
cout << "换行符还在缓冲区\n";
}
}
int main()
{
test4();
return 0;
}
运行结果:
abc
//什么意思呢?当你输入abc\n之后然后abc被getline读取了,然后char c并没有拿到\n,在等你输入数据,这是因为getline将换行符读取了,只是将换行符扔了而已
#include<iostream>
using namespace std;
void test5()
{
cin.ignore();
char c = cin.get();
cout << c << endl;
}
int main()
{
test5();
return 0;
}
运行结果:
as
s
请按任意键继续. . .
//读取一个字符并扔掉
#include<iostream>
using namespace std;
void test6()
{
char c = cin.peek(); //偷窥,从缓冲区偷窥一个字符但不拿出来
cout << c << endl;
char b = cin.get();
cout << b << endl;
}
int main()
{
test6();
return 0;
}
结果:
as
a
a
请按任意键继续. . .
#include<iostream>
using namespace std;
void test7()
{
char c = cin.get();
cout << c << endl;
cin.putback(c);
char buf[1024];
cin.get(buf, 1024);
cout << buf << endl;
}
int main()
{
test7();
return 0;
}
运行结果:
hello world
h
hello world
请按任意键继续. . .
//cin.get()从缓冲区读取一个字符并且打印,然后cin.back()再将c又放了回去,然后再由get(两个参数)完整打印