C++多态

news2024/11/30 12:42:16

目录

多态的概念

多态的定义和实现

深入理解多态

 C++11 override 和 final

重载、覆盖(重写)、隐藏(重定义)的对比

 抽象类

多态的原理

动态绑定与静态绑定

单继承和多继承关系的虚函数表


多态的概念

多态的概念:通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会
产生出不同的状态。

多态的定义和实现

多态的构成条件
多态是在不同继承关系的类对象,去调用同一函数,产生了不同的行为。比如Student继承了Person。Person对象买票全价,Student对象买票半价。
那么在继承中要构成多态还有两个条件:
1. 必须通过基类的指针或者引用调用虚函数
2. 被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写

虚函数
虚函数:即被virtual修饰的类成员函数称为虚函数

class Person {
public:
virtual void buy() 
{ 
    cout << "买票-全价" << endl;
}
};

虚函数的重写
虚函数的重写(覆盖):派生类中有一个跟基类完全相同的虚函数(即派生类虚函数与基类虚函数的返回值类型、函数名字、参数列表完全相同),称子类的虚函数重写了基类的虚函数。

 

class Person {
public:
	virtual void Buy() { cout << "买票-全价" << endl; }
};
class Student : public Person {
public:
	virtual void Buy() { cout << "买票-半价" << endl; }
	/*注意:在重写基类虚函数时,派生类的虚函数在不加virtual关键字时,虽然也可以构成重写(因
	为继承后基类的虚函数被继承下来了在派生类依旧保持虚函数属性),但是该种写法不是很规范,不建议
	这样使用*/
	/*void BuyTicket() { cout << "买票-半价" << endl; }*/
};
void Func(Person& p)
{
	p.Buy();
}
int main()
{
	Person ps;
	Student st;
	Func(ps);
	Func(st);
	return 0;
}

虚函数重写的两个例外:
1. 协变(基类与派生类虚函数返回值类型不同)
派生类重写基类虚函数时,与基类虚函数返回值类型不同。即基类虚函数返回基类对象的指
针或者引用,派生类虚函数返回派生类对象的指针或者引用时,称为协变。

class A{};
class B : public A {};
class Person {
public:
virtual A* f() {return new A;}
};
class Student : public Person {
public:
virtual B* f() {return new B;}
};

 2. 析构函数的重写(基类与派生类析构函数的名字不同)
如果基类的析构函数为虚函数,此时派生类析构函数只要定义,无论是否加virtual关键字,
都与基类的析构函数构成重写,虽然基类与派生类析构函数名字不同。虽然函数名不相同,
看起来违背了重写的规则,其实不然,这里可以理解为编译器对析构函数的名称做了特殊处
理,编译后析构函数的名称统一处理成destructor。

class Person {
public:
	virtual ~Person() { cout << "~Person()" << endl; }
};
class Student : public Person {
public:
	virtual ~Student() { cout << "~Student()" << endl; }
};
// 只有派生类Student的析构函数重写了Person的析构函数,下面的delete对象调用析构函
//数,才能构成多态,才能保证p1和p2指向的对象正确的调用析构函数。
int main()
{
	Person* p1 = new Person;
	Person* p2 = new Student;
	delete p1;
	delete p2;
	return 0;
}

析构派生类p1 会自动调用基类的析构函数 

如果基类的析构没有加virtual那么就会对基类连续析构两次

 

深入理解多态

接下来的讲解就是关于下面这段代码 

class Person {
public:
	virtual void BuyTicket() { cout << "买票-全价" << endl; }
protected:
	int _a;
};
class Student : public Person {
public:
	virtual void BuyTicket() { cout << "买票-半价" << endl; }
protected:
	int _b;
};
void Func(Person& p)
{
	p.BuyTicket();
}
int main()
{
	Person ps;
	Student st;
	Func(ps);
	Func(st);
	return 0;
}

 

从上面这张图可以看出来两个虚函数指针指向的地址是不同的。

总结:多态的本质原理,符合多态的两个条件,那么调用是就会到指向对象的虚表中找到对应的虚函数地址,进行调用。

接下来看一下多态调用和普通调用的区别:

 C++11 override 和 final

从上面可以看出,C++对函数重写的要求比较严格,但是有些情况下由于疏忽,可能会导致函数
名字母次序写反而无法构成重载,而这种错误在编译期间是不会报出的,只有在程序运行时没有
得到预期结果才来debug会得不偿失,因此:C++11提供了override和final两个关键字,可以帮
助用户检测是否重写。
1. final:修饰虚函数,表示该虚函数不能再被重写

2. override: 检查派生类虚函数是否重写了基类某个虚函数,如果没有重写编译报错。

class car
{
public:
virtual void Drive() final {}
};
class baoma :public car
{
public:
virtual void Drive() {cout << "baoma-舒适" << endl;}
};
class Car
{
public:
    virtual void Drive()  {}
};
class Benz :public Car 
{
public:
    virtual void Drive() override {cout << "Benz-舒适" << endl;}
};

注意:final关键字放在父类,override关键字放子类

重载、覆盖(重写)、隐藏(重定义)的对比


 抽象类

概念
在虚函数的后面写上 =0 ,则这个函数为纯虚函数。包含纯虚函数的类叫做抽象类(也叫接口类),抽象类不能实例化出对象。派生类继承后也不能实例化出对象,只有重写纯虚函数,派生
类才能实例化出对象。纯虚函数规范了派生类必须重写,另外纯虚函数更体现出了接口继承。
 

class Person {
public:
	virtual void BuyTicket() = 0;
protected:
	int _a;
};
class Student : public Person {
public:
	virtual void BuyTicket() { cout << "买票-半价" << endl; }
protected:
	int _b;
};

接口继承和实现继承
普通函数的继承是一种实现继承,派生类继承了基类函数,可以使用函数,继承的是函数的实现。虚函数的继承是一种接口继承,派生类继承的是基类虚函数的接口,目的是为了重写,达成多态,继承的是接口。所以如果不实现多态,不要把函数定义成虚函数。

多态的原理

虚函数表,下面这个sizeof(Base)是多少。

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

通过观察测试我们发现b对象是8bytes,除了_b成员,还多一个__vfptr放在对象的前面(注意有些
平台可能会放到对象的最后面,这个跟平台有关),对象中的这个指针我们叫做虚函数表指针(v代表virtual,f代表function)。一个含有虚函数的类中都至少都有一个虚函数表指针,因为虚函数的地址要被放到虚函数表中,虚函数表也简称虚表。

动态绑定与静态绑定

1. 静态绑定又称为前期绑定(早绑定),在程序编译期间确定了程序的行为,也称为静态多态,比如:函数重载
2. 动态绑定又称后期绑定(晚绑定),是在程序运行期间,根据具体拿到的类型确定程序的具体行为,调用具体的函数,也称为动态多态。

单继承和多继承关系的虚函数表

需要注意的是在单继承和多继承关系中,下面我们去关注的是派生类对象的虚表模型,因为基类
的虚表模型前面我们已经看过了。

单继承中的虚函数表

class Base {
public :
virtual void func1() { cout<<"Base::func1" <<endl;}
virtual void func2() {cout<<"Base::func2" <<endl;}
private :
int a;
};
class Derive :public Base {
public :
virtual void func1() {cout<<"Derive::func1" <<endl;}
virtual void func3() {cout<<"Derive::func3" <<endl;}
virtual void func4() {cout<<"Derive::func4" <<endl;}
private :
int b;
};

他的派生类的只有一个虚函数表中存储了上面四个函数的指针。

多继承中的虚函数表
 

class Base1 {
public:
virtual void func1() {cout << "Base1::func1" << endl;}
virtual void func2() {cout << "Base1::func2" << endl;}
private:
int b1;
};
class Base2 {
public:
virtual void func1() {cout << "Base2::func1" << endl;}
virtual void func2() {cout << "Base2::func2" << endl;}
private:
int b2;
};
class Derive : public Base1, public Base2 {
public:
virtual void func1() {cout << "Derive::func1" << endl;}
virtual void func3() {cout << "Derive::func3" << endl;}
private:
int d1;
};

这个派生类有两个虚函数表,第一个虚函数表存储了指三个函数的针,第二个虚函数表存储了两个函数的指针。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SSM整合(五)

SSM整合之事务管理(一) 1.核心准备工作 1.1 导入spring-tx依赖 <!-- 事务spring-tx --> <dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId><version>5.3.22</version> </dependen…

【附源码】计算机毕业设计JAVA研究生招生信息管理

【附源码】计算机毕业设计JAVA研究生招生信息管理 目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; JAVA …

旧苹果短信导入新苹果手机上,iphone短信迁移

概述&#xff1a;随着科技的快速发展&#xff0c;手机的更新换代周期也变得越来越短。那么问题来了&#xff1a;旧苹果短信导入新苹果手机上&#xff1f;相信这是新机主心中的痛点&#xff0c;那么今天小编就来教大家如何解决这个问题。 方法一、使用易我手机数据传输软件转移苹…

D0x-17(anti—Sp17)-3C12/TPGS抗精子蛋白单克隆抗体/维生素E聚乙二醇琥珀酸酯偶联阿霉素研究

下面分享了D0x-17(anti—Sp17)-3C12/TPGS抗精子蛋白单克隆抗体/维生素E聚乙二醇琥珀酸酯偶联阿霉素研究方法&#xff0c;来看&#xff01; D0x-TPGS聚乙二醇1000维生素E琥珀酸酯(TPGS)修饰阿霉素研究方法&#xff1a; 用硫酸铵梯度法制备TPGS修饰的阿霉素脂质体,并对其理化性质…

try/catch/finally的各种情况

众所周知&#xff0c;try语句报错&#xff0c;会执行catch语句&#xff0c;然后执行finally&#xff0c;以下这几种情况&#xff0c;看看会如何输出。 1、try语句中包含return&#xff0c;finally包含输出语句 public static void main(String[] args) {// write your code h…

YOLOX代码、预测(使用摄像头实时预测)及其添加SE注意力前后的实验结果

1. 代码获取 https://github.com/Le0v1n/ml_code/tree/main/ObjectDetection/YOLOX 如果代码对你有用&#xff0c;请star一下❤️ 2. 预测 2.1 图片预测 下载权值文件&#xff1a;https://github.com/Megvii-BaseDetection/YOLOX/releases/download/0.1.1rc0/yolox_s.pth将权…

iOS键盘通知弹框使用小结

项目开发中文本框输入的时候经常会用到键盘弹框遮挡的问题。解决办法就是根据底部键盘弹出的高度动态的改变对应view的位置。这里以多行文本框输入为例&#xff0c;效果图如下。 //第一步&#xff0c;注册监听键盘通知 [[NSNotificationCenter defaultCenter] addObserver:self…

只会 Python 不行,不会 Python 万万不行

当下的环境大家有目共睹&#xff0c;未来一段时间情况如何&#xff0c;想必不少人心里也清楚&#xff0c;技术人走到中年&#xff0c;难免会焦虑&#xff0c;职场上干得不爽&#xff0c;但是跳槽也不容易&#xff0c;加上不少企业裁员&#xff0c;换个满意的工作更是难上加难。…

JavaScript——周技能检测——菜单编辑——2022年11月22日(考完)

JavaScript——周技能检测——菜单编辑——2022年11月22日&#xff08;考完&#xff09; 一、语言和环境 1. 实现语言&#xff1a;JavaScript。 2. 开发环境&#xff1a;VScode。 二、要求 1、在文本框中输入两个操作数和选择运算符后&#xff0c;在页面上显示输出结果。 …

电影《名侦探柯南:万圣节的新娘》观后感

上周看了电影《名侦探柯南&#xff1a;万圣节的新娘》&#xff0c;讲述了一场即将发生在东京涉谷的爆炸案件&#xff0c;引来各方的关注&#xff0c;柯南在参与案件的过程中&#xff0c;找出真凶的故事。 故事属于侦探类&#xff0c;有悬疑反转等要素&#xff0c;还是挺好的。不…

推荐系统实战3——推荐系统中Embedding层工作原理浅析

推荐系统实战3——推荐系统中Embedding层工作原理浅析学习前言什么是Embedding一、为什么要有Embedding二、推荐系统中常见的Embedding处理方式1、字符串形式的输入2、连续值&#xff08;特定范围值&#xff09;的输入三、Embedding的注意点学习前言 Embedding层是推荐系统特征…

盘点一下今年世界杯中国赞助商及联名入圈品牌

作为全世界的超级体育赛事&#xff0c;今年世界杯的ip流量无疑是值得期待的。虽然中国球队缺席&#xff0c;但中国赞助的热情是丝毫不减&#xff0c;中国官方合作伙伴&#xff08;赞助商&#xff09;分别是蒙牛、海信、vivo和万达。除了万达&#xff0c;其余三大品牌都是来自各…

护眼灯真的可以护眼吗?2022护眼台灯该怎样选择

或许很多人看过一些报道&#xff0c;认为护眼灯是智商税&#xff0c;并不能护眼&#xff0c;但是&#xff0c;我们并不能因为一两款劣质灯具的不行就否定整个行业的产品&#xff0c;真正高质量的护眼灯&#xff0c;并没有像相关报道说的那样不堪&#xff0c;相反其光线对人眼具…

微信小程序商城迅速流行的决定因素

随着互联网的不断发展壮大&#xff0c;许多人更倾向于线上购物&#xff0c;享受到足不出户就能送货上门的购物体验&#xff0c;这使得线上商城占据了优势。而微信小程序商城更是广受好评。 小程序商城的经营模式在很大程度上契合了当下的消费需求和消费心理。它的情感链接&…

JavaScript开发工具WebStorm入门教程:如何安装WebStorm

WebStorm是jetbrains旗下一款JavaScript 开发工具&#xff0c;被广大JS开发者誉为"Web前端开发神器""最强大的HTML5编辑器""最智能的JavaSscript IDE"。 本文给大家讲解WebStorm的安装教程&#xff0c;欢迎下载最新版产品体验&#xff01; Web…

算法多重要你还不知道吗?字节大佬把LeetCode前400题的解答笔记都整理好了,头发大佬掉,我们跟着吃经验!

你知道现在LeetCode算法在大厂中的重要性吗&#xff1f; 前几天小编看了一个国内算法大神的短视频&#xff0c;他就在视频中指出了算法对当下无论是生活还是找工作中都是非常重要的&#xff01; 没错这个人就是江湖人称“左神”的左程云老师 小编也简单看了一下一些比较知名互…

定语从句------六级

1.复合句/从句三大类 从句在整个句子中做什么成分&#xff0c;就叫什么从句。 形容词性从句&#xff1a;定语从句&#xff0c;带有谓语的完整的结构在另一个句子中做定语 名词性从句 副词性从句&#xff1a;状语从句 从句典型的标志&#xff0c;带有关系词2.定语从句&#xff1…

selenium⾃动化测试⾯试题及答案,看看你会多少?

说到UI自动化&#xff0c;可能大家和我一样&#xff0c;主要是用Selenium。毕竟Selenium可是UI自动化方面的王者。 而且Selenium 支持多平台&#xff0c;可以模拟真实浏览器&#xff0c;也支持多种浏览器&#xff0c;免费开源&#xff0c;对商业用户也没有任何限制&#xff0c…

分布式任务调度项目xxl-job

xxl-job简介 分布式任务调度项目xxl-job的官网&#xff1a;分布式任务调度平台XXL-JOB 大众点评的分布式任务调度平台&#xff0c;是一个轻量级分布式任务调度平台, 其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线&#xff0c…

【2012】408联考数据结构真题整理

2012年 1 题目 解析 递归 2 题目 答案&#xff1a;A 解析 3 题目 解析 4 题目 答案&#xff1a;B 解析 T1&#xff1a;1T2&#xff1a;2T3&#xff1a;2 1 1 4T4&#xff1a;T3 T2 1 2 4 1 7T5&#xff1a;T4 T3 1 7 4 1 12T6&#xff1a;T5 T4 1 …