• c++(25)STL:类型转换、异常机制


    1、类型转换

    通过改变一个变量的类型为别的类型,从而改变该变量的表达方式。

    c++提供四种类型转换操作符

     基本语法:int a = 100;  char c = static_cast(a);

      例程

    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. class animal{};
    6. class people
    7. {
    8. public:
    9. int a;
    10. };
    11. class student:public people
    12. {
    13. public:
    14. int b;
    15. };
    16. int main(void)
    17. {
    18. //static_cast
    19. //基础类型转换,允许
    20. int a1=99;
    21. char c1 = static_cast<char>(a1);
    22. cout<<"c1="<
    23. //基础类型指针, 不允许转换
    24. //int *np = NULL;
    25. //char *cp = static_cast(np);
    26. //对象指针,不允许转换
    27. //people *p = NULL;
    28. //animal *st = static_cast(p);
    29. //转换具有继承关系的对象指针, 允许
    30. people *p = NULL;
    31. student *st = static_cast(p);
    32. //父类转子类,子类转父类。都允许转换
    33. student *st1 = NULL;
    34. people *p1 = static_cast(st1);
    35. //对象引用,同对象指针
    36. people p2;
    37. people &rep2 = p2;
    38. student &st2 = static_cast(rep2);
    39. //------------------------------------------------
    40. //dynamic_cast做类型安全检查,大空间转小空间是允许的。子类转父类
    41. student *st3 = NULL;
    42. people *p3 = dynamic_cast(st3);
    43. //但是小空间转大空间的时候(父类转子类),指针访问成员就会不安全,也就不被允许转换。
    44. //people *p4 = NULL;
    45. //student *st4 = dynamic_cast(p4);
    46. //------------------------------------------------
    47. //const_cast一般用于取消const修饰的指针、引用、或对象指针、对象引用。或者对非const的加上const修饰。
    48. int a = 10;
    49. const int &b = a; //此时已经不允许 修改b了 b=20是不被允许的
    50. int &c = const_cast<int &>(b);
    51. c = 20;
    52. cout<<"a="<
    53. cout<<"b="<
    54. cout<<"c="<//打印出来都是一样的
    55. int aa = 100;
    56. int *bb = &aa;
    57. const int *cc = const_cast<const int *>(bb);
    58. //*cc = 200; 已经不被允许
    59. //------------------------------------------------
    60. return 0;
    61. }

    (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等基础数据类型,也可以是一个类的对象、或者是结构体,并且异常本身也是一个类,拥有自己的成员,可以传递足够的信息。

    下面看一个简单的案例,介绍了异常的语法

    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. int divide(int x, int y)
    6. {
    7. if (0 == y)
    8. {
    9. throw y;//抛出异常
    10. }
    11. return x/y;
    12. }
    13. void test()
    14. {
    15. //尝试捕获异常
    16. try
    17. {
    18. divide(10, 0);
    19. }
    20. //异常处理
    21. catch(int err)
    22. {
    23. //异常是根据类型进行匹配的,所以形参要加上int
    24. cout<<"错误:除数为"<
    25. }
    26. }
    27. void CallDivide(int x, int y)
    28. {
    29. divide(x, y);
    30. }
    31. //异常处理可以不用逐级响应,可以跳级处理。
    32. void test1()
    33. {
    34. try
    35. {
    36. CallDivide(10, 0);
    37. //异常应该是出现在CallDivide中,但是c++会跳级、跨函数处理,且一旦有异常出现,就必须会处理
    38. }
    39. //异常处理
    40. catch(int err)
    41. {
    42. //异常是根据类型进行匹配的,所以形参要加上int
    43. cout<<"错误:除数为"<
    44. }
    45. }
    46. int main(void)
    47. {
    48. test();
    49. test1();
    50. return 0;
    51. }

    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已经弃用动态异常规范。

    下面是一个抛出类对象的案例,注意分析对象的生命周期

    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. class myException
    6. {
    7. public:
    8. myException(const char *str)
    9. {
    10. cout<<"myException(char *str)..."<
    11. this->Err = new char[strlen(str)+1];
    12. strcpy(this->Err, str);
    13. }
    14. myException(const myException &another)
    15. {
    16. cout<<"myException(const myException &another)..."<
    17. if (NULL == another.Err)
    18. {
    19. this->Err = new char[0+1];
    20. strcpy(this->Err, "");
    21. }
    22. else
    23. {
    24. this->Err = new char[strlen(another.Err)+1];
    25. strcpy(this->Err, another.Err);
    26. }
    27. }
    28. myException & operator=(const myException &another)
    29. {
    30. cout<<"myException & operator=(const myException &another)..."<
    31. if (this->Err == another.Err)
    32. {
    33. return *this;
    34. }
    35. if (this->Err != NULL)
    36. {
    37. delete[] this->Err;
    38. this->Err = NULL;
    39. }
    40. this->Err = new char[strlen(another.Err)+1];
    41. strcpy(this->Err, another.Err);
    42. return *this;
    43. }
    44. ~myException()
    45. {
    46. cout<<"~myException()..."<
    47. if (this->Err != NULL)
    48. {
    49. delete[] this->Err;
    50. this->Err = NULL;
    51. }
    52. }
    53. void showErr()
    54. {
    55. cout<<this->Err<
    56. }
    57. public:
    58. char *Err;
    59. };
    60. void func()
    61. {
    62. myException p("异常!!!");
    63. throw p;
    64. //throw "exceptions!!!";
    65. }
    66. int main(void)
    67. {
    68. try
    69. {
    70. func();
    71. }
    72. catch(char const *str)
    73. {
    74. cout<
    75. }
    76. //如果使用指针 或者引用来接异常的时候,要注意栈变量的生命周期
    77. catch(myException err)
    78. {
    79. err.showErr();
    80. }
    81. return 0;
    82. }

    执行结果 

    5、c++的标准异常类

     (1)在实际使用中,我们往往自己定义个一个异常类,继承自标准异常类。这样有更好的使用便捷性。

    (2) 在继承标准异常类时,应当重载父类的what函数和虚析构函数

    6、案例:自定义异常类

    1. #include
    2. #include
    3. #include
    4. #include
    5. using namespace std;
    6. class myOutOfRange : public exception
    7. {
    8. public:
    9. myOutOfRange(const char *str)
    10. {
    11. cout<<"myOutOfRange(const char *str)..."<
    12. this->err = new char[strlen(str)+1];
    13. strcpy(this->err, str);
    14. }
    15. virtual const char* what() const noexcept
    16. {
    17. return err;
    18. }
    19. virtual ~myOutOfRange()
    20. {
    21. /*if (this->err != NULL)
    22. {
    23. delete[] this->err;
    24. }编译器差异,实际上vs上是需要自己手动释放的*/
    25. }
    26. public:
    27. char *err;
    28. };
    29. class people
    30. {
    31. public:
    32. people()
    33. {
    34. m_age = 0;
    35. }
    36. void setAge(int age)
    37. {
    38. if (age < 0 || age > 200)
    39. {
    40. throw myOutOfRange("年龄应该在0-200之间");
    41. }
    42. this->m_age = age;
    43. }
    44. public:
    45. int m_age;
    46. };
    47. void func()
    48. {
    49. people p;
    50. try
    51. {
    52. p.setAge(1000);
    53. }
    54. catch(exception err)
    55. {
    56. cout<what()<
    57. }
    58. }
    59. int main(void)
    60. {
    61. func();
    62. return 0;
    63. }

    执行结果

  • 相关阅读:
    ZCMU--5115: Buying Keys(C语言)
    kafka基础知识点整理
    软考架构师知识点
    Nginx日志分析和统计
    6.网络编程套接字(上)
    抽象工厂模式【设计模式】
    神经网络在自动控制系统中的应用有哪些
    爆肝总结,软件测试-常见并发问题+解决方案,测试进阶...
    力扣第1047题 删除字符串中的所有相邻重复项 c++string stack巧解
    Java高级面试题(二)-- JVM
  • 原文地址:https://blog.csdn.net/tr_ainiyangyang/article/details/125977134