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

news/2025/1/13 4:39:33/

为什么要把基类指针指向子类对象?
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.ppmy.cn/news/1562706.html

相关文章

【算法】算法大纲

这篇文章介绍计算机算法的各个思维模式。 包括 计数原理、数组、树型结构、链表递归栈、查找排序、管窥算法、图论、贪心法和动态规划、以及概率论:概率分治和机器学习。没有办法逐个说明,算法本身错综复杂,不同的算法对应着不同的实用场景,也需要根据具体情况设计与调整。…

Lua语言的软件开发工具

Lua语言的软件开发工具 引言 Lua是一种轻量级且高效的脚本语言&#xff0c;广泛应用于游戏开发、嵌入式系统以及Web开发等领域。由于其简洁的语法、强大的扩展性和良好的性能&#xff0c;Lua逐渐成为开发者们青睐的语言之一。在Lua语言的生态系统中&#xff0c;各类软件开发工…

docker 安装 fastdfs

1、安装docker(已安装的跳过这一步) 2、安装FastDFS ## 这里我使用的腾讯云个人镜像 docker pull ccr.ccs.tencentyun.com/satan/fastdfs:6.06## 创建挂载映射文件夹 mkdir /data/fdfs/tracker /data/fdfs/storage## 安装tracker docker run -dti --networkhost --name track…

SkyWise Digital:助力国际品牌成功进军中国市场

伦敦,2025年1月8日 —— SkyWise Digital 天智数字营销正式成立,专注于为国际品牌提供定制化的市场进入策略和数字营销服务,帮助他们成功打入中国市场。作为一家集文化洞察、数据驱动与创新技术于一体的专业机构,SkyWise Digital 致力于帮助西方品牌解锁中国市场的巨大潜力。 …

Node.js入门html,css,js 30年了nodejs环境 09年出现 15年

Node.js入门 html,css,js 30年了 nodejs环境 09年出现 15年 nodejs为我们解决了2个方面的问题&#xff1a; 【锦上添花】让我们前端工程师拥有了后端开发能力&#xff08;开接口&#xff0c;访问数据库&#xff09; - 大公司BFF&#xff08;50&#xff09;【✔️】前端工程…

NLP中的问答(Question answering)

在自然语言处理&#xff08;NLP&#xff09;中&#xff0c;问答&#xff08;Question Answering, QA&#xff09;任务并不严格等同于分类任务&#xff0c;但某些形式的QA任务可以被建模为分类问题。具体情况如下&#xff1a; 1. 问答任务的分类情况 多选问答 如果问题有多个备…

C++ vtordisp的应用场景

文章目录 问题代码1. 基本概念回顾2. 应用场景虚继承与虚函数并存的类层次结构 3. 编译器相关考虑 问题代码 #include <iostream> using namespace std;class base { public:base() {}virtual void show() { cout << "base:: show"<<endl; } priv…

代码随想录算法训练营第三十二天|509.斐波那契数、70.爬楼梯、746.使用最小花费爬楼梯

目录 509.斐波那契数 动态规划五部曲&#xff1a; 1.确定dp数组&#xff08;dp table&#xff09;以及下标的含义 2.确定递推公式 3.dp数组如何初始化 4.确定遍历顺序 5.举例推导dp数组 70.爬楼梯 动态规划五部曲&#xff1a; 1.确定dp数组&#xff08;dp table&#xff09;…