【C++】类与对象——多态详解

目录

一、多态的定义

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

三、析构函数重写

四、C++11 override 和 final

1. final

2. override

五、抽象类

六、多态的原理


一、多态的定义

多态是在不同继承关系的类对象,去调用同一函数,产生了不同的行为。比如Student继承了 Person。Person对象买票全价,Student对象买票半价。

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

那么在继承中要构成多态还有两个条件:

  1. 必须通过基类的指针或者引用调用虚函数
  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;
}

四、C++11 override 和 final

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

1. final

修饰虚函数,表示该虚函数不能再被重写

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

2. override

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

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

五、抽象类

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

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;}
};
void Test()
{Car* pBenz = new Benz;pBenz->Drive();Car* pBMW = new BMW;pBMW->Drive();
}

接口继承与实现继承

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

六、多态的原理

多态的关键在于通过基类指针或引用调用一个虚函数时,编译时不能确定到底调用的是基类还是派生类的函数,运行时才能确定。

class A 
{
public:int i;virtual void Print() { } // 虚函数
};class B
{
public:int n;void Print() { } 
};int main() 
{cout << sizeof(A) << ","<< sizeof(B);return 0;
}

在32位环境下,运行上面函数。

可以发现有虚函数的类,多出了4个字节,在32位机子上指针类型大小正好是4个字节,多出来这四个字节,就是一个指向虚函数表的指针。

// 基类
class Base 
{
public:int i;virtual void Print() { } // 虚函数
};// 派生类
class Derived : public Base
{
public:int n;virtual void Print() { } // 虚函数
};

上面 Derived 类继承了 Base类,两个类都有「虚函数」,那么它「虚函数表」的形式可以理解成下图:

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

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

相关文章

访存优化实践之一 : CPU、GPU、DDR与访存路径介绍

一、CPU的访存路径 上图是目前主流的CPU架构介绍。可以看到,CPU的访存路径:先经过MMU,然后经过Cache,最后到达DRAM。这其中涉及到的关键内容为基于MMU的内存管理以及缓存机制。 1.1、基于MMU的内存管理 众所周知,在计算机设计之处是没有虚拟地址的概念的,CPU发出的地址即…

centos7.9用docker运行一个nginx容器

首先你的linux 系统里面已经安装好了docker&#xff0c;docker的安装教程看这个 1&#xff0c;下载nginx镜像 有很多文章会把镜像下载说成是拉取镜像&#xff0c; 我觉得就是下载的意思啊&#xff0c;搞不懂为什么要说拉取&#xff1f; docker pull nginx 下载最新版 Nginx …

SpringBoot如何实现跨域?

定义一个配置类&#xff0c;实现WebMvcConfigurer接口&#xff0c;重写addCorsMappings方法 Configuration public class CorsConfig implements WebMvcConfigurer {Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**").allow…

LeetCode刷题笔记第2769题:找到最大的可达成数字

LeetCode刷题笔记第2769题&#xff1a;找到最大的可达成数字 题目&#xff1a; 想法&#xff1a; 从题目中可以看出&#xff0c;num经过t次增减变为x&#xff0c;x即为可达成数字。因为要求最大的可达成数字&#xff0c;需要满足num一直增加&#xff0c;x一直减少&#xff0c…

Spring Boot: 为 JPA 插上翅膀的 QueryDSL

1. 引言 不可否认的是 JPA 使用是非常方便的&#xff0c;极简化的配置&#xff0c;只需要使用注解&#xff0c;无需任何 xml 的配置文件&#xff0c;语义简单易懂&#xff0c;但是&#xff0c;以上的一切都建立在单表查询的前提下的&#xff0c;我们可以使用 JPA 默认提供的方法…

力扣刷题笔记——Day1

二分查找 题目描述&#xff1a;给定一个 n 个元素有序的&#xff08;升序&#xff09;整型数组 nums 和一个目标值 target &#xff0c;写一个函数搜索 nums 中的 target&#xff0c;如果目标值存在返回下标&#xff0c;否则返回 -1。 eg1&#xff1a;输入: nums [-1,0,3,5…

蛮力法0/1背包问题实验

实验项目1 蛮力法 实验题目 使用蛮力法解决0/1背包问题。 ​ 问题描述&#xff1a;给定n个重量(weight)为{w1, w2, … ,wn}、价值(key)为{v1, v2, … ,vn}的物品和一个**容量为C(contain)**的背包&#xff0c;求这些物品中的一个最有价值的子集&#xff0c;且要能够装到背包中…

【简单介绍下链表基础知识】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

嵌入式linux系统中文件系统制作方法详解

第一:制作目的 1、掌握嵌入式Ubuntu系统的构建方法 2、熟悉嵌入式Ubuntu文件系统映射压缩打包方法 3、掌握RK3399linux系统单文件系统更新方法 Ubuntu根文件系统制作完成之后,把制作好的ubuntu文件系统映射文件在出厂系统的基础上替换原有的ubuntu根文件系统,即对 Linux 系统…

vue data中的return

vue 的data return 是干啥的呢&#xff0c;vue中页面中绑定的变量都要放在data的return中&#xff0c;可以赋值&#xff0c;值可在script中改&#xff0c;修改引用就用this了 如果不使用return包裹的数据会在项目的全局中可见&#xff0c;会造成变量污染&#xff1b; 使用retu…

《AI学习笔记》大模型-微调/训练区别以及流程

阿丹&#xff1a; 之前一直对于大模型的微调和训练这两个名词不是很清晰&#xff0c;所有找了一个时间来弄明白到底有什么区别以及到底要怎么去使用去做。并且上手实践一下。 大模型业务全流程&#xff1a; 大模型为啥要微调&#xff1f;有哪些微调方式&#xff1f; 模型参数…

mac vscode 怎么配置git密码

1. 使用 Git 凭证管理器 Git 凭证管理器 (Git Credential Manager) 可以帮助你安全地存储和管理 Git 凭证。以下是配置步骤&#xff1a; 安装 Git 凭证管理器&#xff1a; 如果没有安装 Git&#xff0c;可以先通过以下命令安装 Homebrew&#xff1a; /bin/bash -c "$(cur…

简易进程池的实现

什么是进程池&#xff1f; 进程池&#xff08;Process Pool&#xff09;是一种用于管理和复用多个进程的技术或设计模式。在进程池中&#xff0c;一定数量的进程会被预先创建并保持在内存中&#xff0c;以便在需要时立即使用&#xff0c;而不是每次需要进程时都重新创建新的进程…

每日一题《leetcode--1472.设计浏览器历史记录》

https://leetcode.cn/problems/design-browser-history/ 这里我是用双栈实现前进和后退。 #define URL_SIZE 21 #define STACK_SIZE 5000typedef struct {char *BackStack[STACK_SIZE]; //回退栈char *ForwardStack[STACK_SIZE]; //前进栈int BackTop; //回退栈的栈顶下标…

Kubectl 的使用——k8s陈述式资源管理

一、kebuctl简介: kubectl 是官方的CLI命令行工具&#xff0c;用于与 apiserver 进行通信&#xff0c;将用户在命令行输入的命令&#xff0c;组织并转化为 apiserver 能识别的信息&#xff0c;进而实现管理 k8s 各种资源的一种有效途径。 对资源的增、删、查操作比较方便&…

JavaScript表达式语句一

表达式尾部假分号会形成一个表达式语句。默认的独立一行也是一个表达式语句。 语句块是由大括号包含一个或多个语句&#xff0c;形成的代码片段。 条件语句 程序右三种基结构&#xff1a;顺序、选择、循环。条件语句属于选择结构。 if语句 基本语法&#xff1a;if(条件语句…

使用nvm管理nodejs多个版本

在工作中&#xff0c;可能会遇到同时使用vue2和vue3开发项目&#xff0c;但他们的nodejs版本又不同&#xff0c;给你带来了困扰&#xff0c;不知道怎么办&#xff1f;这时就可以使用nvm管理多个nodejs版本 第一步&#xff1a;先去github上面下载nvm 这是下载地址&#xff1a;…

001 mongodb

文章目录 NoSql分类键值(Key-Value)存储数据库列存储数据库文档型数据库图形(Graph)数据库 NoSql的应用场景 MongoDb笛卡尔集mysql与mongodb逻辑结构对比mongodb社区版下载地址windows mongodb7.0配置安装mongoshell下载地址windows下创建名为mongod.cfg的配置文件运行mongodb检…

强化师资,优路教育为职教发展增动力

伴随着科学技术的进步&#xff0c;新兴产业蓬勃发展&#xff0c;在以可持续发展为目标的当下&#xff0c;亟需更多具备扎实有效、强大竞争力的复合型人才投入其中。职业教育作为培养高素质技术技能人才的主要力量之一&#xff0c;是赋能新质生产力发展的关键因素&#xff0c;这…

Fastjson漏洞之CVE-2017-18349

前言&#xff1a; 要想理解漏洞原理&#xff0c;首先看看Fastjson是什么&#xff0c;具体用来做什么才能更好的找到可以利用的场景&#xff1a; Fastjson 是一个由阿里巴巴开发的 Java 语言实现的高性能 JSON 解析器和生成器。它具有以下特点: 快速&#xff1a;Fastjson 在序列…