C++学习笔记11——多态篇

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;
	}

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值