通过改变一个变量的类型为别的类型,从而改变该变量的表达方式。
c++提供四种类型转换操作符
基本语法:int a = 100; char c = static_cast
例程
- #include
- #include
- #include
- using namespace std;
-
- class animal{};
- class people
- {
- public:
- int a;
- };
- class student:public people
- {
- public:
- int b;
- };
-
- int main(void)
- {
- //static_cast
- //基础类型转换,允许
- int a1=99;
- char c1 = static_cast<char>(a1);
- cout<<"c1="<
-
- //基础类型指针, 不允许转换
- //int *np = NULL;
- //char *cp = static_cast
(np); -
- //对象指针,不允许转换
- //people *p = NULL;
- //animal *st = static_cast
(p); -
- //转换具有继承关系的对象指针, 允许
- people *p = NULL;
- student *st = static_cast
(p); -
- //父类转子类,子类转父类。都允许转换
- student *st1 = NULL;
- people *p1 = static_cast
(st1); -
- //对象引用,同对象指针
- people p2;
- people &rep2 = p2;
- student &st2 = static_cast
(rep2); -
- //------------------------------------------------
- //dynamic_cast做类型安全检查,大空间转小空间是允许的。子类转父类
- student *st3 = NULL;
- people *p3 = dynamic_cast
(st3); -
- //但是小空间转大空间的时候(父类转子类),指针访问成员就会不安全,也就不被允许转换。
- //people *p4 = NULL;
- //student *st4 = dynamic_cast
(p4); -
- //------------------------------------------------
- //const_cast一般用于取消const修饰的指针、引用、或对象指针、对象引用。或者对非const的加上const修饰。
- int a = 10;
- const int &b = a; //此时已经不允许 修改b了 b=20是不被允许的
- int &c = const_cast<int &>(b);
- c = 20;
- cout<<"b="<
- cout<<"c="<
//打印出来都是一样的 -
- int aa = 100;
- int *bb = &aa;
- const int *cc = const_cast<const int *>(bb);
- //*cc = 200; 已经不被允许
-
- //------------------------------------------------
-
-
- return 0;
- }
-
-
(1)、static_cast 用于内置的类型转换(int、char),或者是有继承关系的对象指针、对象引用的转换。
(2)、dynamic_cast 只能转换有继承关系的对象指针、或引用。但是dynamic_cast会做类型安全检查。
(3)、const_cast一般用于取消const修饰的指针、引用、或对象指针、对象引用。或者对非const的加上const修饰。
(4)、reintrpret_cast 就是c语言的强转,要注意自己进行安全检查
结论:1、程序员必须清楚的知道要转换的变量,转换前是什么类型,转换后是什么类型,以及转换后有什么后果
2、一般情况下,不建议类型转换,避免进行类型转换。
2、c++异常机制
我们在C语言中处理异常,一般都是通过函数返回值来进行判断并处理。且C语言的异常处理逻辑完全交由程序员管理,必须逐级处理。如果func1中调用func2,又func2调用func3,如果func3返回的异常,func2没有处理,则在func1中可能发生不可预期的问题。
c++中提供了异常处理机制。当出现异常时,由程序员抛出异常,可以跳级捕获,并且一旦发生捕获异常,就必须处理异常。且异常抛出的类型没有做限定,可以是一个int、char等基础数据类型,也可以是一个类的对象、或者是结构体,并且异常本身也是一个类,拥有自己的成员,可以传递足够的信息。
下面看一个简单的案例,介绍了异常的语法
- #include
- #include
- #include
- using namespace std;
-
- int divide(int x, int y)
- {
- if (0 == y)
- {
- throw y;//抛出异常
- }
-
- return x/y;
- }
-
- void test()
- {
- //尝试捕获异常
- try
- {
- divide(10, 0);
- }
-
- //异常处理
- catch(int err)
- {
- //异常是根据类型进行匹配的,所以形参要加上int
- cout<<"错误:除数为"<
- }
- }
-
-
- void CallDivide(int x, int y)
- {
- divide(x, y);
- }
-
- //异常处理可以不用逐级响应,可以跳级处理。
- void test1()
- {
- try
- {
- CallDivide(10, 0);
- //异常应该是出现在CallDivide中,但是c++会跳级、跨函数处理,且一旦有异常出现,就必须会处理
- }
-
- //异常处理
- catch(int err)
- {
- //异常是根据类型进行匹配的,所以形参要加上int
- cout<<"错误:除数为"<
- }
- }
-
- int main(void)
- {
- test();
- test1();
-
- return 0;
- }
-
-
throw关键字抛出一个异常。
try{ do func... },执行方法,并尝试捕获异常
catch(数据类型){ 处理异常,do something ...},关键字根据数据类型匹配异常,并进行处理。catch抓住的数据,就是throw抛出的数据。
异常是跨函数的,异常必须被处理,如果不处理,程序会崩溃。有些编译器甚至不允许编译通过。
3、栈解旋
概念意义:在调用func中,出现了异常。异常被抛出且处理掉的时候,func中的局部对象、变量等会被释放。相当于return之前释放栈空间。
4、异常接口声明
(1)为了加强程序的可读性,可以在函数声明中列出可能抛出异常的所有类型。比如函数声明void func()throw(A,B);这个函数func只能抛出类型A,B及其子类型的异常
(2)如果函数声明中没有包含异常接口声明,则此函数可以抛出任何类型的异常
(3)一个不抛出任何类型异常的函数可以声明为void func()throw();
(4)如果一个函数抛出了他的异常接口声明锁不允许抛出的异常,unexcepted函数会被调用,该函数默认行为调用terminate函数中断程序。
注意:C++11已经弃用动态异常规范。
下面是一个抛出类对象的案例,注意分析对象的生命周期
- #include
- #include
- #include
- using namespace std;
-
- class myException
- {
- public:
- myException(const char *str)
- {
- cout<<"myException(char *str)..."<
- this->Err = new char[strlen(str)+1];
- strcpy(this->Err, str);
- }
-
- myException(const myException &another)
- {
- cout<<"myException(const myException &another)..."<
- if (NULL == another.Err)
- {
- this->Err = new char[0+1];
- strcpy(this->Err, "");
- }
- else
- {
- this->Err = new char[strlen(another.Err)+1];
- strcpy(this->Err, another.Err);
- }
- }
-
- myException & operator=(const myException &another)
- {
- cout<<"myException & operator=(const myException &another)..."<
- if (this->Err == another.Err)
- {
- return *this;
- }
-
- if (this->Err != NULL)
- {
- delete[] this->Err;
- this->Err = NULL;
- }
-
- this->Err = new char[strlen(another.Err)+1];
- strcpy(this->Err, another.Err);
- return *this;
- }
-
- ~myException()
- {
- cout<<"~myException()..."<
- if (this->Err != NULL)
- {
- delete[] this->Err;
- this->Err = NULL;
- }
- }
-
- void showErr()
- {
- cout<<this->Err<
- }
- public:
- char *Err;
- };
-
- void func()
- {
- myException p("异常!!!");
-
- throw p;
- //throw "exceptions!!!";
- }
-
- int main(void)
- {
- try
- {
- func();
-
- }
-
- catch(char const *str)
- {
- cout<
- }
-
- //如果使用指针 或者引用来接异常的时候,要注意栈变量的生命周期
- catch(myException err)
- {
- err.showErr();
- }
-
- return 0;
- }
-
-
执行结果
5、c++的标准异常类
(1)在实际使用中,我们往往自己定义个一个异常类,继承自标准异常类。这样有更好的使用便捷性。
(2) 在继承标准异常类时,应当重载父类的what函数和虚析构函数
6、案例:自定义异常类
- #include
- #include
- #include
- #include
- using namespace std;
-
- class myOutOfRange : public exception
- {
- public:
- myOutOfRange(const char *str)
- {
- cout<<"myOutOfRange(const char *str)..."<
- this->err = new char[strlen(str)+1];
- strcpy(this->err, str);
- }
-
- virtual const char* what() const noexcept
- {
- return err;
- }
-
- virtual ~myOutOfRange()
- {
- /*if (this->err != NULL)
- {
- delete[] this->err;
- }编译器差异,实际上vs上是需要自己手动释放的*/
- }
- public:
- char *err;
- };
-
- class people
- {
- public:
- people()
- {
- m_age = 0;
- }
-
- void setAge(int age)
- {
- if (age < 0 || age > 200)
- {
- throw myOutOfRange("年龄应该在0-200之间");
- }
-
- this->m_age = age;
- }
- public:
- int m_age;
- };
-
- void func()
- {
- people p;
-
- try
- {
- p.setAge(1000);
- }
-
-
- catch(exception err)
- {
- cout<
what()< - }
- }
-
- int main(void)
- {
- func();
- return 0;
- }
执行结果
-
相关阅读:
ZCMU--5115: Buying Keys(C语言)
kafka基础知识点整理
软考架构师知识点
Nginx日志分析和统计
6.网络编程套接字(上)
抽象工厂模式【设计模式】
神经网络在自动控制系统中的应用有哪些
爆肝总结,软件测试-常见并发问题+解决方案,测试进阶...
力扣第1047题 删除字符串中的所有相邻重复项 c++string stack巧解
Java高级面试题(二)-- JVM
-
原文地址:https://blog.csdn.net/tr_ainiyangyang/article/details/125977134