当前位置: 首页 > news >正文

C++中 为什么要把基类指针指向子类对象?

为什么要把基类指针指向子类对象?
1)实现多态性
动态绑定行为:通过基类指针指向子类对象,可以利用 C++ 的多态机制。当基类中有虚函数,并且子类重写了这些虚函数时,通过基类指针调用虚函数,实际调用的是对象所属子类中重写后的函数。这使得程序能够根据对象的实际类型(子类类型)来动态地选择正确的行为。例如,在一个图形绘制系统中,有一个基类Shape,包含虚函数draw,以及子类Circle和Rectangle分别重写了draw函数。

class Shape 
{
public:virtual void draw() = 0;
};
class Circle : public Shape 
{
public:void draw() override {std::cout << "Drawing a circle." << std::endl;}
};
class Rectangle : public Shape 
{
public:void draw() override {std::cout << "Drawing a rectangle." << std::endl;}
};

可以使用基类指针来操作不同类型的图形对象,如
Shape* shapePtr;
shapePtr = new Circle();
shapePtr->draw();,
这里shapePtr指向Circle对象时,draw函数会调用Circle类中的draw实现;当shapePtr指向Rectangle对象(shapePtr = new Rectangle();)时,draw函数会调用Rectangle类中的draw实现。这种动态绑定允许在不修改调用代码的情况下,轻松地添加新的图形子类并实现其特定的绘制行为,提高了代码的可扩展性和灵活性。
二)统一管理不同子类对象
容器存储和操作:可以将不同子类的对象存储在一个容器中,只要这些子类都继承自同一个基类。例如,使用std::vector<BaseClass*>这样的容器来存储多个不同类型的子类对象指针。在游戏开发中,假设有一个基类GameCharacter,子类有Warrior、Mage等不同类型的游戏角色。

class GameCharacter 
{
public:virtual void attack() = 0;
};
class Warrior : public GameCharacter 
{
public:void attack() override {std::cout << "Warrior attacks with a sword." << std::endl;}
};
class Mage : public GameCharacter 
{
public:void attack() override {std::cout << "Mage attacks with magic." << std::endl;}
};

可以创建一个角色指针的向量
std::vector<GameCharacter*> characterList;
characterList.push_back(new Warrior());
characterList.push_back(new Mage());
,然后通过遍历这个容器,使用基类指针调用每个角色的attack函数
(for (auto character : characterList) { character->attack(); }),这样就可以用统一的方式来处理不同类型的游戏角色的行为,而不需要为每个子类单独编写处理代码,使得代码更加简洁和易于维护。
三)代码复用和模块性
利用基类功能:子类继承了基类的属性和方法,当基类指针指向子类对象时,可以访问和使用基类中定义的公共成员函数和成员变量(在权限允许的情况下)。这有助于代码的复用,因为基类中的功能可以被多个子类共享。例如,在一个车辆管理系统中,有一个基类Vehicle定义了通用的属性(如车辆编号)和方法(如启动和停止车辆),子类Car和Truck继承自Vehicle。

class Vehicle 
{
protected:int vehicleId;
public:Vehicle(int id) : vehicleId(id) {}void start() {std::cout << "Vehicle is starting." << std::endl;}void stop() {std::cout << "Vehicle is stopping." << std::endl;}
};
class Car : public Vehicle 
{
public:Car(int id) : Vehicle(id) {}void honk() {std::cout << "Car is honking." << std::endl;}
};
class Truck : public Vehicle 
{
public:Truck(int id) : Vehicle(id) {}void loadCargo() {std::cout << "Truck is loading cargo." << std::endl;}
};

通过基类指针(如
Vehicle* vehiclePtr; vehiclePtr = new Car(1);
vehiclePtr->start();)
可以调用start和stop这样的基类方法,无论指针实际指向的是Car还是Truck对象,都能复用基类中定义的这些通用功能,同时每个子类还可以有自己特有的功能(如Car的honk和Truck的loadCargo),这种方式提高了代码的模块性,使得基类和子类的功能划分更加清晰。


http://www.mrgr.cn/news/83391.html

相关文章:

  • 如何用 SSH 访问 QNX 虚拟机
  • 多跳问答中的语言模型知识编辑增强
  • 相机和激光雷达的外参标定 - 无标定板版本
  • 【练习】力扣 热题100 两数之和
  • Redis:数据类型
  • 新型物联网智能断路器功能参数介绍
  • Java 应用程序CPU 100%问题排查优化实战
  • 图像模糊度(清晰度)检测 EsFFT 算法详细分析
  • Java Web开发进阶——Spring Boot与Thymeleaf模板引擎
  • 计算机的错误计算(二百零八)
  • 一分钟学会文心一言API如何接入,文心一言API接入教程
  • 1.两数之和--力扣
  • 第26章 汇编语言--- 内核态与用户态
  • 01 Oracle自学环境搭建(Windows系统)
  • 超完整Docker学习记录,Docker常用命令详解
  • 模式识别与机器学习
  • 类与对象(上)
  • Python自学 - 类进阶(可调用对象)
  • 《HeadFirst设计模式》笔记(下)
  • 第27章 汇编语言--- 设备驱动开发基础
  • RNN之:LSTM 长短期记忆模型-结构-理论详解(Matlab向)
  • win32汇编环境,怎么进行乘法运算的
  • 测试开发之面试宝典
  • 01 springboot集成mybatis后密码正确但数据库连接失败
  • JVM与Java体系结构
  • SQL从入门到实战-2