C++ 面向对象特征4 多态(Polymorphism)

简介: C++ 面向对象特征4 多态(Polymorphism)

1、对多态的理解

同一对象可以有多重层级递进身份

在不同的场合中,被外界所关注的是不同的身份,但本质和应有的行为并不会因外界眼光而改变。

比如说我自己 kali-Myon(一个实体)


生物学家会认为我(该实体)是人类 ;


教育局认为我是一名学生;


西南科技大学认为我是一名大学生。


但我目前在做什么呢?上大学对吧,我做着我自己最本质身份(大学生)的行为。


一个对象就是内存中的一个实体,它只能属于一个确定的类:最精确的子类


它可能在不同处被视为不同身份,但它本质行为方式与外界如何看待它是无关的。


为了保证一个对象执行其最本质身份的行为


我们可以利用虚函数重写和指向子类对象的父类指针来实现

2、实现多态的例子

eg1:

#include <iostream>
using namespace std;
class Human {  //定义了一个父类
public:
  virtual void say() {
      cout << "I'm human\n";
  }
};
class Student : public Human {  //子类1公有继承父类
public:
  virtual void say() {
    cout << "I'm a student\n";
  }
};
class CollegeStudent : public Student {  //子类2公有继承子类1(对于子类2来说,子类1就相当于它的父类)
public:
  void say() {
    cout << "I'm a college student\n";
  }
};
int main() {
  CollegeStudent a;  //a是子类2的一个实例化对象
  Human* p1 = (Human*)&a;  //父类指针,指向子类对象
  Student* p2 = (Student*)&a;  //父类指针,指向子类对象
  CollegeStudent* p3 = &a;
  p1->say();  //“->”是类成员访问运算符,可以被重载,它被定义用于为一个类赋予"指针"行为,常与指针引用运算符“*”结合使用
  p2->say();  
  p3->say(); 
}

由运行结果可以看出:通过指针调用的是对象本质子类的方法

(即collegestudent这个类中的say()函数)

eg2:

有很多的人(human),男的(man)应该去男厕所,女的(women)该去女厕所


但是有太多对象man1,man2,women1,man3,women2...


如何用func()函数让他们都能去到正确的厕所


我们只需定义一个上厕所的函数toilet()


男的还是女的都是人,都具有上厕所这个行为


human可能指向两种不同的实际对象

事实上func()并不关心实际是什么,反正都当成Human,能toilet就行

#include <iostream>
using namespace std;
class Human {
public:
  virtual void toilet() = 0;
};
class Man : public Human {
public:
  void toilet() {
    cout << "我去男厕所";
  }
};
class Woman : public Human {
public:
  void toilet() {
    cout << "我去女厕所";
  }
};
void func(Human * human) {
    human->toilet();
  }
int main() {
  Man man1;
  Woman woman2;
  func(&man1);
  cout << endl;
  func(&woman2);
}

运行结果:

可以看到,man1去了男厕所,woman2去了女厕所

3、多态的意义

实现代码复用


通过“虚函数+指向子类对象的父类指针”,无需针对不同的子类写相同逻辑,统一视为其共同父类,利用指针操作即可,本质是虚函数将能做什么和怎么做分离,父类指定要做什么,子类来实现具体做法。


eg3:


比如我们要设计一个函数来求图形的面积,但是我们并不知道具体是什么图形


如果没有多态,我们就需要对每种图形都实现一个函数


但是有多态,我们只需要实现一个函数

并不关心图形具体是什么,只要能求面积就行(满足父类,是个图形,就能求面积)

#include <iostream>
using namespace std;
class Shape {  //定义了一个类shape
public:
  virtual float getS() = 0;  //在父类声明了一个纯虚函数
};
class Circle : public Shape {  //圆公有继承父类shape
private:
  float radius;
public:
  Circle(float radius)
  {
    this->radius = radius;
  }
  float getS() { return 3.14 * radius * radius; }  //在子类重写虚函数
};
class Rectangle : public Shape {  //矩形公有继承父类shape
private:
  float a;
  float b;
public:
  Rectangle(float a, float b) {
    this->a = a;
    this->b = b;
}
float getS() { return a * b; }  //在子类重写虚函数
};
void display(Shape* ptr) {  //此处实现了多态:通过父类指针调用子类重写的虚函数
  cout << ptr->getS() << endl;
}
int main() {
    Circle c(1.3);
    Rectangle r(1.5, 2.3);
    display(&c);
    display(&r);
    return 0;
}

运行结果:

4、静态联编与动态联编

上述利用虚函数重写+指针实现的多态特指运行时多态,与之相对的是编译时多态


静态联编=编译时多态=函数重载=overload


动态联编=运行时多态=虚函数重写=override


联编(bind):确定具体要调用多个同名函数中的哪一个


静态联编:在编译时就确定了要调用的是哪个函数(根据多个重载函数的参数列表确)


动态联编:直到运行时才知道实际调用的是哪个函数(根据指针指向对象的实际身份)


至此,我们已经介绍完了面向对象的四个特征:封装、派生、继承、多态。

目录
相关文章
|
4月前
|
存储 人工智能 编译器
c++--多态
上一篇文章已经介绍了c++的继承,那么这篇文章将会介绍多态。看完多态的概念,你一定会感觉脑子雾蒙蒙的,那么我们先以举一个例子,来给这朦胧大致勾勒出一个画面,在此之前,先介绍一个名词虚函数,(要注意与虚拟继承区分)重定义: 重定义(隐藏)只要求函数名相同(但要符合重载的要求,其实两者实际上就是重载);重定义下:在这种情况下,如果通过父类指针或引用调用函数,会调用父类的函数而不是子类。重定义(或称为隐藏)发生的原因是因为函数名相同但参数列表不同,导致编译器无法确定调用哪一个版本的函数。
73 0
|
8月前
|
编译器 C++
c++中的多态
c++中的多态
|
7月前
|
存储 编译器 C++
【c++】多态(多态的概念及实现、虚函数重写、纯虚函数和抽象类、虚函数表、多态的实现过程)
本文介绍了面向对象编程中的多态特性,涵盖其概念、实现条件及原理。多态指“一个接口,多种实现”,通过基类指针或引用来调用不同派生类的重写虚函数,实现运行时多态。文中详细解释了虚函数、虚函数表(vtable)、纯虚函数与抽象类的概念,并通过代码示例展示了多态的具体应用。此外,还讨论了动态绑定和静态绑定的区别,帮助读者深入理解多态机制。最后总结了多态在编程中的重要性和应用场景。 文章结构清晰,从基础到深入,适合初学者和有一定基础的开发者学习。如果你觉得内容有帮助,请点赞支持。 ❤❤❤
875 0
|
9月前
|
C++ 芯片
【C++面向对象——类与对象】Computer类(头歌实践教学平台习题)【合集】
声明一个简单的Computer类,含有数据成员芯片(cpu)、内存(ram)、光驱(cdrom)等等,以及两个公有成员函数run、stop。只能在类的内部访问。这是一种数据隐藏的机制,用于保护类的数据不被外部随意修改。根据提示,在右侧编辑器补充代码,平台会对你编写的代码进行测试。成员可以在派生类(继承该类的子类)中访问。成员,在类的外部不能直接访问。可以在类的外部直接访问。为了完成本关任务,你需要掌握。
177 19
|
9月前
|
存储 编译器 数据安全/隐私保护
【C++面向对象——类与对象】CPU类(头歌实践教学平台习题)【合集】
声明一个CPU类,包含等级(rank)、频率(frequency)、电压(voltage)等属性,以及两个公有成员函数run、stop。根据提示,在右侧编辑器补充代码,平台会对你编写的代码进行测试。​ 相关知识 类的声明和使用。 类的声明和对象的声明。 构造函数和析构函数的执行。 一、类的声明和使用 1.类的声明基础 在C++中,类是创建对象的蓝图。类的声明定义了类的成员,包括数据成员(变量)和成员函数(方法)。一个简单的类声明示例如下: classMyClass{ public: int
215 13
|
9月前
|
编译器 数据安全/隐私保护 C++
【C++面向对象——继承与派生】派生类的应用(头歌实践教学平台习题)【合集】
本实验旨在学习类的继承关系、不同继承方式下的访问控制及利用虚基类解决二义性问题。主要内容包括: 1. **类的继承关系基础概念**:介绍继承的定义及声明派生类的语法。 2. **不同继承方式下对基类成员的访问控制**:详细说明`public`、`private`和`protected`继承方式对基类成员的访问权限影响。 3. **利用虚基类解决二义性问题**:解释多继承中可能出现的二义性及其解决方案——虚基类。 实验任务要求从`people`类派生出`student`、`teacher`、`graduate`和`TA`类,添加特定属性并测试这些类的功能。最终通过创建教师和助教实例,验证代码
187 5
|
9月前
|
存储 C++
【C++面向对象——输入输出流】处理二进制文件(头歌实践教学平台习题)【合集】
本任务要求使用C++读取二进制文件并在每行前添加行号后输出到控制台。主要内容包括: 1. **任务描述**:用二进制方式打开指定文件,为每一行添加行号并输出。 2. **相关知识**: - 流类库中常用的类及其成员函数(如`iostream`、`fstream`等)。 - 标准输入输出及格式控制(如`cin`、`cout`和`iomanip`中的格式化函数)。 - 文件的应用方法(文本文件和二进制文件的读写操作)。 3. **编程要求**:编写程序,通过命令行参数传递文件名,使用`getline`读取数据并用`cout`输出带行号的内容。 4. **实验步骤**:参考实验指
204 5
|
9月前
|
存储 算法 搜索推荐
【C++面向对象——群体类和群体数据的组织】实现含排序功能的数组类(头歌实践教学平台习题)【合集】
1. **相关排序和查找算法的原理**:介绍直接插入排序、直接选择排序、冒泡排序和顺序查找的基本原理及其实现代码。 2. **C++ 类与成员函数的定义**:讲解如何定义`Array`类,包括类的声明和实现,以及成员函数的定义与调用。 3. **数组作为类的成员变量的处理**:探讨内存管理和正确访问数组元素的方法,确保在类中正确使用动态分配的数组。 4. **函数参数传递与返回值处理**:解释排序和查找函数的参数传递方式及返回值处理,确保函数功能正确实现。 通过掌握这些知识,可以顺利地将排序和查找算法封装到`Array`类中,并进行测试验证。编程要求是在右侧编辑器补充代码以实现三种排序算法
136 5
|
9月前
|
Serverless 编译器 C++
【C++面向对象——类的多态性与虚函数】计算图像面积(头歌实践教学平台习题)【合集】
本任务要求设计一个矩形类、圆形类和图形基类,计算并输出相应图形面积。相关知识点包括纯虚函数和抽象类的使用。 **目录:** - 任务描述 - 相关知识 - 纯虚函数 - 特点 - 使用场景 - 作用 - 注意事项 - 相关概念对比 - 抽象类的使用 - 定义与概念 - 使用场景 - 编程要求 - 测试说明 - 通关代码 - 测试结果 **任务概述:** 1. **图形基类(Shape)**:包含纯虚函数 `void PrintArea()`。 2. **矩形类(Rectangle)**:继承 Shape 类,重写 `Print
137 4
|
9月前
|
设计模式 IDE 编译器
【C++面向对象——类的多态性与虚函数】编写教学游戏:认识动物(头歌实践教学平台习题)【合集】
本项目旨在通过C++编程实现一个教学游戏,帮助小朋友认识动物。程序设计了一个动物园场景,包含Dog、Bird和Frog三种动物。每个动物都有move和shout行为,用于展示其特征。游戏随机挑选10个动物,前5个供学习,后5个用于测试。使用虚函数和多态实现不同动物的行为,确保代码灵活扩展。此外,通过typeid获取对象类型,并利用strstr辅助判断类型。相关头文件如&lt;string&gt;、&lt;cstdlib&gt;等确保程序正常运行。最终,根据小朋友的回答计算得分,提供互动学习体验。 - **任务描述**:编写教学游戏,随机挑选10个动物进行展示与测试。 - **类设计**:基类
181 3