C++进阶--多态

概念

多态是面向对象编程中的一个重要概念,它允许不同类型的对象对同一个消息做出不同的响应。具体的来说,当相同的消息传递给不同的对象时,这些对象能够以不同的方式进行处理,从而产生不同的行为

对于多态的实现,需要一定的条件
在这里插入图片描述

虚函数的重写

在这里插入图片描述

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

但有两个例外。

协变

class A {};
class B : public A {};
class Person {
public:virtual A* f() { cout << "A:f()" << endl;return new A;}
};
class Student : public Person {
public:virtual B* f(){cout << "B:f()" << endl;return new B;}
};int main()
{Person* p = new Student;p->f();return 0;
}

在这里插入图片描述

析构函数的重写

class Person {
public:virtual ~Person() { cout << "~Person()" << endl; }
};
class Student : public Person {
public:virtual ~Student() { cout << "~Student()" << endl; }
};int main()
{Person* p1 = new Person;Person* p2 = new Student;delete p1;//p1->destructor()+ operator delete(p1)delete p2;//p2->destructor()+ operator delete(p2)return 0;
}

在这里插入图片描述

c++11的两个关键字

在这里插入图片描述

多态的实现

class Person {
public:virtual ~Person(){ cout << "~Person()" << endl;}virtual void BuyTicket() { cout << "买票-全价" << endl; }
};
class Student : public Person {
public:virtual ~Student(){ // delete _ptr;cout << "~Student()" << endl;}virtual void BuyTicket() { cout << "买票-半价" << endl; }
};int main()
{Person p;Student s;//多态调用Person* p1 = new Person;Person* p2 = new Student;p1->BuyTicket();p2->BuyTicket();delete p1;delete p2;return 0;
}

在这里插入图片描述

多态的原理

虚函数表

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;
};void f(Base* ptr)
{ptr->Func1();
}// vitual function table
int main()
{Base bb;Derive dd;f(&bb);f(&dd);return 0;
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
总结:
1.派生类对象d也有一个虚表指针,并且该虚表指针地址和基类的不相同
2.在虚表中,发现func1的地址不一样,而func2的地址一样,这是因为func1完成了重写,被重写的虚函数地址是不一样的
3.在虚表中,只有是虚函数才有被放进虚表中
4.虚表本质就是一个存虚函数指针的指针数组,一般情况这个数组最后面会放nullptr;
5.对于派生类虚表的生成,派生类会先拷贝一份基类的虚表地址(地址是不一样的),如果派生类中有函数进行了重写,那么用派生类自己的虚函数覆盖基类的虚函数,最后派生类有新增的虚函数按其在派生类中的声明次序增加到派生类虚表的最后;

在这里插入图片描述

原理

所以可以看出,多态实际上就是利用了虚函数的重写,让虚函数的地址是不同的,当基类的指针或引用指向自己或者派生类时,会根据虚表中对应的虚函数地址来进行运行
这就达到了不同对象完成同一行为展示出的不同形态;
并且满足多态的函数调用,不是在编译时确定的,是在运行后到具体对象中取栈的,普通的函数调用都是在编译期间确定好的

动态绑定和静态绑定

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

抽象类

class Car
{
public:virtual void Drive() = 0;
};
class Benz :public Car
{
public:virtual void Drive(){cout << "Benz-舒适" << endl;}
};
class BMW :public Car
{
public:virtual void Drive(){cout << "BMW-操控" << endl;}
};int main()
{//抽象类不能实例化//Car c1;Benz b;Car* p = new Benz;p->Drive();p = new BMW;p->Drive();
}

在这里插入图片描述
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/3b24fa596f35418cbc02c7c236bfdcbc.png

接口继承和实现继承

在这里插入图片描述

虚函数表存于哪个区域

class Base
{
public:Base():_b(2){cout << "Base()" << endl;}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;}virtual void Func3(){cout << "Derive::Func3()" << endl;}
private:int _d = 2;
};int main()
{Base b;Base b1;Base b2;Derive d;int i = 0;static int j = 1;int* p1 = new int;const char* p2 = "xxx";printf("栈:%p\n", &i);printf("静态区:%p\n", &j);printf("堆:%p\n", p1);printf("常量区:%p\n", p2);Base* p3 = &b;Derive* p4 = &d;printf("Base虚表地址:%p\n", *(int*)p3);printf("Base虚表地址:%p\n", *(int*)p4);return 0;
}

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

单继承的虚表

在这里插入图片描述

typedef void(*VF_PTR)();//函数指针
void PrintVFT(VF_PTR* vft,int n)
{for (size_t i = 0; i<n; i++){printf("[%d]:%p->", i, vft[i]);VF_PTR f = vft[i];(*f)();}cout << endl << endl;
}//打印虚函数表
int main()
{Derive d;PrintVFT((VF_PTR*)(*((int*)&d)));
}

在这里插入图片描述

多继承的虚表

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;
};int main()
{Derive d;cout << sizeof(d) << endl;Base1* ptr1 = &d;Base2* ptr2 = &d;PrintVFT((VF_PTR*)(*(int*)ptr1),3);PrintVFT((VF_PTR*)(*(int*)ptr2),2);return 0;
}

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

内联和static

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

开源MES/免费MES,提升生产效率的最佳选择

开源MES系统为企业提供了一个灵活、经济的选择。企业可以根据自身需求选择合适的开源MES系统&#xff0c;并进行定制开发&#xff0c;可以节约不少成本。开源MES系统的出现&#xff0c;促进了整个制造业的创新和发展&#xff0c;有助于企业提高运营效率和竞争力。今天介绍一款市…

面试中问到的算法题。————目录树生成

前言 我在面试中遇到了算法题&#xff0c;也是我第一次面试&#xff0c;也不知道是太紧张了还是太久没刷算法题了&#xff0c;感觉压有点懵的状态&#xff0c;所以当时面试的时候没有做出来或者说只做了一半没有做完。 面试完成后&#xff0c;我又重新审视了一下题目&#xff…

混乱字母排序——欧拉路数论

题目描述 小明接到一个神秘的任务&#xff1a;对于给定的 n 个没有顺序的字母对&#xff08;无序代表这两个字母可以前后顺序颠倒&#xff0c;区分大小写&#xff09;。请构造一个有 (n1) 个字母的混乱字符串使得每个字母对都在这个字符串中出现。 输入输出格式 输入格式 第…

2023年06月CCF-GESP编程能力等级认证Python编程四级真题解析

Python等级认证GESP(1~6级)全部真题・点这里 一、单选题(共15题,共30分) 第1题 高级语言编写的程序需要经过以下( )操作,可以生成在计算机上运行的可执行代码。 A:编辑 B:保存 C:调试 D:编译 答案:D 第2题 排序算法是稳定的(Stable Sorting),就是指排序算…

iOS pod sdk开发到发布,记录

本文章记录从开发sdk到发布cocopod的问题和流程,省的每次都忘还得重新查 1:pod lib create (sdk名称) 命令创建 工程结构,然后根据命令行提示进行选择. What platform do you want to use?? [ iOS / macOS ]。~》 iOS What language do you want to use?? [ Swift / Obj…

鸿蒙开发有必要学吗?看完这篇再决定吧

在科技的潮流中&#xff0c;每一次新操作系统的诞生都是对旧秩序的挑战与新机遇的孕育。鸿蒙操作系统的出现&#xff0c;无疑是近年来科技界最引人注目的事件之一。自华为于2019年正式推出鸿蒙系统以来&#xff0c;这一我们自主研发的操作系统不仅在国内引起巨大反响&#xff0…

解决ModuleNotFoundError: No module named ‘pysqlite2‘

目录 一、问题描述 二、问题分析 三、解决方法 四、参考文章 一、问题描述&#xff1a; 新建conda编译环境。安装Jupyter后打不开&#xff0c;报错&#xff1a; 二、问题分析&#xff1a; 缺少sqlite3动态链接库 三、解决方法&#xff1a; SQLite Download Page 下载…

力扣461. 汉明距离(位运算)

Problem: 461. 汉明距离 文章目录 题目描述思路复杂度Code 题目描述 思路 Problem: 力扣191. 位1的个数&#xff08;位运算&#xff09; 该题只需要在上题的基础上先对两个数进行一次异或操作即可 复杂度 时间复杂度: O ( 1 ) O(1) O(1) 空间复杂度: O ( 1 ) O(1) O(1) Code …

【LeetCode】每日一题 2024_2_2 石子游戏 VI(排序、贪心)

文章目录 LeetCode&#xff1f;启动&#xff01;&#xff01;&#xff01;题目&#xff1a;石子游戏 VI题目描述代码与解题思路 LeetCode&#xff1f;启动&#xff01;&#xff01;&#xff01; 题目&#xff1a;石子游戏 VI 题目链接&#xff1a;1686. 石子游戏 VI 题目描述…

Linux - iptables 防火墙

一. 安全技术和防火墙 1.安全技术 入侵检测系统&#xff08;Intrusion Detection Systems&#xff09;&#xff1a;特点是不阻断任何网络访问&#xff0c;量化、定位来自内外网络的威胁情况&#xff0c;主要以提供报警和事后监督为主&#xff0c;提供有针对性的指导措施和安全…

linux 下mongodb7版本怎么连?

概述&#xff1a;linux下的mongodb7版本默认是没有安装客户端的&#xff0c;需要下载shell客户端才能连&#xff0c;下载之后解压&#xff0c;不需要编译&#xff0c;进入bin目录就能自己运行&#xff0c;。 安装&#xff1a; linux 下mongodb7版本没有安装客户端需要当地下载…

【GitHub项目推荐--一个由OpenAI提供支持的聊天机器人和虚拟助手的构建平台】【转载】

Botpress Botpress是一个开源项目&#xff0c;它提供了一个平台&#xff0c;用于构建、部署和管理基于人工智能的聊天机器人和虚拟助手 github地址&#xff1a; https://github.com/botpress/botpress Botpress的介绍 Botpress是一个开源项目&#xff0c;它提供了一个平台&…