C++:多态(继承)

hello,各位小伙伴,本篇文章跟大家一起学习《C++:多态》,感谢大家对我上一篇的支持,如有什么问题,还请多多指教 !

文章目录

    • :maple_leaf:多态的概念
    • :maple_leaf:继承中的多态
      • 1.:leaves:虚函数表
    • :maple_leaf:多态原理

🍁多态的概念

在 C++ 中,多态性(Polymorphism)是面向对象编程中一个重要的概念,它允许使用统一的接口来操作不同的对象,从而提高代码的灵活性、可维护性和可扩展性。多态性的实现依赖于两种主要机制:编译时多态性(静态多态性)和运行时多态性(动态多态性)

  1. 编译时多态性(静态多态性):
  2. 在 C++ 中,编译时多态性主要通过函数重载和运算符重载来实现。这种多态性是在编译期间根据函数或运算符的参数类型和数量来选择调用的函数版本,称为静态绑定或早期绑定
  3. 例如,函数重载允许在同一个作用域内定义多个函数名相同但参数列表不同的函数,编译器会根据调用时的参数类型来选择正确的函数。如下实现不同类型进行交换代码:
void Swap(int& left, int& right)
{
	int temp = left;
	left = right;
	right = temp;
}

void Swap(double& left, double& right)
{
	double temp = left;
	left = right;
	right = temp;
}

void Swap(char& left, char& right)
{
	char temp = left;
	left = right;
	right = temp;
}
  1. 运行时多态性(动态多态性):
  2. 运行时多态性是通过虚函数和继承关系来实现的。这种多态性允许在程序运行时根据对象的实际类型来调用对应的函数,称为动态绑定或后期绑定。
  3. 在 C++ 中,通过在基类中将成员函数声明为虚函数(使用 virtual 关键字),允许派生类覆盖(override)这些虚函数。当通过基类指针或引用调用虚函数时,会根据实际指向的对象类型来决定调用哪个函数版本。

下面是一个简单的示例,展示了 C++ 中的运行时多态性:

#include <iostream>
using namespace std;

// Base class
class Animal {
public:
    // Virtual function
    virtual void speak() {
        cout << "Animal speaks!" << endl;
    }
};

// Derived class overriding the speak() function
class Dog : public Animal {
public:
    // Override the speak() function
    void speak() override {
        cout << "Dog barks!" << endl;
    }
};

// Derived class overriding the speak() function
class Cat : public Animal {
public:
    // Override the speak() function
    void speak() override {
        cout << "Cat meows!" << endl;
    }
};

int main() {
    Animal *animal;

    Dog myDog;
    Cat myCat;

    // Pointer to Dog object
    animal = &myDog;
    animal->speak();  // Output: Dog barks!

    // Pointer to Cat object
    animal = &myCat;
    animal->speak();  // Output: Cat meows!

    return 0;
}


在这个示例中:

  1. Animal 类中的 speak() 函数被声明为虚函数。
  2. Dog 和 Cat 类都重写了 speak() 函数,实现了不同的动作。
  3. 在 main() 函数中,通过 Animal 类指针 animal 分别指向 Dog 对象和 Cat 对象,并调用它们的 speak() 函数。虽然指针类型是基类 Animal,但实际上根据指向的对象类型,调用的是对应的虚函数版本,展示了运行时多态性的特性。

通过多态性,C++ 提供了一种灵活且强大的机制,使得程序能够根据对象的实际类型来决定调用哪个函数版本,从而实现代码的重用性和扩展性。

🍁继承中的多态

1.🍃虚函数表

先出一道题,32位机器下,sizeof(Base)答案是多少呢?

class Base
{
public:
 virtual void Func1()
 {
 cout << "Func1()" << endl;
 }
private:
 int _b = 1;
};

答案是:8
在这里插入图片描述
可以看到,除了_b成员,还多一个__vfptr放在对象的前面(注意有些平台可能会放到对象的最后面,这个跟平台有关),对象中的这个指针我们叫做虚函数表指针(v代表virtual,f代表function)。

class Base
{
public:
	virtual void Func1()
	{
		cout << "Base::Func1()" << endl;
	}
	virtual void Func2()
	{
		cout << "Base::Func2()" << endl;
	}
	void Func3()
	{
		cout << "Base::Func3()" << endl;
	}
private:
	int _b = 1;
};
class Derive : public Base
{
public:
	virtual void Func1()
	{
			cout << "Derive::Func1()" << endl;
	}
private:
	int _d = 2;
};
int main()
{
	Base b;
	Derive d;
	return 0;
}
  1. 派生类对象d中也有一个虚表指针,d对象由两部分构成,一部分是父类继承下来的成员,虚表指针也就是存在部分的另一部分是自己的成员。
  2. 基类b对象和派生类d对象虚表是不一样的,这里我们发现Func1完成了重写,所以d的虚表中存的是重写的Derive::Func1,所以虚函数的重写也叫作覆盖,覆盖就是指虚表中虚函数的覆盖。重写是语法的叫法,覆盖是原理层的叫法。
  3. 另外Func2继承下来后是虚函数,所以放进了虚表,Func3也继承下来了,但是不是虚函数,所以不会放进虚表。
  4. 虚函数表本质是一个存虚函数指针的指针数组,一般情况这个数组最后面放了一个nullptr。
  5. 总结一下派生类的虚表生成:a.先将基类中的虚表内容拷贝一份到派生类虚表中 b.如果派生类重写了基类中某个虚函数,用派生类自己的虚函数覆盖虚表中基类的虚函数 c.派生类自己新增加的虚函数按其在派生类中的声明次序增加到派生类虚表的最后。
  6. 这里还有一个童鞋们很容易混淆的问题:虚函数存在哪的?虚表存在哪的? 答:虚函数存在虚表,虚表存在对象中。注意上面的回答的错的。但是很多童鞋都是这样深以为然的。注意虚表存的是虚函数指针,不是虚函数,虚函数和普通函数一样的,都是存在代码段的,只是他的指针又存到了虚表中。另外对象中存的不是虚表,存的是虚表指针。

🍁多态原理

在CS2中,不同枪械的机动性不同:

class Gun
{
public:
	virtual void Mobility(Gun& gun) = 0;
};

class AK47 : public Gun
{
public:
	void Mobility(Gun& gun)
	{
		cout << "Mobility = " << _Mobility << endl;
	}
private:
	int _Mobility = 215;
};

class M4A4 : public Gun
{
public:
	void Mobility(Gun& gun)
	{
		cout << "Mobility = " << _Mobility << endl;
	}
private:
	int _Mobility = 225;
};

void Func(Gun& gun)
{
	gun.Mobility(gun);
}

int main()
{
	AK47 ak47;
	M4A4 m4a4;

	Gun& ak = ak47;
	Gun& m4 = m4a4;

	Func(ak);
	Func(m4);

	return 0;
}

在这里插入图片描述
在这里插入图片描述

  • 多态必须要满足两个条件:
    1.必须通过基类的指针或者引用调用虚函数
    2.被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写

举个简单例子解释,如下代码:

class Base
{
public:
	virtual void Func1()
	{
		cout << "Base::Func1()" << endl;
	}
	virtual void Func2()
	{
		cout << "Base::Func2()" << endl;
	}
	void Func3()
	{
		cout << "Base::Func3()" << endl;
	}
private:
	int _b = 1;
};
class Derive : public Base
{
public:
	virtual void Func1()
	{
			cout << "Derive::Func1()" << endl;
	}
private:
	int _d = 2;
};

int main()
{
	Base b;
	Derive d;
	Base& s1 = b;
	Base& s2 = d;

	s1.Func1();
	s2.Func1();
	return 0;
}

解释:Derive继承BaseFunc1进行重写,重写后的虚函数会产生新的地址,放入虚表中Base&引用子类Derive对象,会发生切割,切割部分其实就是继承Base部分,由于DeriveFunc1进行重写,所以s2虚表中的Func1是已经重写的。

图解:
在这里插入图片描述
在这里插入图片描述
你学会了吗?
好啦,本章对于《C++:多态(继承)》的学习就先到这里,如果有什么问题,还请指教指教,希望本篇文章能够对你有所帮助,我们下一篇见!!!

如你喜欢,点点赞就是对我的支持,感谢感谢!!!

请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/788030.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

更亮更好听的户外耳机,下班之后畅快运动,哈氪聆光体验

在当今市场上&#xff0c;蓝牙耳机种类繁多&#xff0c;现在正值酷热的夏季&#xff0c;有必要准备一副适合户外活动的蓝牙耳机&#xff0c;对此&#xff0c;我觉得气传导耳机更适合在户外锻炼或散步时使用。这种耳机设计通常为后挂式&#xff0c;不仅佩戴舒适&#xff0c;而且…

宝塔面板运行Admin.net框架

准备 宝塔安装 .netcore安装 Admin.net框架发布 宝塔面板设置 完结撒花 1.准备 服务器/虚拟机一台 系统Windows server / Ubuntu20.04&#xff08;本贴使用的是Ubuntu20.04版本系统&#xff09; Admin.net开发框架 先安装好服务器系统&#xff0c;这里就不做安装过程描述了&…

安装nodejs | npm报错

nodejs安装步骤: 官网&#xff1a;https://nodejs.org/en/ 在官网下载nodejs: 双击下载下来的msi安装包&#xff0c;一直点next&#xff0c;我选的安装目录是默认的: 测试是否安装成功&#xff1a; 输入cmd打开命令提示符&#xff0c;输入node -v可以看到版本&#xff0c;说…

“郑商企航”暑期社会实践赴美丽美艳直播基地开展调研

马常旭文化传媒网讯&#xff08;记者张明辉报道&#xff09;导读&#xff1a;2024 年 7 月 3 日&#xff0c;商学院暑期社会实践团“郑商企航”在河南省郑州市新密市岳村镇美丽美艳直播基地&#xff0c;展开了一场意义非凡的考察活动&#xff0c;团队成员深度调研了直播基地的产…

DMA方式的知识点笔记

苏泽 “弃工从研”的路上很孤独&#xff0c;于是我记下了些许笔记相伴&#xff0c;希望能够帮助到大家 目录 1. DMA基本概念 2. DMA传送过程 易错点 DMA控制器操作流程 3. DMA传送方式 这是单总线的结果 &#xff08;CPU说了算 所以不会产生于CPU的冲突&#xff09; 这…

idea创建dynamic web project

由于网课老师用的是eclipse,所以又得自己找教程了…… 解决方案&#xff1a; https://blog.csdn.net/Awt_FuDongLai/article/details/115523552

仕考网:公务员体检对视力有要求吗?

公务员招聘过程中的体检标准对视力有具体要求&#xff0c;根据不同的岗位职责有所差异。通常情况下&#xff0c;如果申请者双眼经过矫正后视力均低于4.8(小数视力0.6)&#xff0c;则会被视为不合格。 对于某些特殊岗位&#xff0c;如J察等&#xff0c;单侧裸眼视力若低于4.8也…

【教程】Github Page 添加自定义域名

目录 前言购买域名验证自定义域名映射自定义域名记录类型注意点参考 前言 Github Page 是 Github 提供的一个可以从 Github 仓库上托管静态网站的功能服务。默认当你建立起一个仓库后&#xff0c;在对应会有一个可供浏览的静态网站&#xff0c;例如 https://eternaldeath.gith…

【动态规划Ⅵ】背包问题 /// 组合问题

背包问题 什么是背包问题0-1背包问题分数背包完全背包问题重复背包问题 背包问题例题416. 分割等和子集474. 一和零 完全平方数279. 完全平方数322. 零钱兑换 排列与组合组合&#xff0c;无重复&#xff1a;518. 零钱兑换 II排列&#xff0c;可重复&#xff1a;377. 组合总和 Ⅳ…

MySQL架构优化及SQL优化

变更项目的整体架构是性能收益最大的方式。主要涉及两方面&#xff0c;一方面是从整个项目角度&#xff0c;引入一些中间件优化整体性能&#xff0c;另一方面是调整MySQL的部署架构&#xff0c;确保能承载更大的流量访问&#xff0c;提高数据层的整体吞吐。 1. 引入缓存中间件…

语义分割和实例分割区别?

语义分割&#xff1a;将图像中的每个像素分配给其对应的语义类别&#xff0c;其主要针对于像素&#xff0c;或者说它是像素级别的图像分割方法。&#xff1a;语义分割的目的是为了从像素级别理解图像的内容&#xff0c;并为图像中的每个像素分配一个对象类。 实例分割&#xf…

泛微E9开发 控制Radio框字段打印是否仅显示选中项文字

控制Radio框字段打印是否仅显示选中项文字 1、需求说明2、实现方法3、扩展知识点控制Radio框字段打印是否仅显示选中项文字格式参数说明样例 1、需求说明 当我们对单选框进行打印时&#xff0c;往往会把所有的选项一起打印出来&#xff08;如下图所示&#xff09;&#xff0c;现…

【1】A-Frame整体介绍

1.A-Frame是什么&#xff1f; A-Frame 是一个用于构建虚拟现实 (VR) 体验的 Web 框架。 A-Frame 基于 HTML 之上&#xff0c;因此上手简单。但 A-Frame 不仅仅是 3D 场景图或标记语言&#xff1b;它还是一种标记语言。其核心是一个强大的实体组件框架&#xff0c;为 Three.js …

昇思MindSpore学习入门-模型模块自定义

基础用法示例 神经网络模型由各种层(Layer)构成&#xff0c;MindSpore提供构造神经网络层的基础单元Cell&#xff0c;基于Cell进行神经网络封装。下面使用Cell构造经典模型AlexNet。 如图所示&#xff0c;AlexNet由5个卷积层与3个全连接层串联构成&#xff0c;我们使用mindspo…

秋招Java后端开发冲刺——并发篇2(ThreadLocal、Future接口)

本文对ThreadLocal类和Future接口进行了总结概括&#xff0c;包括ThreadLocal类的原理、内存泄露等问题&#xff0c;和Future接口的使用等问题。 一、ThreadLocal 1. 介绍 ThreadLocal&#xff08;线程局部变量&#xff09;是Java中的一个类&#xff0c;线程通过维护一个本地…

探索安卓四大组件:活动、服务、广播接收器和内容提供者

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;Android ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 1. Activity&#xff08;活动&#xff09; 概述&#xff1a; 生命周期&#xff1a; 使用方法&#xff1a; 2. Service&…

简过网:2024年一级造价工程师正在报名中,看看你有报考资格吗?

计划报考2024一级造价工程师的小伙伴要注意了&#xff0c;现在一造报名正在启动中&#xff0c;想考试的小伙伴一定要看清楚这些报考条件和考试内容哦&#xff0c;今天&#xff0c;小编和大家一块来分享一下&#xff0c;希望对你有帮助。 几个简单的问题&#xff0c;让你彻底了解…

2024年信息系统项目管理师1批次上午客观题参考答案及解析(3)

51、探索各种选项&#xff0c;权衡包括时间与成本、质量与成本、风险与进度、进度与质量等多种因素&#xff0c;在整个过程中&#xff0c;舍弃无效或次优的替代方案&#xff0c;这种不确定性应对方法是()。 A&#xff0e;集合设计 B&#xff0e;坚韧性 C&#xff0e;多种结果…

alibabacloud学习笔记11

讲解什么是配置中心及使用前后的好处 讲解Nacos作为配置中心面板介绍 官方文档 Nacos config alibaba/spring-cloud-alibaba Wiki GitHub 加入依赖&#xff1a; 订单服务和视频服务也加上这个依赖。 讲解Nacos作为配置中心实战 订单服务添加配置。 我们注释掉之前的配置。 …