多重继承中使用delete操作符时谁调用类的析构函数

2024-05-05

这个问题听起来可能太愚蠢了,但是,我在其他地方找不到具体的答案。

对后期绑定如何工作以及继承中使用的 virtual 关键字知之甚少。

如代码示例中所示,在继承的情况下,当使用指向在堆上创建的派生类对象的基类指针和删除运算符来释放内存时,将仅按顺序调用派生类和基类的析构函数当基析构函数被声明为虚函数时。

现在我的问题是:

1)当base的析构函数不是virtual时,为什么只有在使用“delete”运算符的情况下才会出现未调用派生dtor的问题,为什么在下面给出的情况下不会出现:


derived drvd;
base *bPtr;
bPtr = &drvd; //DTOR called in proper order when goes out of scope.

2)当使用“删除”运算符时,谁负责调用类的析构函数?删除运算符将有一个调用 DTOR 的实现?或者编译器写了一些额外的东西?如果操作员有实现,那么它看起来怎么样,[我需要示例代码如何实现]。

3)如果本例中使用了virtual关键字,那么operator delete现在如何知道要调用哪个DTOR?

从根本上来说,我想知道当使用删除时谁调用了类的故事。

<h1> Sample Code </h1>

class base
{
    public:
    base(){
       cout<<"Base CTOR called"<<endl;
    }

    virtual ~base(){  
       cout<<"Base DTOR called"<<endl;
    }
};

class derived:public base
{
    public:
        derived(){
            cout<<"Derived CTOR called"<<endl;
        }

    ~derived(){
            cout<<"Derived DTOR called"<<endl;
     }
};

我不确定这是不是重复的,我在搜索中找不到。

int main() { 基 *bPtr = 新派生();


delete bPtr;// only when you explicitly try to delete an object
return 0;
  

  1. 这是因为在这种情况下,编译器知道有关要破坏的对象的所有信息,在这种情况下是drvd并且是类型derived. When drvd超出范围编译器插入代码来调用其析构函数

  2. delete是编译器的关键字。当编译器看到删除时,它会插入调用析构函数的代码和要调用的代码operator delete释放内存。请记住keyword delete and operater delete是不同的。

  3. 当编译器看到keyword delete用于指针时,它需要生成代码才能正确销毁。为此,它需要知道指针的类型信息。编译器对指针唯一了解的是指针类型,而不是指针所指向的对象的类型。指针所指向的对象可以是基类或派生类。在某些情况下,对象的类型可能非常明确地定义,例如

void fun()
{
    Base *base= new Derived(); 
    delete base;
}

但大多数情况并非如此,比如这个

void deallocate(Base *base)
{
    delete base;
}

因此编译器不知道调用基类或派生类的哪个析构函数。这就是它的工作方式

  1. 如果基类没有虚函数(成员函数或析构函数)。直接插入调用基类析构函数的代码
  2. If the Base class has virtual functions, then the compiler takes the information of destructer from vtable.
    1. 如果析构函数不是虚拟的。 vtable 将具有基析构函数的地址,这就是将要调用的内容。这是不对的,因为这里没有调用正确的析构函数。这就是为什么总是建议将基类的析构函数声明为 virtual
    2. 如果析构函数是虚拟的,则 vtable 将具有析构函数的正确地址,并且编译器将在那里插入正确的代码
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

多重继承中使用delete操作符时谁调用类的析构函数 的相关文章

  • 检查两个数是否是彼此的排列?

    给定两个数字 a b 使得 1 例如 123 是 312 的有效排列 我也不想对数字中的数字进行排序 如果您指的是数字的字符 例如 1927 和 9721 则 至少 有几种方法 如果允许排序 一种方法是简单地sprintf将它们放入两个缓冲
  • C# 和 Javascript SHA256 哈希的代码示例

    我有一个在服务器端运行的 C 算法 它对 Base64 编码的字符串进行哈希处理 byte salt Convert FromBase64String serverSalt Step 1 SHA256Managed sha256 new S
  • 如何使用GDB修改内存内容?

    我知道我们可以使用几个命令来访问和读取内存 例如 print p x 但是如何更改任何特定位置的内存内容 在 GDB 中调试时 最简单的是设置程序变量 参见GDB 分配 http sourceware org gdb current onl
  • 如何避免情绪低落?

    我有一个实现状态模式每个状态处理从事件队列获取的事件 根据State因此类有一个纯虚方法void handleEvent const Event 事件继承基础Event类 但每个事件都包含其可以是不同类型的数据 例如 int string
  • 指针问题(仅在发布版本中)

    不确定如何描述这一点 但我在这里 由于某种原因 当尝试创建我的游戏的发布版本进行测试时 它的敌人创建方面不起作用 Enemies e level1 3 e level1 0 Enemies sdlLib 500 2 3 128 250 32
  • 获取没有非标准端口的原始 url (C#)

    第一个问题 环境 MVC C AppHarbor Problem 我正在调用 openid 提供商 并根据域生成绝对回调 url 在我的本地机器上 如果我点击的话 效果很好http localhost 12345 login Request
  • C#:如何防止主窗体过早显示

    在我的 main 方法中 我像往常一样启动主窗体 Application EnableVisualStyles Application SetCompatibleTextRenderingDefault false Application
  • 将目录压缩为单个文件的方法有哪些

    不知道怎么问 所以我会解释一下情况 我需要存储一些压缩文件 最初的想法是创建一个文件夹并存储所需数量的压缩文件 并创建一个文件来保存有关每个压缩文件的数据 但是 我不被允许创建许多文件 只能有一个 我决定创建一个压缩文件 其中包含有关进一步
  • Json.NET - 反序列化接口属性引发错误“类型是接口或抽象类,无法实例化”

    我有一个类 其属性是接口 public class Foo public int Number get set public ISomething Thing get set 尝试反序列化Foo使用 Json NET 的类给我一条错误消息
  • 指针减法混乱

    当我们从另一个指针中减去一个指针时 差值不等于它们相距多少字节 而是等于它们相距多少个整数 如果指向整数 为什么这样 这个想法是你指向内存块 06 07 08 09 10 11 mem 18 24 17 53 7 14 data 如果你有i
  • 如何返回 json 结果并将 unicode 字符转义为 \u1234

    我正在实现一个返回 json 结果的方法 例如 public JsonResult MethodName Guid key var result ApiHelper GetData key Data is stored in db as v
  • 如何在 VBA 中声明接受 XlfOper (LPXLOPER) 类型参数的函数?

    我在之前的回答里发现了问题 https stackoverflow com q 19325258 159684一种无需注册即可调用 C xll 中定义的函数的方法 我之前使用 XLW 提供的注册基础结构 并且使用 XlfOper 类型在 V
  • 实体框架 4 DB 优先依赖注入?

    我更喜欢创建自己的数据库 设置索引 唯一约束等 使用 edmx 实体框架设计器 从数据库生成域模型是轻而易举的事 现在我有兴趣使用依赖注入来设置一些存储库 我查看了 StackOverflow 上的一些文章和帖子 似乎重点关注代码优先方法
  • C++ 复制初始化和直接初始化,奇怪的情况

    在继续阅读本文之前 请阅读在 C 中 复制初始化和直接初始化之间有区别吗 https stackoverflow com questions 1051379 is there a difference in c between copy i
  • C - 直接从键盘缓冲区读取

    这是C语言中的一个问题 如何直接读取键盘缓冲区中的数据 我想直接访问数据并将其存储在变量中 变量应该是什么数据类型 我需要它用于我们研究所目前正在开发的操作系统 它被称为 ICS OS 我不太清楚具体细节 它在 x86 32 位机器上运行
  • 为什么 C# Math.Ceiling 向下舍入?

    我今天过得很艰难 但有些事情不太对劲 在我的 C 代码中 我有这样的内容 Math Ceiling decimal this TotalRecordCount this PageSize Where int TotalRecordCount
  • Validation.ErrorTemplate 的 Wpf 动态资源查找

    在我的 App xaml 中 我定义了一个资源Validation ErrorTemplate 这取决于动态BorderBrush资源 我打算定义独特的BorderBrush在我拥有的每个窗口以及窗口内的不同块内
  • mysql-connector-c++ - “get_driver_instance”不是“sql::mysql”的成员

    我是 C 的初学者 我认为学习的唯一方法就是接触一些代码 我正在尝试构建一个连接到 mysql 数据库的程序 我在 Linux 上使用 g 没有想法 我运行 make 这是我的错误 hello cpp 38 error get driver
  • 如何使用 std::string 将所有出现的一个字符替换为两个字符?

    有没有一种简单的方法来替换所有出现的 in a std string with 转义 a 中的所有斜杠std string 完成此操作的最简单方法可能是boost字符串算法库 http www boost org doc libs 1 46
  • ASP.NET MVC 6 (ASP.NET 5) 中的 Application_PreSendRequestHeaders 和 Application_BeginRequest

    如何在 ASP NET 5 MVC6 中使用这些方法 在 MVC5 中 我在 Global asax 中使用了它 现在呢 也许是入门班 protected void Application PreSendRequestHeaders obj

随机推荐

  • 将数组写入文件的最佳方法? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我想避免写入数据库并使用常量 数组作为 lang 文件等 i e lang array hello gt hello world 并能够从后台编
  • 数据库镜像/Postgres流复制

    我不是 DBA 我是基于企业数据库的应用程序的主要开发人员 我目前正在指定一些新机器来升级我们现有的企业数据库 目前 我们在 DR 站点上运行带有数据库的 Postgres 8 4 该数据库通过前员工执行的一些自定义 rsync 工作定期接
  • 在 Vim 中的缩进线上按“Home”

    我有一个坏习惯 就是使用 home 键返回到行首 当我最近开始使用 vim 时 我注意到当我在缩进的行上按 home 键时 它会让我回到该行的开头 在 Notepad 我曾经使用的编辑器 中 它会让我返回到该行代码的开头 就在缩进之后 有没
  • 使用 jqGrid 的 ASP.NET MVC 路由

    我正在尝试创建一个指向 url 的链接 例如首页 详情 1在 jqGrid 列中 文档显示 showlink baseLinkUrl showAction show addParam key 2 注意 addParam 应该包含 例如 格式
  • 如何使事件 DOM 侦听器适应 Google Maps JavaScript API v3.35

    我曾经使用以下代码来捕获用户的 Enter 键事件 如果用户没有选择其中任何一个 即没有标记为 pac 的 pac item 则自动从自动完成结果 pac items 中选择第一个结果 项目选择 var input document get
  • 如何告诉 Xcode 我的 info.plist 和 .pch 文件在哪里

    我重命名了我的项目及其文件 现在 Xcode 仍在寻找旧的 info plist 文件 在哪里设置所需的 plist 和 pch 文件的位置 在我的 项目信息 窗口中 打包 下有一个 Info Plist 文件项 但它是空白的 当我尝试不同
  • MySQL - 插入后更新同一个表的触发器

    这就是我想做的 当有新的INSERT到表中ACCOUNTS 我需要更新行ACCOUNTS where pk NEW edit on通过设置status E 表示特定 旧 帐户已被编辑 DELIMITER DROP TRIGGER IF EX
  • 以编程方式添加 TabBarController

    我想以编程方式制作标签栏控制器和导航控制器 到目前为止 我的代码有效 它在底部显示了一个选项卡栏 但 OptionViewController 在第二个选项卡栏的按钮上没有说任何内容 没有标题 有趣的是 当我单击没有任何内容的按钮时 标题出
  • 使用 JNA 列出所有导出的符号名称

    如何使用 JNA 列出给定 dll 中的所有可用函数名称 JNA 允许您在运行时调用这些函数 要查看可用的内容 请使用适合该工作的工具 在 Windows 上 您有 转储箱 出口 http msdn microsoft com en us
  • R 将 data.frame 转换为 json

    我正在尝试将 data frame 转换为 json 格式 我的 data frame 具有以下结构 a lt rep c Mario Luigi each 3 b lt sample 34 57 size length a df lt d
  • jinja2.exceptions.TemplateNotFound:index.html

    我尝试使用 Flask 打开 index html run py from app import app app run debug True init py from flask import Flask app Flask name f
  • Graphviz:除了标签之外,还在节点上添加标题

    在我的 Graphviz 图中 用 DOT 编写 我希望每个节点都有一个标签 但除此之外 我还希望某些节点有一个小标题 表示该节点的一些其他唯一值 例如 如果这是一个历史图 则节点的标签可能类似于 乔治 华盛顿的诞生 标题可能为 另请参阅
  • 如何在多个端口上运行 FastAPI 应用程序?

    我有一个 FastAPI 应用程序 正在使用 Uvicorn 以编程方式在端口 30000 上运行 现在我也想在端口 8443 上运行相同的应用程序 相同的应用程序需要在这两个端口上运行 我怎样才能在Python代码中做到这一点 最小可重现
  • 如何使用链接本地 IPv6 地址访问 Web 服务器或网站?

    以下是托管 Web 服务器的计算机的 ipconfig 输出 以太网适配器本地连接 连接特定的 DNS 后缀 链路本地 IPv6 地址 fe80 f85b 4256 ee76 24a4 11 IPv4 地址 10 213 254 119 子
  • 为什么我不能执行 fmt.Sprintf("%d.%d.%d.%d", a...)?

    我正在学习 Go 但我一直坚持 Go 之旅 exercise stringer go https tour golang org methods 7 https tour golang org methods 7 这是一些代码 type I
  • 某些事务传播不适用于 Spring/Hibernate 4

    我正在将应用程序从 3 3 升级到 Hibernate 4 2 我们还使用 Spring 3 1 3 目前我们不能 不会更新 我的一些单元测试现在失败了 org hibernate HibernateException No Session
  • 如何简化 Swift Enum 自定义 init

    我创建了一个带有字符串类型的枚举 它有两个 init 方法 一种是使用 rawValue 的默认 init 方法 另一种是使用 intValue 的自定义 init 方法 我是这样写的 有没有什么简单的方法可以不使用两个开关盒 enum R
  • 如何在 VC++ 项目中引用 DLL

    我有一个正在尝试编译的 C 驱动程序 它的代码中有这一行 import msado15 dll no namespace rename EOF EndOfFile 但是当我编译项目时 出现错误 错误1致命错误C1083 无法打开类型库文件
  • 如何设置 TeamCity NuGet 安装程序的 MSBuild 版本?

    我正在尝试使用以下命令恢复 NET Core 解决方案的 NuGet 包NuGet 安装程序 https confluence jetbrains com display TCD10 NuGet InstallerTeamCity 构建步骤
  • 多重继承中使用delete操作符时谁调用类的析构函数

    这个问题听起来可能太愚蠢了 但是 我在其他地方找不到具体的答案 对后期绑定如何工作以及继承中使用的 virtual 关键字知之甚少 如代码示例中所示 在继承的情况下 当使用指向在堆上创建的派生类对象的基类指针和删除运算符来释放内存时 将仅按