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

文章目录

  • 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.mzph.cn/diannao/9618.shtml

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

相关文章

electron-vite工具打包后通过内置配置文件动态修改接口地址实现方法

系列文章目录 electronvitevue3 快速入门教程 文章目录 系列文章目录前言一、实现过程二、代码演示1.resources/env.json2.App.vue3.main/index.js4.request.js5.安装后修改 前言 使用electron-vite 工具开发项目打包完后每次要改接口地址都要重新打包&#xff0c;对于多环境…

思维导图如何用AI生成?借助这几款工具

思维导图如何用AI生成&#xff1f;在数字化时代&#xff0c;思维导图作为一种高效的信息组织与展示工具&#xff0c;被广泛应用于学习、工作和项目管理中。随着人工智能技术的飞速发展&#xff0c;AI生成思维导图已成为现实&#xff0c;极大地提升了创建思维导图的效率和创意。…

翻译《The Old New Thing》 - Restating the obvious about the WM_COMMAND message

Restating the obvious about the WM_COMMAND message - The Old New Thing (microsoft.com)https://devblogs.microsoft.com/oldnewthing/20060302-10/?p32093 Raymond Chen 2006年03月02日 关于 WM_COMMAND 消息的显而易见的知识点补充 简要 本文详细解释了 WM_COMMAND 消息…

Django 静态文件管理与部署指南

title: Django 静态文件管理与部署指南 date: 2024/5/10 17:38:36 updated: 2024/5/10 17:38:36 categories: 后端开发 tags: WebOptCDN加速DjangoCompressWebpackStaticDeployCICD-ToolsSecStatic 第一章&#xff1a;介绍 Django 静态文件的概念和重要性 在 Web 开发中&a…

算法-靠谱的车

import java.util.*; public class Main{public static void main(String[] args){Scanner innew Scanner(System.in);int nin.nextInt(),copyn;// 取每一位上的数放入数组List<Integer> listnew ArrayList<>();while(n!0){int resn%10;list.add(0,res);n/10;}// 转…

Linux diff命令(比较两个文件或目录的内容差异)

文章目录 Linux diff 命令详解教程基本用法比较文件输出解释 递归比较&#xff08;-r&#xff09;示例代码 控制输出格式统一格式&#xff08;-u&#xff09;上下文格式&#xff08;-c&#xff09; 高级选项忽略所有空白差异&#xff08;-w&#xff09;仅报告文件是否不同 Linu…

如何通过AI技术提升内容生产的效率和质量

如何利用AI提高内容生产效率? 利用人工智能&#xff08;AI&#xff09;技术提高内容生产效率和质量&#xff0c;可以从以下几个关键方面入手&#xff1a; 1. 智能内容策划与选题 数据分析&#xff1a;AI能够分析用户行为数据、市场趋势、竞争对手策略等&#xff0c;帮助内容…

纯 CSS 实现标签自动显示超出数量

现代 CSS 强大的令人难以置信。 这次我们来用 CSS 实现这样一个功能&#xff1a;有多个宽度不同的标签水平排列&#xff0c;当外层宽度不足时&#xff0c;会提示超出的数量&#xff0c;演示效果如下 如果让我用 JavaScript来实现估计都有点折腾&#xff0c;毕竟宽度都是动态的…

有什么方便实用的黏土特效教程?6个软件教你快速进行特效制作

有什么方便实用的黏土特效教程&#xff1f;6个软件教你快速进行特效制作 作为时尚小达人&#xff0c;你自己是否想要制作出属于自己的黏土特效照片呢&#xff1f;比如下面几种。 看到这些黏土特效软件有没有心动&#xff0c;下面我也为大家详细的介绍一下可以制作出对应特效的…

Java 集合-List

集合主要分为两组(单列集合, 双列集合) Connection 接口有两个重要的子接口LIst 和 Set, 它们的实现子类都是单列集合, Map 接口的实现子类是双列集合, 存放的是 K-V Connection 接口 Collection 接口和常用方法 下面以 ArrayList 演示一下 add: 添加单个元素remove: 删除指…

Socket学习记录

本次学习Socket的编程开发&#xff0c;该技术在一些通讯软件&#xff0c;比如说微信&#xff0c;QQ等有广泛应用。 网络结构 这些都是计算机网络中的内容&#xff0c;我们在这里简单回顾一下&#xff1a; UDP(User Datagram Protocol):用户数据报协议;TCP(Transmission Contr…

python笔记(16)模块

模块是组织代码、实现复用、提升开发效率的关键元素。它们如同积木块一样&#xff0c;构成了Python程序的基石。本 一、理解Python模块&#xff1a;定义与基本特性 1. 定义 模块&#xff0c;简单来说&#xff0c;就是包含Python定义和语句的文件。它可以是一个.py文件&#…

这是一关于DSC相关的文档

这是一关于DSC相关的文档 上面这幅图清晰的展示了somewhat flat的像素图示

机器学习算法应用——关联规则分析(4-4)

关联规则分析&#xff08;4-4&#xff09; 关联规则分析&#xff08;Association Rule Mining&#xff09;是一种基于频繁项集的分析方法&#xff0c;它以最常出现在一起的元素之间的关系作为分析对象&#xff0c;主要用于发掘大数据中隐藏的关联规则&#xff0c;是数据挖掘技术…

JAVA_1

JAVA_1 一、JAVA8种数据类型二、JAVA数据类型自动和强制转换三、JAVA运算符 一、JAVA8种数据类型 1.byte 1字节 2.short 2字节 3.int 4字节 4.long 8字节 5.float 4字节 6.double 8字节 7.char 2字节 8.boolean true和false import java.util.Scanner;public class test1_dat…

Python教程:一文了解PageObject模式

PageObject 模式是一种用于测试自动化的设计模式&#xff0c;它将页面的功能和页面的实现分开&#xff0c;提高了代码的可维护性和可重用性。本文将从基础概念开始&#xff0c;逐步介绍 Python 中的 PageObject 模式&#xff0c;并提供详细的代码示例。 1. 什么是 PageObject 模…

小众行业风口:Q1季度擦窗机器人行业线上市场销售数据分析

今天给大家分享一个2024年的小众行业增长风口——擦窗机器人。 作为家居自动化里的重要一员&#xff0c;擦窗机器人可以简称为擦窗神器&#xff0c;是为了解决大户型家庭的外窗清洁痛点而存在。而目前&#xff0c;擦窗机器人行业正在走向成熟&#xff0c;且市场需求量居高不下…

Linux专题-Makefile(1)

1.Makefile中的注释使用 # 2. Makefile中的静默执行。 makefile中&#xff0c;默认情况下执行一行命令前会先把这一行命令打印出来&#xff0c;然后再执行这条命令。如果不想看到打印的命令&#xff0c;则可以使用静默执 行的功能&#xff0c;即仅打印出命令执行的结果。使用方…

苹果公司因iPad广告争议而道歉,承认“未达标”|TodayAI

周二&#xff0c;苹果公司发布了一则新的iPad Pro广告&#xff0c;引起了广泛争议&#xff0c;该公司随后发表道歉声明&#xff0c;承认这则广告“未达标”。这则名为“压碎&#xff01;”的广告意图展示全新的M4芯片iPad Pro的创意潜力&#xff0c;但却因其表现方式而备受批评…

设计模式学习笔记 - 回顾总结:在实际软件开发中常用的设计思想、原则和模式

概述 本章&#xff0c;先来回顾下整个专栏的知识体系&#xff0c;主要包括面向对象、设计原则、编码规范、重构技巧、设计模式五个部分。 面向对象 相对于面向过程、函数式编程&#xff0c;面向对象是现在最主流的编程范式。纯面向过程的编程方法&#xff0c;现在已经不多见了…