复读机的毁灭

本文介绍了如何在C++中设计三个复读机类(Repeater、ForRepeater和RevRepeater),并通过虚析构函数实现多态性和资源管理,以及一个根据类型动态创建复读机对象的普通函数CreateRepeater。
摘要由CSDN通过智能技术生成
任务描述

本关任务:设计三个复读机类并实现一个普通函数。

相关知识

为了完成本关任务,你需要掌握虚析构函数的使用。

多态性的体现

C++ 允许将一个对象的指针赋值给它的父类指针变量。而当通过父类指针调用一个虚函数时,则会调用子类中最后被重写的那个版本,这样对于同一段通过指针调用某个虚函数的代码,就会因为实际指向的对象不同,而调用不同函数,这就是所谓的多态性。

同理,通过引用调用一个虚函数,也会有这样的效果。

例如:

 
  1. class Base
  2. {
  3. public:
  4. virtual void Cal(int a,int b);
  5. };
  6. void Base::Cal(int a, int b)
  7. {
  8. cout << a * b << endl; // 默认是乘法
  9. }
  10. class Add : public Base
  11. {
  12. public:
  13. void Cal(int a,int b) override;
  14. };
  15. void Add::Cal(int a,int b)
  16. {
  17. cout << a + b << endl; // 实现一个加法
  18. }
  19. class Sub : public Base
  20. {
  21. public:
  22. void Cal(int a,int b) override;
  23. };
  24. void Sub::Cal(int a,int b)
  25. {
  26. cout << a - b << endl; //实现一个减法
  27. }
  28. //普通函数
  29. void call(Base *ptr)
  30. {
  31. ptr->Cal(10,10); // 通过指针调用虚函数
  32. }
  33. int main()
  34. {
  35. Add ad;
  36. call(&ad);
  37. Sub sb;
  38. call(&sb);
  39. }

输出结果为:

 
  1. 20
  2. 0

可以看到,连续两次调用 call 函数,调用的效果有所不同。第一次调用的是对象是 Add,因此实现的是加法,即10+10=20;而第二次的调用对象是 Sub,实现的则是减法,即10-10=0

虽然 C++ 也允许将子类对象直接赋值给父类变量,但是这样做会导致子类被切割成父类对象,丢失了子类的成分,这时调用虚函数,也就不会调用到被子类的重写的版本了。

例如:

 
  1. /* 类的定义同上 */
  2. void call(Base b) // 这里不使用指针
  3. {
  4. b.Cal(10,10);
  5. }
  6. int main()
  7. {
  8. Add ad;
  9. call(ad); // Add 子类赋值给 Base 父类变量
  10. Sub sb;
  11. call(sb); // Sub 子类赋值给 Base 父类变量
  12. }

输出结果为:

 
  1. 100
  2. 100

如果子类对象赋值给父类变量,则使用该变量时只能访问子类的父类部分(因为子类含有父类的部分,所以不会有问题)。因此无论哪个对象在调用 Call 函数时都是调用的父类的成员函数,所以输出结果都为100,即10*10=100

虚析构函数

如果一个父类的析构函数没有声明成虚函数,那么使用 delete 运算符销毁一个父类指针所指的子类对象时,就只会调用父类的析构函数,子类的析构函数则不会被调用,这样就可能导致子类动态分配的资源无法及时回收,造成资源泄露。

例如:

 
  1. class Base
  2. {
  3. public:
  4. ~Base(); // 析构函数不是虚函数
  5. };
  6. Base::~Base()
  7. {
  8. cout << "父类析构函数" << endl;
  9. }
  10. class D : public Base
  11. {
  12. public:
  13. int *Ptr;
  14. D();
  15. ~D();
  16. };
  17. D::D():Ptr(new int){} // 动态分配一块 int 类型大小的空间
  18. D::~D()
  19. {
  20. delete Ptr; // 回收 Ptr 所指空间
  21. cout << "子类析构函数" << endl;
  22. }
  23. int main()
  24. {
  25. Base *ptr = new D();
  26. delete ptr; // 由于只会调用 Base 类的析构函数,导致 D 类中 Ptr 所指的那块空间没有被释放,造成内存泄露。
  27. }

输出结果为:父类析构函数

如果将析构函数声明为虚函数,调用它时除了调用子类重写的那个版本,还会沿着继承链向上(父类方向)依次调用父类的析构函数。

对于上面那个例子,如果将 Base 类的析构函数声明成虚函数,即virtual ~Base(),那么最后得到的输出结果就是:

 
  1. 子类析构函数
  2. 父类析构函数

即也就是依次调用了 D 类、Base 类的析构函数。所以,在一般情况下析构函数建议声明成虚函数。

编程要求

在右侧编辑器中的Begin-End之间补充代码,设计三个复读机类和一个普通函数,具体要求如下:

  1. 复读机类( Repeater )

    • 它有一个成员函数 Play,在这里它什么也不做。它还有一个析构函数,它被调用时会输出一行砰!
  2. 正向复读机类( ForRepeater )

    • 继承 Repeater 类并重写 Play 函数,输出没想到你也是一个复读机且在析构函数中输出正·复读机 炸了
  3. 反向复读机类( RevRepeater )

    • 继承 Repeater 类也重写 Play 函数,输出机读复个一是也你到想没且在析构函数中输出机读复·反 炸了
  4. 普通函数:Repeater* CreateRepeater(int type),函数根据 type 的值,动态创建不同的复读机对象,并返回它的指针。其中当type = 0,创建 ForRepeater 对象;type = 1,创建 RevRepeater 对象;其他则返回 0。

测试说明

平台会对你编写的代码进行测试,比对你输出的数值与实际正确数值,只有所有数据全部计算正确才能通过测试:

测试输入:0

预期输出:

 
  1. 没想到你也是一个复读机
  2. 正·复读机 炸了
  3. 砰!

#include <iostream>
using namespace std;

/********* Begin *********/
class Repeater
{
	//复读机基类的声明
    public:
	virtual void Play()=0;
	virtual~Repeater();
    
    
};
//复读机基类的定义
Repeater::~Repeater()
{
	cout<<"砰!"<<endl;
}



class ForRepeater : public Repeater
{
	//正向复读机的声明
    public:
	void Play() override;
	~ForRepeater(){cout<<"正·复读机 炸了"<<endl;}
    
    
};
//正向复读机的定义

void ForRepeater::Play()
{cout<<"没想到你也是一个复读机"<<endl;}


class RevRepeater : public Repeater
{
	//反向复读机的声明
  public:
  void Play() override;  
  ~RevRepeater(){cout<<"机读复·反 炸了"<<endl;}  
    
};
//反向复读机的定义
void RevRepeater::Play()
{cout<<"机读复个一是也你到想没"<<endl;}



//普通函数
  Repeater* CreateRepeater(int type)
{
   
    Repeater *p;
   if(type==0)
   {
   	p=new ForRepeater;
    
   }
   else 
   if(type==1)
   {
   	p=new RevRepeater;
   	
   }
   else return 0;
}

/********* End *********/

  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

STM32单片机定制

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值