当前位置: 首页 > news >正文

C++的类和new和delete和菱形继承机制

文章目录

  • 参考
  • 虚函数
  • 使用虚函数的class结构
  • 相关实现
  • 源码
  • IDA反编译
  • 子类虚表和父类虚表
  • 调用函数
  • 菱形继承

参考

https://showlinkroom.me/2017/08/21/C-%E9%80%86%E5%90%91%E5%88%86%E6%9E%90/
https://www.cnblogs.com/bonelee/p/17299985.html
https://xz.aliyun.com/t/5242?time__1311=n4%2BxnD07itGQ%3DD54AKDsA3xCuU%3DwQNY4D&alichlgref=https%3A%2F%2Fxz.aliyun.com%2Fu%2F15779#toc-3

虚函数

在C++中,虚函数(virtual function)是一种特殊的成员函数,它允许在派生类中重写或覆盖基类中定义的函数,从而实现多态性(polymorphism)。虚函数的关键特征和用途可以概括如下:

  1. 声明与定义
    要声明一个虚函数,需要在基类的成员函数声明前加上virtual关键字。例如:

    class Base {
    public:virtual void someFunction() {// 基类的实现}
    };
    

    派生类可以重写该函数,也可以不重写,如果重写,则在派生类中提供新的实现:

    class Derived : public Base {
    public:void someFunction() override {// 派生类的实现}
    };
    
  2. 虚函数表(VTable)
    实现虚函数的机制通常涉及到虚函数表(Virtual Table,简称vtable)。每个含有虚函数的类都会有一个虚函数表,表中存储着该类所有虚函数的地址。每个对象都有一个指向相应类虚函数表的指针(称为vptr)。当通过基类指针或引用调用虚函数时,程序会根据对象的vptr查找到正确的虚函数表,从而调用实际对象类型的函数实现。

  3. 纯虚函数与抽象类
    如果基类中的虚函数没有提供实现,并且在声明时被= 0初始化,那么这个函数被称为纯虚函数。含有纯虚函数的类不能实例化,只能作为基类被继承,这样的类称为抽象类。

使用虚函数的class结构

在这里插入图片描述

相关实现

在这里插入图片描述

  • new的本质,实际上就是malloc+构造函数
  • delete的本质就是析构函数+free
    在这里插入图片描述

源码

#include <iostream>
#include <string>using namespace std;class Person
{public:Person() {age = 0;name = "";};~Person() {};virtual void setName(string name) = 0;virtual void setAge(int age) = 0;
protected:int age;string name;};class Student :public Person {public:Student() {age = 17;}void setName(string name) {this->name = name;}string getName() {return this->name;}void setAge(int age) {if (age > 30 || age < 6) {cout << "not suitable for school!" << endl;return;}this->age = age;}int getAge() {return this->age;}
};int main() {Student* stu = new Student();stu->setName("Link");stu->setAge(18);cout << stu->getName() << " with age " << stu->getAge() << endl;return 0;
}

IDA反编译

在这里插入图片描述
子类构造函数
在这里插入图片描述
父类构造函数
在这里插入图片描述

子类虚表和父类虚表

在这里插入图片描述
纯虚函数的抽象类的虚表由__cxa_pure_virtual填充,有几个纯虚函数就有几个__cxa_pure_virtual,student类虚表分别有各自实现的虚函数,虚表上面是该类的typeinfo的地址
在这里插入图片描述

  • RTTI (Run-Time Type Information) 是C++的一项特性,允许程序在运行时识别对象的类型。
  • typeid运算符和dynamic_cast都是基于RTTI实现的。
  • 每个包含虚函数的类实例,在内存中都有一个隐藏的指针(称为vptr,虚函数指针),指向该类的虚函数表(vtable)。这个vptr是在对象创建时由编译器自动初始化的。
  • RTTI信息通常与vtable一起管理,其中可能包括类型描述信息和继承链信息等。
  1. Aclass* ptra = new Bclass;:这行代码创建了一个指向Bclass实例的指针,但这个指针被声明为Aclass*类型。因为BclassAclass的子类(假设如此),所以这是向上转型,是多态的基础。

  2. int ** ptrvf = (int**)(ptra);:这里进行了一次不安全的类型转换,将Aclass指针转换为了int**。这种转换通常是为了直接访问虚函数指针(vptr),因为在许多系统上,vptr是对象内存布局的第一个元素,可以被视为一个指针的指针。但是,请注意,这种做法非常危险且非标准,违反了类型安全原则。

  3. *((int*)ptrvf[0]-1):这一部分是为了找到RTTI信息的位置。ptrvf[0]访问的是第一个虚函数(按指针算起),减1则是尝试访问vptr前的一个位置,期望那里存放着RTTI相关数据的指针。这一步同样非常危险,依赖于特定编译器和平台的实现细节。

  4. *((RTTICompleteObjectLocator*)(...)):这里进一步将找到的地址强制转换为RTTICompleteObjectLocator指针,并解引用它。RTTICompleteObjectLocator是一个内部使用的结构(非标准公开接口),用于存储有关对象类型的完整信息,比如类的类型描述符、偏移量到类型名称字符串等。

调用函数

在这里插入图片描述
对于虚函数

  1. 先通过对象开始八个字节得到虚表地址
  2. 通过虚表地址和相关偏移得到函数地址
  3. 调用函数
    对于非虚函数
  4. 直接调用再text段实现的函数

菱形继承

#include<stdio.h>
#include<stdlib.h>//间接基类
class A {
public:virtual void function() {printf("A virtual function\n");}int a;
};//直接基类
class B :virtual public A { //虚继承
public:virtual void func() {printf("B virtual func()\n");}int b;
};//直接基类
class C :virtual public A { //虚继承
public:virtual void func() {printf("C virtual func()");}int c;
};//派生类
class D :public B, public C {
public:virtual void function() {printf("D virtual function()");}int d;
};int main(int argc, char** argv) {A* A_ptr = (A*)new D();A_ptr->function();return 0;
}

B和C继承A,D继承B和C

在这里插入图片描述通过虚表地址减去24后的位置的内容是32,然后再加上起始地址,对应到的V4为D内的A的对象内存位置,offset vbase应该是与虚基类的偏移也就是和A的偏移
在这里插入图片描述
在这里插入图片描述
这里给各个父类对象在本对象的空间的前八个字节赋值时,用的是本对象虚表对应到的不同父类的虚函数的地址
在这里插入图片描述

此时对应的虚表地址,所以**两次得到D::function的地址,然后参数为对象自己
在这里插入图片描述

相关文章:

C++的类和new和delete和菱形继承机制

文章目录 参考虚函数使用虚函数的class结构相关实现源码IDA反编译子类虚表和父类虚表调用函数菱形继承 参考 https://showlinkroom.me/2017/08/21/C-%E9%80%86%E5%90%91%E5%88%86%E6%9E%90/ https://www.cnblogs.com/bonelee/p/17299985.html https://xz.aliyun.com/t/5242?t…...

Redis教程(二十二):Redis的过期删除和缓存淘汰策略

传送门:Redis教程汇总篇,让你从入门到精通 一、过期删除策略 Redis 中的过期删除策略是与 Redis 管理键的生命周期相关的一系列操作,用于删除过期的Key以释放内存。Redis 提供了三种主要的过期删除策略: 1、惰性删除(Lazy Expiration) 工作原理:当客户端尝试访问一个…...

Lodop 实现局域网打印

文章目录 前言一、Lodop支持打印的方式lodop 打印方式一般有3种&#xff1a;本地打印局域网集中打印广域网AO打印 二、集成步骤查看lodop 插件的服务端口&#xff1a;查看ip后端提供接口返回ip&#xff0c;前端动态获取最后步骤 前言 有时候会根据不同的ip来获取资源文件&…...

HarmonyOS(二十四)——Harmonyos通用事件之触摸事件

1.触摸事件。 触摸事件是HarmonyOS通用事件的一种事件之一&#xff0c;当手指在组件上按下、滑动、抬起时触发。 名称是否冒泡功能描述onTouch(event: (event?: TouchEvent) > void)是手指触摸动作触发该回调&#xff0c;event返回值见下面TouchEvent介绍。 2. TouchEve…...

2024-前端面试的正确打开方式(GitHub火爆场景题剖析)

写在前面 最近前端面试大家有没有感觉到场景题的压迫感&#xff01;&#xff01;&#xff01; 很显然普通面试八股不会怎么更新&#xff0c;而且就前端来说&#xff0c;面试并不是真正困难的&#xff0c;常规八股显示不出面试者的技术水平。 前端作为一个技术行业&#xff0c…...

Vue3项目炫酷实战,检测密码强度值

在前端项目开发中&#xff0c;确保用户密码的强度是保护账户安全的重要措施。本文将演示如何使用Vue 3实现一个简单的密码强度检测功能。通过实时反馈&#xff0c;帮助用户创建更安全的密码&#xff0c;从而提升整体系统的安全性。无论您是前端开发新手还是经验丰富的开发者&am…...

PHP实现抖音小程序用户登录获取openid

目录 第一步、抖音小程序前端使用tt.login获取code 第二步、前端拿到code传给后端 第三步、方法1 后端获取用户信息 第四步、方法2 抖音小程序拿到用户信息把用户信息传给后端 code2Session抖音小程序用户登录后端文档 第一步、抖音小程序前端使用tt.login获取code 前端 …...

Linux进程无法被kill

说明&#xff1a;记录一次应用进程无法被kill的错误&#xff1b; 场景 在一次导出MySQL数据时&#xff0c;使用下面的命令&#xff0c;将数据库数据导出为.sql文件&#xff0c;数据量大&#xff0c;导出时间长&#xff0c;于是我就将服务器重启了。 mysqldump -u username -…...

MySQL binlog三种模式

1.statement statement 记录的是sql语句。比如一条sql&#xff0c;update table_user set age 20 where id between 1 and 100。这条sql会更新100条数据&#xff0c;但是statement 模式下只会记录这条sql语句。 优点&#xff1a;不需要记录数据的变化&#xff0c;减少了bin …...

【CentOS 7】挑战探索:在CentOS 7上实现Python 3.9的完美部署指南

【CentOS 7】挑战探索&#xff1a;在CentOS 7上实现Python 3.9的完美部署指南 大家好 我是寸铁&#x1f44a; 总结了一篇【CentOS 7】挑战探索&#xff1a;在CentOS 7上实现Python 3.9的完美部署指南详细步骤✨ 喜欢的小伙伴可以点点关注 &#x1f49d; 前言 此篇教程只适用于p…...

oracle删除表空间和用户命令

创建表空间和用户可参考 ORACLE创建表空间,用户,修改密码,分配权限,以及导入导出_oracle表空间的密码-CSDN博客 1.删除表空间 --删除空的表空间&#xff0c;但是不包含物理文件 drop tablespace tablespace_name; --删除非空表空间&#xff0c;但是不包含物理文件 drop tabl…...

企业微信hook接口协议,ipad协议http,获取未发送群发列表

获取未发送群发列表 参数名必选类型说明uuid是String每个实例的唯一标识&#xff0c;根据uuid操作具体企业微信 请求示例 {"uuid":"1753cdff-0501-42fe-bb5a-2a4b9629f7fb" } 返回示例 {"data": {"listdata": [{"now_cnt&qu…...

oracle中的INTERVAL函数学习总结

Oracle 从9i数据库开始引入了一种新特性&#xff0c;可以用来存储时间间隔&#xff0c;出现了INTERVAL 函数。这个函数的表达式比较多&#xff0c;初学比较费劲不好掌握&#xff0c;经过以几个小时的查阅资料和实验&#xff0c;总结如下&#xff1a; interval year t…...

爬虫(没)入门:用 node-crawler 爬取 blog

起因 前几天想给一个项目加 eslint&#xff0c;记得自己曾经在博客里写过相关内容&#xff0c;所以来搜索。但是发现 csdn 的只能按标题&#xff0c;没办法搜正文&#xff0c;所以我没搜到自己想要的内容。 没办法只能自己又重新折腾了一通 eslint&#xff0c;很烦躁。迁怒于…...

GAMES104笔记

GAMES104 文章目录 GAMES10401.从入门到实践什么是游戏引擎学习顺序 02.引擎架构分层资源层功能层核心层平台层工具层总结 03.如何构建游戏世界其它需要管理的复杂情况 04.游戏引擎中的渲染实践Rendering游戏引擎中的绘制知识点&#xff08;结合实际进化而来&#xff09;渲染基…...

ARM功耗管理架构演进及变迁

安全之安全(security)博客目录导读 目录 一、功耗管理架构演进及变迁概述 二、多核 三、big.LITTLE 四、DynamIQ...

ARM-V9 RME(Realm Management Extension)系统架构之系统能力的设备隔离和保护

安全之安全(security)博客目录导读 目录 三、设备隔离和保护 1、外设隔离 2、非pe请求者(设备)...

如何为律师制作专业的商务名片?含电子名片二维码

律师关注细节&#xff0c;律师名片也不例外。它们不仅仅是身份的象征&#xff0c;更是律师专业形象的代表&#xff0c;传递专业知识和信任。今天就来和我们一起来看看制作律师商务名片的注意事项&#xff0c;以及如何制作商务名片上的电子名片二维码&#xff1f; 一、名片的主…...

方案设计|汽车轮胎数显胎压计方案

一、引言 数显轮胎胎压计是一个专门测量车辆轮胎气压的工具&#xff0c;它具有高精度测量的功能&#xff0c;能够帮助快速准确获取轮胎气压正确数值&#xff0c;保证轮胎使用安全。本文将对数显轮胎胎压计的方案技术进行分析&#xff0c;包括其基本原理、硬件构成、软件设计等方…...

MySQL学习——选项文件的使用

MySQL 的许多程序都可以从选项文件&#xff08;有时也被称为配置文件&#xff09;中读取启动选项。选项文件提供了一种方便的方式来指定常用的选项&#xff0c;这样你就不必每次运行程序时都在命令行上输入这些选项。 要确定一个程序是否读取选项文件&#xff0c;你可以使用 -…...

Vulnhub-DC-3

joomla3.7.0的提权 信息收集 靶机IP:192.168.20.136 kaliIP:192.168.20.128 网络有问题的可以看下搭建Vulnhub靶机网络问题(获取不到IP) 首先nmap扫端口和版本&#xff0c;dirsearch跑下目录&#xff0c;wappalyzer也可以用下 发现服务器用的ubuntu&#xff0c;JoomlaCMS…...

docker 停止重启容器命令start/stop/restart详解(容器生命周期管理教程-2)

Docker 提供了多个命令来管理容器的生命周期&#xff0c; 其中start、stop 和 restart。这些命令允许用户控制容器的运行状态。 1. docker start 命令格式&#xff1a; docker start [OPTIONS] CONTAINER [CONTAINER...]功能&#xff1a; 启动一个或多个已经停止的 Docker …...

lua字符串模式匹配

string.gmatch()不支持匹配首字符 string.gmatch(s, pattern)中&#xff0c;如果s的开头是’^字符&#xff0c;不会被当成首字符标志&#xff0c;而是被当成一个普通字符。 比如 s"hello world from lua" for w in string.gmatch(s, "^%a") doprint(w) e…...

【深度学习】温故而知新4-手写体识别-多层感知机+CNN网络-完整代码-可运行

多层感知机版本 import torch import torch.nn as nn import numpy as np import torch.utils from torch.utils.data import DataLoader, Dataset import torchvision from torchvision import transforms import matplotlib.pyplot as plt import matplotlib import os # 前…...

ChatGPT 论文翻译指南!解锁高质量翻译的秘密!

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …...

SQLserver通过CLR调用TCP接口

一、SQLserver启用CLR 查看是否开启CRL&#xff0c;如果run_value1&#xff0c;则表示开启 EXEC sp_configure clr enabled; GO RECONFIGURE; GO如果未启用&#xff0c;则执行如下命令启用CLR sp_configure clr enabled, 1; GO RECONFIGURE; GO二、创建 CLR 程序集 创建新项…...

前复权、后复权,技术分析看哪个?价值投资呢?

先说结论&#xff0c; 前复权可以实现技术指标的连续性&#xff0c;适合技术分析&#xff0c; 后复权可以实现股价走势的连续性&#xff0c;适合价值投资者 ​ 从头来说&#xff0c;一家公司盈利后&#xff0c;可以选择用盈利购买新的生产设备或者拓展生产&#xff0c;但是…...

Python正则表达式:深度解析URL匹配与操作

Python正则表达式&#xff1a;深度解析URL匹配与操作 在Python编程中&#xff0c;正则表达式&#xff08;Regular Expression&#xff0c;简称regex或regexp&#xff09;是一种强大的文本处理工具&#xff0c;它可以帮助我们快速匹配、查找、替换复杂的文本模式。在处理URL&am…...

[C][数据结构][顺序表]详细讲解+实现

目录 1.线性表2.顺序表 - SeqList3.实现4.顺序表缺点 1.线性表 线性表(linear list)是n个具有相同特性的数据元素的有限序列线性表是一种在实际中广泛使用的数据结构&#xff0c;常见的线性表&#xff1a;顺序表、链表、栈、队列、字符串…线性表在逻辑上是线性结构&#xff0…...

vscode运行Java utf-8文件中文乱码报错

问题现象 vscode 运行utf-8 java文,爆出如下错误 hello.java:5: &#xfffd;&#xfffd;&#xfffd;&#xfffd;: &#xfffd;&#xfffd;&#xfffd;&#xfffd;GBK&#xfffd;IJ&#xfffd;&#xfffd;&#xfffd;ӳ&#xfffd;&#xfffd;&#xfffd;ַ&a…...