异常
常见的异常包括:数组下标越界,除法计算的时候除数为0,动态分配空间时空间不足。
try,throw,catch
#include <iostream>
using namespace std;
int main()
{
double m = 1, n = 0;
try {
cout << "before dividing." << endl;
if (n == 0)
throw - 1; //抛出int型异常
else if (m == 0)
throw - 1.0; //拋出 double 型异常
else
cout << m / n << endl;
cout << "after dividing." << endl;
}
catch (double d) {
cout << "catch (double)" << d << endl;
}
catch (...) {
cout << "catch (...)" << endl;
}
cout << "finished" << endl;
return 0;
}
//运行结果
//before dividing.
//catch (...)
//finished
函数的异常声明列表
int fun() throw(int,double,A,B,C){...};
可以在函数声明和定义的时候,指出所能抛出异常的列表,如果throw中为空,表明不会抛出任何异常,如果没有throw则可能抛出任何异常。
C++标准异常类
bad_typeid
如果其操作数是一个多态类指针,而该指针的值为NULL,则会抛出这个异常。
#include <iostream>
#include <typeinfo>
using namespace std;
class A{
public:
virtual ~A();
};
using namespace std;
int main() {
A* a = NULL;
try {
cout << typeid(*a).name() << endl; // Error condition
}
catch (bad_typeid){
cout << "Object is NULL" << endl;
}
return 0;
}
//运行结果:bject is NULL
bad_cast
在用dynamic_cast进行多态基类对象或引用到派生类的引用的强制类型转换时,如果转换是不安全的,则会抛出这个异常。
bad_alloc
没有足够内存
out_of_range
下标越界。
C++是如何处理多个异常的
异常处理基本思想:执行一个函数的过程中发现异常,可以不用在本函数内立即进行处理, 而是抛出该异常,让函数的调用者直接或间接处理这个问题。 C++异常处理机制由3个模块组成:try(检查)、throw(抛出)、catch(捕获) 抛出异常的语句格式为:throw 表达式;如果try块中程序段发现了异常则抛出异常。
try { 可能抛出异常的语句;(检查) try
{
可能抛出异常的语句;(检查)
}
catch(类型名[形参名])//捕获特定类型的异常
{
//处理1;
}
catch(类型名[形参名])//捕获特定类型的异常
{
//处理2;
}
catch(…)//捕获所有类型的异常
{
}
类型转换
reinterpret_cast
reinterpret_cast<type-id> (expression)
,type-id必须是一个指针、引用、算术类型、函数指针或者成员指针,可以用于类型之间的强制转换。
const_cast
const_cast<type_id> (expression)
,用法如下:
- 常量指针被转化成非常量指针,并且仍然指向原来的对象
- 常量引用被转换成非常量引用,并且仍然指向原来的对象
- const_cast一般用于修改底指针,比如const char*p的形式
static_cast
static_cast < type-id > (expression)
该运算符将experssion转换为type-id类型,但是没有运行时类型检查来保证转换安全性。主要有以下几种用途:
- 类层次结构中基类和派生类之间引用或者指针的转换
- 用于基本数据类型之间的转换,比如把int转换成char,安全性需要由开发人员来保证
- 把空指针转换成目标类型的空指针
- 把任何类型的表达式转换成void类型
注意:stati_cast不能转换掉expression的const、volatile、或者_unaligned属性
dynamic_cast
dynamic_cast <type-id> (expression)
有类型检查。type-id必须是类的指针、类的引用或者void*。- 如果 type-id 是类指针类型,那么expression也必须是一个指针,如果 type-id 是一个引用,那么 expression 也必须是一个引用。
- dynamic_cast运算符可以在执行期决定真正的类型,也就是说**expression必须是多态类型,如果下行转换是安全的那么运算符会传回适当转型过的指针,如果不安全,这个运算符会传回空指针。
- 主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换。
static_cast与dynamic_cast进行上下行转换的区别
- 对于上行转换,都是安全的;对于向下转换,dynamic_cast会进行RTTI,具有类型检查的功能,所以下行转换是安全的;而static_cast不会进行RTTI,所以是不安全的。
代码参考阿秀的学习笔记
#include <bits/stdc++.h>
using namespace std;
class Base
{
public:
Base() :b(1) {}
virtual void fun() {};
int b;
};
class Son : public Base
{
public:
Son() :d(2) {}
int d;
};
int main()
{
int n = 97;
//reinterpret_cast
int *p = &n;
//以下两者效果相同
char *c = reinterpret_cast<char*> (p);
char *c2 = (char*)(p);
cout << "reinterpret_cast输出:"<< *c2 << endl;
//const_cast
const int *p2 = &n;
int *p3 = const_cast<int*>(p2);
*p3 = 100;
cout << "const_cast输出:" << *p3 << endl;
Base* b1 = new Son;
Base* b2 = new Base;
//static_cast
Son* s1 = static_cast<Son*>(b1); //同类型转换
Son* s2 = static_cast<Son*>(b2); //下行转换,不安全
cout << "static_cast输出:"<< endl;
cout << s1->d << endl;
cout << s2->d << endl; //下行转换,原先父对象没有d成员,输出垃圾值
//dynamic_cast
Son* s3 = dynamic_cast<Son*>(b1); //同类型转换
Son* s4 = dynamic_cast<Son*>(b2); //下行转换,安全
cout << "dynamic_cast输出:" << endl;
cout << s3->d << endl;
if(s4 == nullptr)
cout << "s4指针为nullptr" << endl;
else
cout << s4->d << endl;
return 0;
}
//输出结果
//reinterpret_cast输出:a
//const_cast输出:100
//static_cast输出:
//2
//-33686019
//dynamic_cast输出:
//2
//s4指针为nullptr
大小端存储
什么是大小端存储
- 大端:高字节放在低地址
- 小端:低字节放在低地址
如何判断大小端存储
- 强制类型转换
#include <iostream>
using namespace std;
int main()
{
int a = 0x1234;
//由于int和char的长度不同,借助int型转换成char型,只会留下低地址的部分
char c = (char)(a);
if (c == 0x12)
cout << "big endian" << endl;
else if(c == 0x34)
cout << "little endian" << endl;
}
- union联合体
#include <iostream>
using namespace std;
//union联合体的重叠式存储,endian联合体占用内存的空间为每个成员字节长度的最大值
union endian
{
int a;
char ch;
};
int main()
{
endian value;
value.a = 0x1234;
//a和ch共用4字节的内存空间
if (value.ch == 0x12)
cout << "big endian"<<endl;
else if (value.ch == 0x34)
cout << "little endian"<<endl;
}
联合体(union)是一种数据结构,它允许在相同的内存位置存储不同类型的数据。联合体中的不同成员共享同一块内存空间,但只能同时存储其中的一个成员。这意味着联合体中的成员在内存中是重叠的,因为它们共享相同的存储空间。
如何在不使用额外空间的情况下,交换两个数?
1) 算术
x = x + y;
y = x - y;
x = x - y;
2) 异或
//两个数相等的时候不能这么用
x = x^y;// 只能对int,char..
y = x^y;
x = x^y;