C++反汇编——多态,面试题01

news2024/12/28 21:14:19

文章目录

  • 1.C++的三大特性
    • 1.1封装
    • 1.2继承
    • 1.3多态
      • 1.3.1 虚函数
      • 1.3.2 多态代码+反汇编分析。
        • 反汇编分析1——基类指针指向子类对象,构造过程。
        • 反汇编分析2——基类指针指向子类对象,调用虚函数getPrice()过程。
        • 反汇编分析3——基类对象,调用虚函数getPrice()过程。
        • 反汇编分析4——基类指针指向子类对象,析构过程。
        • 反汇编分析5——基类指针指向子类对象,析构过程,基类析构函数不是虚函数时。
      • 1.3.3 静态多态vs动态多态

1.C++的三大特性

1.1封装

将对象的属性和方法封装起来。为了模块化,便于使用者操作,同时可以隔离外部使用者对内部数据的干扰,提高了安全性。

类成员的三种属性:
private:本类使用。设置get和set方法,因为通过接口来访问和修改数据是可控的,相对安全。
protected:本类和子类使用。
public:公开的,都可以访问。

1.2继承

允许通过继承原有类的某些特性或全部特性而产生新的类,原有的类称为基类(父类),产生的类称为派生类(子类)。为了扩展和重用,减少重复代码。

1.3多态

发生在继承关系中,不同的对象,对于相同的方法有不同的操作逻辑。为了接口重用,提高代码的可复用性、可维护性和可扩充性。

多态的实现机制为虚函数。

1.3.1 虚函数

关键字:virtual

作用:允许在子类中重新定义与基类同名的函数,并且可以通过基类指针或引用来访问基类和子类的同名函数。

最常见的用法:声明基类的指针,利用该指针指向任意一个子类对象,调用相应的虚函数,可以根据指向的子类的不同而实现不同的方法。

实现原理:虚表+虚表指针。
在这里插入图片描述
当类存在虚函数时,编译器会为类创建一个虚表,虚表是一个数组,数组的元素存放的是虚函数地址。同时为每个类对象添加一个隐藏数据成员,即虚表指针,它被定义在对象首地址处。
【注意】 虚表只有一份,而有多少个对象,就有多少个虚表指针。

1.3.2 多态代码+反汇编分析。

1.定义了一个基类,图形类Shape,数据成员分别为价格price和面积area,两个虚成员函数分别为获取图形描述getDescription()和获取图形价格getPrice(),虚析构函数;
2.定义了一个子类,圆形类Circle,继承Shape,数据成员为半径radius,重写父类方法getDescription()和getPrice();
3.定义了一个子类,矩形类Rectangle,继承Shape,数据成员分别为长度length和宽度width,重写父类方法getDescription()和getPrice();
4.main()里,基类指针s1指向Circle类对象,基类指针s2指向Rectangle类对象,基类对象s3。

// ConsoleApplication5.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#include<iostream>
#include<string>
using namespace std;

class Shape 
{
protected:
    double price;
    double area;

public:
    Shape() :price(100),area(0) {}
    virtual ~Shape() { printf("%s\n", "Delete shape"); }

    virtual void getDescription() { printf("%s\n", "Base shape");}
    virtual void getPrice() { printf("%s%f\n", "Shape price ",price); }
};

class Circle : public Shape 
{
private:
    double radius; 

public:
    Circle(double r) : radius(r) { area = 3.14 * radius * radius; price = 100 + area * 6; }
    ~Circle() { printf("%s%f\n", "Delete circle with radius ",radius); }

    void getDescription() { printf("%s%f\n", "Circle with radius ",radius);}
    void getPrice(){ printf("%s%f%s%f\n", "Circle with area ", area," price ",price); }
};

class Rectangle : public Shape {
private:
    double length;
    double width;  

public:
    Rectangle(double l, double w) : length(l), width(w) { area = length * width; price = 100 + area * 6; }
    ~Rectangle() { printf("%s%f%s%f\n", "Delete rectangle with length ", length," and width ",width); }

    void getDescription() { printf("%s%f%s%f\n","Rectangle with length ", length, " and width ", width);}
    void getPrice() { printf("%s%f%s%f\n", "Rectangle with area ", area, " price ", price); }
};

int main() {
   
    Shape* s1 = new Circle(5.0);
    Shape* s2 = new Rectangle(4.0, 6.0);
    s1->getPrice();
    s2->getPrice();

    Shape s3;
    s3.getPrice();
    s3.getDescription();

    delete s1;
    delete s2;

    _CrtDumpMemoryLeaks();
    return 0;
}

程序执行结果,如下图。
在这里插入图片描述

反汇编分析1——基类指针指向子类对象,构造过程。

1.调用子类构造函数(Rectangle),如下图。
在这里插入图片描述

2.调用父类构造函数(Shape),如下图。
看寄存器eax,对象s2地址0x014E5AB8;
虚表指针0x00DC9E10;
length地址eax+18h,0x0014E5AD0;
width地址eax+20h,0x0014E5AD8;
在这里插入图片描述
area=length * width,area地址eax+10h,0x0014E5AC8。
price=100 + area * 6,price地址eax+8h,0x0014E5AC0,如下图。
请添加图片描述
基类数据成员声明顺序price、area。
子类数据成员声明顺序length、width,如下图。
在这里插入图片描述

反汇编分析2——基类指针指向子类对象,调用虚函数getPrice()过程。

1.取对象s2地址,存放进eax,0x014E5AB8。
2.取虚表指针,存放进edx,0x00DC9E10。
3.取虚函数getPrice()地址,0x00DC14D3,并调用,如下图。
在这里插入图片描述

反汇编分析3——基类对象,调用虚函数getPrice()过程。

基类对象调用自身虚函数时,没有构成多态性,所以没必要查表访问,编译器使用了直接调用方式,如下图。

基类对象s3地址0x0118FE90。
虚表指针0x00DC9F64。
虚析构函数地址0x00DC14BF。
虚函数getDescription()地址0x00DC10CD。
虚函数getPrice()地址0x00DC14CE。

虚函数声明顺序:析构函数、getDescription()、getPrice()。
在这里插入图片描述

反汇编分析4——基类指针指向子类对象,析构过程。

在这里插入图片描述
在这里插入图片描述
1.调用子类析构函数(Circle),如下图。
在这里插入图片描述
2.释放子类资源后,调用父类析构函数(Shape),如下图。
在这里插入图片描述

反汇编分析5——基类指针指向子类对象,析构过程,基类析构函数不是虚函数时。

只调用基类析构函数,如下图。
【注意】 由于子类析构函数不会被调用,子类资源没有正确释放,造成内存泄漏。
在这里插入图片描述
在这里插入图片描述

1.3.3 静态多态vs动态多态

1.静态多态在编译期完成,由模板实现;而动态多态在运行期完成,由继承、虚函数实现。
2.静态多态中接口是隐式的,以有效表达式为中心;而动态多态中接口是显式的,以函数签名为中心。
3.【注意】 虚函数表在编译的时候就确定了,而类对象的虚函数指针是在运行阶段确定的,这是实现多态的关键!

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

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

相关文章

数据库入门(sql文档+命令行)

一.基础知识 1.SQL&#xff08;Structured Query Language&#xff09;结构化查询语言分类&#xff1a; DDL数据定义语言用来定义数据库对象&#xff1a;数据库、表、字段DML数据操作语言对数据库进行增删改查DQL数据查询语言查询数据库中表的信息DCL数据控制语言用来创建数据…

C#中字典Dictionary与自定义类型CustomType之间的转换

C#中字典Dictionary与自定义类型CustomType之间的转换 思路&#xff1a; 可以使用反射System.Reflection来获取类的具体属性&#xff0c; 属性名称就映射字典的键Key。 新建控制台程序DictionaryCustomClassConversionDemo 第一步、新建关键转换类ConversionUtil。 类Con…

FFmpeg常用API与示例(二)—— 解封装与转封装

封装层 封装格式(container format)可以看作是编码流(音频流、视频流等)数据的一层外壳&#xff0c;将编码后的数据存储于此封装格式的文件之内。 封装又称容器&#xff0c;容器的称法更为形象&#xff0c;所谓容器&#xff0c;就是存放内容的器具&#xff0c;饮料是内容&…

机器人种类分析

2000年前&#xff0c;机器人主要应用于工业生产&#xff0c;俗称工业机器人&#xff0c;由示教器操控&#xff0c;帮助工厂释放劳动力&#xff0c;此时的机器人并没有太多智能而言&#xff0c;完全按照人类的命令执行动作&#xff0c;更加关注电气层面的驱动器、伺服电机、减速…

深度剖析:为何跨境卖家纷纷转向自养号测评?

自养号测评&#xff0c;作为跨境电商卖家的一种关键运营策略&#xff0c;具有举足轻重的地位。通过精心策划的自养号测评&#xff0c;卖家能够有效地推动产品销量的飙升、评论数量的积累&#xff0c;并在平台内实现排名的显著上升。这一系列的正面效果进而有助于提升产品的曝光…

每日一题——力扣27. 移除元素(举一反三)

题目链接&#xff1a;https://leetcode.cn/problems/remove-element/description/ 菜鸡写法&#xff1a; // 函数定义&#xff0c;移除数组nums中所有值为val的元素&#xff0c;并返回新的数组长度 int removeElement(int* nums, int numsSize, int val) {// 如果数组长度为…

kernel32.dll丢失要如何解决?电脑kernel32.dll文件下载方法

kernel32.dll丢失要怎么解决才好&#xff1f;其实针对这个问题还是有很多种的解决方法的&#xff0c;只要你明白了kernel32.dll的作用&#xff0c;了解kernel32.dll&#xff0c;那么就可以有很多种方法去解决&#xff0c;下面一起来看看吧。 一.了解kernel32.dll文件 kernel32…

更新、简略高效的用git(Gitee篇)

前提&#xff1a;因为很多编译软件虽然可以连接git&#xff0c;但是操作起来还是比较懵&#xff0c;不同软件有不同的上传git的方式&#xff0c;而且有的连着GitHub有的是Gitee&#xff0c;那么使用Git Bash无疑是万无一失的方式 然后这一篇也仅针对上传Gitee&#xff0c;上传G…

数据结构05:树与二叉树 习题01[C++]

考研笔记整理&#xff0c;本篇作为树与二叉树的基本概念习题&#xff0c;供小伙伴们参考~&#x1f95d;&#x1f95d; 之前的博文链接在此&#xff1a;数据结构05&#xff1a;树与二叉树[C]-CSDN博客~&#x1f95d;&#x1f95d; 第1版&#xff1a;王道书的课后习题~&#x1…

YOLO-World环境搭建推理测试

一、引子 CV做了这么多年&#xff0c;大多是在固定的数据集上训练&#xff0c;微调&#xff0c;测试。突然想起来一句话&#xff0c;I have a dream&#xff01;就是能不能不用再固定训练集上捣腾&#xff0c;也就是所谓的开放词汇目标检测&#xff08;OVD&#xff09;。偶尔翻…

【总结】CE认证详解

文章目录 CE认证 CE作用 适用范围 测试项目 一、2014/30/EU指令&#xff0c;电磁兼容&#xff08;EMC&#xff09;测试项目 二、2014/35/EU指令&#xff0c;低电压&#xff08;LVD&#xff09;测试项目 三、2011/65/EU指令&#xff0c;有害物质&#xff08;RoHS&#xff09…

Linux进程间通信方式

每个进程的用户空间都是独立的&#xff0c;不能相互访问。 所有进程的内核空间(32位系统3G-4G)都是共享的 应用场景 作为缓冲区&#xff0c;处理速度不同的进程之间的数据传输资源共享&#xff1a;多个进程之间共享同样的资源&#xff0c;一个进程对共享数据的修改&#xff0c…

MathType2024官方版数学公式编辑器功能全面介绍

在数字化学习和科研的浪潮中&#xff0c;数学公式的编辑与展示成为了不可或缺的一部分。MathType&#xff0c;作为一款专业的数学公式编辑器&#xff0c;凭借其强大的功能和便捷的操作&#xff0c;为科研人员、教师、学生等广大用户提供了极大的便利。下面&#xff0c;我们将对…

docker compose kafka集群部署

kafka集群部署 目录 部署zookeeper准备工作2、部署kafka准备工作3、编辑docker-compose.yml文件4、启动服务5、测试kafka6、web监控管理 部署zookeeper准备工作 mkdir data/zookeeper-{1,2,3}/{data,datalog,logs,conf} -p cat >data/zookeeper-1/conf/zoo.cfg<<EOF…

在CentOS 7服务器及Windows 10客户端间建立并配置NFS服务

在CentOS 7服务器及Windows 10客户端间建立并配置NFS服务 引言 网络文件系统(Network File System)&#xff0c;简称NFS&#xff0c;是一种分布式文件系统协议。它允许网络上的客户端机器像访问本地磁盘文件一样&#xff0c;通过网络访问服务器上的文件。在某些特定的业务场景中…

【Linux】模拟实现bash(简易版)

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前正在学习c和算法 ✈️专栏&#xff1a;Linux &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章有啥瑕疵&#xff0c;希望大佬指点一二 如果文章对…

未来相遇过去:博物馆藏品管理平台的科技革新之旅

引言&#xff1a; 尊重历史&#xff0c;意味着保护其实体的载体。在博物馆这个时间的容器中&#xff0c;每一件藏品都承载着人类文明的印记&#xff0c;它们是历史的低语&#xff0c;是过去对现在的细语。在这篇文章中&#xff0c;我将带您走进博物馆的幕后&#xff0c;探究藏品…

wireshark-cli工具Tshark工具使用教程

介绍 本文档基于wireshark-2.6.10/编写 tshark为wireshark工具的命令行版本呢&#xff0c; 在服务器版本服务器上&#xff0c;通过tshark工具可以实现和wireshark相同的功能。工具使用wireshark默认配置&#xff0c;对于wireshark一些常用的首选项&#xff0c;也可通过tshark…

文献速递:深度学习医学影像心脏疾病检测与诊断--基于迁移学习的生成对抗网络用于静态和动态心脏PET的衰减校正

Title 题目 Transfer learning‑based attenuation correction for static and dynamic cardiac PET using a generative adversarial network 基于迁移学习的生成对抗网络用于静态和动态心脏PET的衰减校正 01 文献速递介绍 心脏正电子发射断层扫描&#xff08;PET&#xf…

【ArcGIS Pro微课1000例】0059:计算地级城市之间的距离

一、加载数据并符号化 1. 加载实验数据 数据加载完毕。 2. 符号化设置 点击面状数据符号,在右侧的符号系统中选择黑色轮廓。 点击点状符号,选择以个样式。 3. 标注名称 选择地级市图层,打开标注选项卡,设置标注字段为name,设置字体属性,如下所示: