RTTI——运行时类型识别
RTTI:Run-Time Type Identification
typeid <——> denamic_cast
举例说明:
Bird类继承了Flyable类,就要实现takeoff()和land(),自己特有foraging()
Plane类继承了Flyable类,要实现takeoff()和land(),自己特有carry()
参数是Flyable的指针,中间可对指针进一步判断,如果是Bird的对象指针,可调用foraging(),如果是Plane的对象指针,可调用carry()
要完成上述功能,要用到RTTI
编码示例:
Flyable.h
#ifndef FLYABLE_H
#define FLYABLE_H
class Flyable
{ //只有纯虚函数,是接口类
public:
virtual void takeoff() = 0;
virtual void land() = 0;
};
#endif // !FLYABLE_H
Bird.h
#ifndef BIRD_H
#define BIRD_H
#include "Flyable.h"
#include <string>
using namespace std;
class Bird:public Flyable
{
public:
void foraging();
virtual void takeoff();
virtual void land();
};
#endif // !BIRD_H
Bird.cpp
#include "Bird.h"
#include <iostream>
using namespace std;
void Bird::foraging()
{
cout << "Bird::foraging()" << endl;
}
void Bird::takeoff()
{
cout << "Bird::takeoff()" << endl;
}
void Bird::land()
{
cout << "Bird::land()" << endl;
}
Plane.h
#ifndef PLANE_H
#define PLANE_H
#include <string>
#include "Flyable.h"
using namespace std;
class Plane : public Flyable
{
public:
void carry();
virtual void takeoff();
virtual void land();
};
#endif // ! PLANE_H
Plane.cpp
#include "Plane.h"
#include <iostream>
using namespace std;
void Plane::carry()
{
cout << "Plane::carry()" << endl;
}
void Plane::takeoff()
{
cout << "Plane::takeoff()" << endl;
}
void Plane::land()
{
cout << "Plane::land()" << endl;
}
demo.cpp
#include "Bird.h"
#include "Plane.h"
#include <iostream>
using namespace std;
void dosomething(Flyable *obj)
{
cout << typeid(*obj).name() << endl; //通过cout打印传入的指针的数据类型(是哪个对象的指针)
obj->takeoff();
if (typeid(*obj) == typeid(Bird)) //判断传入的指针是不是Bird类
{
Bird *bird = dynamic_cast<Bird *>(obj); //如果是Bird类,就通过dynamic_cast将指针obj转化为Bird类的指针,并将该指针赋值给新指针bird
bird->foraging();
}
if (typeid(*obj) == typeid(Plane)) //判断传入的指针是不是Plane类
{
Plane *bird = dynamic_cast<Plane *>(obj); //如果是Plane类,就通过dynamic_cast将指针obj转化为Plane类的指针,并将该指针赋值给新指针plane
bird->carry();
}
obj->land();
}
int main()
{
Bird b;
dosomething(&b);
return 0;
}
修改demo.cpp
Plane b;
修改demo.cpp
nt main()
{
int i = 0;
cout << typeid(i).name() << endl;
return 0;
}
修改demo.cpp
int main()
{
Flyable *p = new Bird();
cout << typeid(p).name() << endl;
cout << typeid(*p).name() << endl;
return 0;
}
说明p的数据类型是 Flyable *
*p是Bird的对象
修改:
Flyable.h
#ifndef FLYABLE_H
#define FLYABLE_H
class Flyable
{ //只有纯虚函数,是接口类
public:
void takeoff() {}
void land() {}
};
#endif // !FLYABLE_H
Bird.h
#ifndef BIRD_H
#define BIRD_H
#include "Flyable.h"
#include <string>
using namespace std;
class Bird:public Flyable
{
public:
void foraging();
void takeoff();
void land();
};
#endif // !BIRD_H
把Flyable和Bird变为普通的子类和父类
demo.cpp
int main()
{
Flyable *p = new Bird();
//Bird *b = dynamic_cast<Bird *> p; //把p转化为Bird的指针并赋值给Bird的新指针b
//此句报错,要求转换的目标类型和被转换的数据类型都应该是具有虚函数的,没有就报错
return 0;
}
修改demo.cpp
int main()
{
Flyable p;
//Bird b = dynamic_cast<Bird>p; //该句报错,必须要是引用和指针才可能进行转换,且要有虚函数。
异常处理
异常:程序运行期出现的错误
异常处理:对有可能发生异常的地方做出预见性的安排
要用到关键字:
try...catch... //尝试...捕获... ,尝试运行,遇到问题捕获错误
throw //抛出异常
基本思想:主逻辑与异常处理分离
从f1到f2到f3到再往上,能处理异常就处理,不能处理就往上抛
先执行try里的内容,无异常就跳过catch往下执行,如果try运行到fun1有异常(catch捕获到fun1抛出了1),则fun1以下的内容不执行
(如果抛出的是0.1,catch括号int改成double)
例2:
上例中,抛出的是一个值,但捕获的是一种类型。如果想要捕获一个值,如上图,该函数功能是获取一个字符,传入的参数,一个是字符串(const string& sStr),一个是下标(const int aIndex)。想要根据字符串,且通过下标拿到字符串中所对应下标的字符(return aStr[aIndex])。但无法保证传入的下标一定比字符串短(aIndex<aStr.size)(如果下标比字符串长,如下标是4,但字符串长只有3,就不符合逻辑)不符合逻辑,就通过throw将异常抛出
通过catch将该字符拿到:
异常处理与多态的关系
举例:
定义一个异常类名为Exception(假设定义为一个接口类)
通过细分的子类定义接口类,当抛出这些子类的对象时,就都可以用这个父类去捕获
SizeErr是Exception的子类,MemoryErr也是xception的子类
如上图,此时不论是fun1还是fun2都可以用Exception来捕获异常
编码示例:
Exception.h
#ifndef EXCEPTION_H
#define EXCEPTION_H
class Exception
{
public:
virtual void printException();
virtual ~Exception() {}
};
#endif // !EXCEPTION_H
Exception.cpp
#include "Exception.h"
#include <iostream>
using namespace std;
void Exception::printException()
{
cout << "Exception::printException()" << endl;
}
IndexException.h
#ifndef INDEX_EXCEPTION_H
#define INDEX_EXCEPTION_H
#include "Exception.h"
class IndexException : public Exception
{
public:
virtual void printException();
};
#endif // !INDEX_EXCEPTION_H
IndexException.cpp
#include "IndexException.h"
#include <iostream>
using namespace std;
void IndexException::printException()
{
cout << "提示:下标越界" << endl;
}
demo.cpp
#include "IndexException.h"
#include <iostream>
using namespace std;
void test()
{
throw 10;
}
int main()
{
try
{
test();
}
catch (int)
{
cout << "exception" << endl;
}
return 0;
}
修改demo.cpp throw 0.1;
不会输出exception
再修改demo.cpp catch (double)
又会输出exception
再修改demo.cpp
catch (double &e)
{
cout << e << endl;
}
修改demo.cpp
#include "IndexException.h"
#include <iostream>
using namespace std;
void test()
{
throw IndexException();
}
int main()
{
try
{
test();
}
catch (IndexException &e)
{
e.printException();
}
return 0;
}
修改demo.cpp
catch (Exception &e)
{
e.printException();
}
修改demo.cpp
catch (...)
{
cout << "Exception" << endl;
}