C++ 面向对象 - 类的多态性与虚函数

任务描述

本关任务:设计人类、英语学生类和复读机类三个类。

相关知识

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

多态性

在面向对象的方法中,多态性是指向不同对象发送同一个消息,不同对象在接收时会产生不同的行为(方法)。

通俗点说就是可以不用像 C 语言中为了求多种图形的面积而针对不同的图形各设计一个独立名字的函数,在 C++ 中只要设计一个专门用于求面积的函数名即可。这个专门用于求面积的函数名可以作为各种求图形面积的函数名。

这么做的好处在于程序设计者可以省去设立多个函数名对应多个函数的麻烦,使用的时候统一用同一个函数名就可调用具有不同功能的函数。

多态在 C++ 中的实现可以是函数的重载、运算符的重载和虚函数,本实训我们介绍虚函数的使用。

虚函数

我们知道在同一个类中是不能定义两个名字相同、参数个数和类型完全相同的函数,否则就是重复定义。但是在类的继承层次结构中,在不同的层次中可以出现名字相同、参数个数和类型相同而功能不同的函数。这时系统会根据同名覆盖的原则决定调用的对象。

那么有没有一种方法,用同一种调用形式,既能调用派生类又能调用基类的同名函数?即不通过不同的对象名去调用不同派生层次中的同名函数,而是通过指针调用它们,虚函数就是用来解决这个问题的。

虚函数是一种动态的重载方式。虚函数的作用是允许在派生类中重新定义与基类同名的函数,并可以通过基类指针或引用来访问基类和派生类中同名函数。

C++ 中要声明一个成员函数为虚函数,只需要在函数的声明前加上一个关键字 virtual 即可,然后就像对待普通成员函数那样,给它加上定义。

例如:

 
  1. class Base
  2. {
  3. public:
  4. virtual void VFunc(); // 声明一个虚函数
  5. };
  6. void Base::VFunc()
  7. {
  8. cout << "虚函数" << endl;
  9. }

重写父类虚函数

当一个类继承了一个含有虚函数的类,子类就可以选择是否要对父类的虚函数进行重写。所谓重写,就是覆盖父类中的定义,提供一个自己的定义。当然也可以选择不重写,那么就沿用父类的定义。

要重写一个虚函数,需要增加一条与要重写的函数相同(参数与返回值)的函数声明,然后在声明后面加上说明符 override。

例如:

 
  1. /* Base类的声明同上 */
  2. class D1 : public Base // 继承 Base 类
  3. {
  4. public:
  5. void VFunc() override; // 重写 VFunc 函数
  6. };
  7. void D1::VFunc()
  8. {
  9. cout << "覆盖父类实现" <<endl;
  10. }
  11. int main()
  12. {
  13. D1 b;
  14. b.VFunc();
  15. }

输出结果为:覆盖父类实现

在子类中重写虚函数时是可以重新定义访问性的,即使父类中虚函数的访问性为 private,在子类中仍然可以重写为 public。如果子类想要访问被重写的父类的定义,同样使用作用域运算符(::)即可。

例如:

 
  1. /* Base类的声明同上 */
  2. class D1 : public Base // 继承 Base 类
  3. {
  4. public:
  5. void VFunc() override; // 重写 VFunc 函数
  6. };
  7. void D1::VFunc()
  8. {
  9. Base::VFunc(); // 调用父类的定义
  10. cout << "覆盖父类实现" <<endl;
  11. }
  12. int main()
  13. {
  14. D1 b;
  15. b.VFunc();
  16. }

输出结果为:

 
  1. 虚函数
  2. 覆盖父类实现

编程要求

在右侧编辑器中的Begin-End之间补充代码,设计人类、英语学生类和复读机类三个类,具体要求如下:

  1. 人类( Chinese )

    • 它有一个虚函数 greet,函数输出中文问候,即你好
  2. 英语学生类( EnglishLearner )

    • 继承 Chinese 类,重写 greet 函数,访问性为 public,输出英文问候,即Hello
  3. 复读机类( Repeater )

    • 继承 Chinese 类,以 public 访问性重写 greet 函数,函数调用 Chinese 类的 greet 函数。

测试说明

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

第1关:人与复读机

#include <iostream>
using namespace std;

/********* Begin *********/
class Chinese
{
public:
	virtual void greet()
	{
		cout<<"你好"<<endl;
	}//人类的声明
    
    
    
};
//人类的定义




class EnglishLearner : public Chinese
{
public:
    void greet()
	{
		cout<<"Hello"<<endl;
	}//英语学生类的声明
    
    
    
};
//英语学生类的定义





class Repeater : public Chinese
{
public:
   void greet()
   {
	   Chinese::greet();
	}//复读机类的声明
    
    
    
};
//复读机类的定义



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

第2关:复读机的毁灭

#include <iostream>
using namespace std;

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



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




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




//普通函数
Repeater* CreateRepeater(int type)
{
    if(type==0)
	   Repeater *R=new ForRepeater;
	if(type==1)
	   Repeater *R=new RevRepeater;
	//if(type!=0||type!=1)
	   //return 0;
	//根据type创建指定的复读机

    
    
}

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

第3关:计算图像面积

目录

第1关:人与复读机


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值