多重继承中使用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操作符时谁调用类的析构函数 的相关文章

随机推荐

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

    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 关键字知之甚少 如代码示例中所示 在继承的情况下 当使用指向在堆上创建的派生类对象的基类指针和删除运算符来释放内存时 将仅按