使用 gcc 调用纯虚函数时出现链接器错误

2023-11-23

我和一个朋友对对象的构造进行了一次非常有趣的讨论,最终得到了这段代码:

#include <iostream>

class Parent {
  public:
    Parent( ) {
      this->doSomething( );
    }

    virtual void doSomething( ) = 0;
};

class Child : public Parent {
    int param;

  public:
    Child( ) {
      param = 1000;
    }

    virtual void doSomething( ) {
      std::cout << "doSomething( " << param << " )" << std::endl;
    }
};

int main( void ) {
    Child c;
    return 0;
}

我知道标准没有定义从构造函数或析构函数调用纯虚函数时的行为,这也不是我如何在生产中编写代码的实际示例,它只是检查编译器做什么的测试。

在 Java 打印中测试相同的构造

做某事(0)

这是有道理的,因为param此时尚未初始化doSomething()从父构造函数调用。

我期望 C++ 中有类似的行为,区别在于param包含调用函数时的任何内容。

相反,编译上面的代码会导致链接器错误(c++ (Ubuntu 4.4.3-4ubuntu5.1) 4.4.3)说的是参考Parent::doSomething( )未定义。

所以,我的问题是:为什么这是链接器错误?如果这是一个错误,我希望编译器会抱怨,特别是因为有该函数的实现。 任何有关链接器在这种情况下如何工作的见解或对进一步阅读的参考都将受到高度赞赏。

先感谢您!我希望这个问题不是重复的,但我找不到类似的问题..


所以,我的问题是:为什么这是链接器错误?如果这是一个错误,我希望编译器会抱怨,特别是因为有该函数的实现。任何有关链接器在这种情况下如何工作的见解或对进一步阅读的参考都将受到高度赞赏。

让我们进一步扩展一下。

为什么是链接器错误?

因为编译器注入了一个调用Parent::doSomething()来自构造函数,但链接器发现没有该函数的定义。

我希望编译器会抱怨,特别是因为有该函数的实现。

这是不正确的。有一个override对于可以通过虚拟调度访问的函数,但是该函数Parent::doSomething()没有定义。这里有一个微妙但重要的区别,可以通过禁用动态调度以不同的方式进行测试。您可以通过使用类名限定函数来禁用特定调用的动态调度,例如,Child::doSomething()如果你添加Parent::doSomething(),这将生成一个调用Parent::doSomething()不使用动态调度来调用最终的重写器。

为什么这很重要?

这很重要,因为即使函数是纯虚拟(纯虚拟意味着动态调度永远不会调度到特定的重载),它也可以是defined and called:

struct base {
   virtual void f() = 0;
};
inline void base::f() { std::cout << "base\n"; }
struct derived : base {
   virtual void f() {
      base::f();
      std::cout << "derived\n";
   }
};
int main() {
   derived d;
   d.f();        // outputs: base derived
}

现在,C++ 有一个单独的编译模型,这意味着不需要在这个特定的翻译单元中定义函数。那是Parent::doSomething()可以在链接到同一程序的不同翻译单元中定义。编译器不可能知道任何其他 TU 是否会定义该函数,只有链接器知道,因此是链接器抱怨的。

任何有关链接器在这种情况下如何工作的见解或对进一步阅读的参考都将受到高度赞赏。

如前所述,编译器(这个特定的编译器)正在添加对特定覆盖的调用Parent等级。与所有其他函数调用一样,链接器试图查找任何翻译单元中定义的符号,但失败,从而触发错误。

The 纯虚拟说明符的唯一目的是避免隐式使用 (odr-use在标准中)创建虚拟表时的函数。也就是说,纯说明符的唯一目的不是向虚拟表添加对该符号的依赖关系。这反过来意味着链接器不需要符号的存在(Parent::doSomething)在程序中用于动态调度(vtable),但如果程序显式使用它,它仍然需要该符号。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 gcc 调用纯虚函数时出现链接器错误 的相关文章

随机推荐

  • Twig模板不能包含php模板

    我遇到了一个问题 这对我来说相当不清楚且难以理解 我尝试制作日历小部件 它应该显示在我网站的每个页面上 所以 我认为它应该是平均模板 没有参数 不是每个网站 我尝试将其作为树枝模板 我设法渲染日历 但在获取日期对象时遇到问题 这是获取渲染日
  • Active Directory 用户组成员身份 GroupPrincipal

    我正在尝试使用GroupPrincipal 的一部分System DirectoryServices AccountManagement名称空间 来填充字符串类型的列表 以便我可以检查用户是否是 Active Directory 组的成员
  • python passlib:“轮次”的最佳值是多少

    来自passlib 文档 对于大多数面向公众的服务 通常可以让登录时间长达 250 毫秒 400 毫秒 然后用户就会开始感到厌烦 那么什么是最有价值的rounds in a 登录 注册如果我们认为有一次调用数据库对于登录尝试 它使用Mong
  • 如何使用 printf 打印非空终止字符串?

    假设我在运行时知道字符串的长度 如何使用 printf 打印非空终止字符串 printf s length string 与其他参数一起使用 printf integer d string s number f integer length
  • GNU Autotools:无需版本信息即可重建

    我需要构建一个配置有自动工具的库 通常configure make make install步骤生成版本化共享库 例如libfoo so x x是否可以修改configure ac或Makefile am 当然还有autoreconf 以便
  • C# 游戏网络库

    我正在使用 Net v2 开发在线策略游戏 虽然游戏主要是战略性的 但它确实有一些需要合理网络性能的战术元素 我计划对战略数据使用 TCP 数据包 对战术数据使用 UDP 数据包 编辑 我忘了提及 出于几个原因 我正在放弃 WCF 和 NE
  • Kafka - 反序列化消费者中的对象

    我们正在考虑在我们的消息传递中使用 Kafka 并且我们的应用程序是使用 Spring 开发的 所以 我们打算使用spring kafka 生产者将消息作为 HashMap 对象放入队列中 我们有 JSON 序列化器 并且假设映射将被序列化
  • 如何用reactjs合并两个对象数组?

    我有一个反应大日历 我想从后端获取本周的事件 从本地存储获取其他几周的事件 我的代码是 componentDidMount fetch url then Response gt Response json then data gt let
  • 将列名转换为第一行

    我想将以下数据框转换为 json df A sector B sector C sector TTM Ratio 35 99 12 70 20 63 14 75 23 06 RRM Sales 114 57 1 51 5 02 1 00 4
  • 使用 Java 8 lambda 表达式过滤列表

    我有一个Project class class Project List
  • java中x++和++x有区别吗?

    java中 x和x 有区别吗 x 称为前增量 而 x 称为后增量 int x 5 y 5 System out println x outputs 6 System out println x outputs 6 System out pr
  • 如何在ios应用程序中将自定义字体系列设置为系统字体[重复]

    这个问题在这里已经有答案了 我正在开发一个 ios 应用程序 其中我必须为 UI 使用自定义字体 我知道如何在应用程序中集成新的自定义字体 为此我有 下载扩展名为 ttf 的字体系列文件 将它们添加到资源包中 在 info plist 文件
  • Qemu Freescale i.MX6 DualLite SABRE:根文件系统未挂载

    目标 模拟 Qemu 特别支持的 sabrelite Freescale i MX6 Quad SABRE Lite Board Cortex A9 执行 qemu system arm M 它显示 Qemu 版本 2 10 1 主机 fe
  • Visual Studio 中(基于字符的)STL(流)容器的编译错误

    这基本上是同一个问题 SO C2491 std numpunct id 不允许定义dllimport静态数据成员 关闭 但考虑以下事实 在我看来 这是一个完全有效的问题 根据 SO 如何创建一个最小的 完整的 可验证的示例 真不知道为什么有
  • 在 Windows 上编写轻量级 GUI 程序的最快途径是什么?

    我想要一个小型 此可执行文件必须在 x86 64 架构以及 Itanium 芯片上的 32 位和 64 位 Windows XP Vista Server 2003 和 Server 2008 版本上运行 如果我们只需要构建一次就可以在所有
  • 将 IsAssignableFrom 与“开放”泛型类型一起使用

    使用反射 我试图找到从给定基类继承的类型集 没花很长时间就搞清楚了简单类型 但当涉及到泛型时我就被难住了 对于这段代码 第一个 IsAssignableFrom 返回 true 但第二个返回 false 然而 最终的作业编译得很好 clas
  • ACTION_INSTALL_PACKAGE

    我的应用程序正在尝试安装 APK Intent installIntent new Intent Intent ACTION INSTALL PACKAGE installIntent setData Uri fromFile new Fi
  • 使用 Promises 的类型“{}”上不存在属性

    我正在访问从已解决的承诺返回的对象的属性 return new Promise resolve gt Get result resolve result then r gt console log r id Typescript 编译代码并
  • 解析请求URL时如何获取URL标签?

    URL 可以有一个标签 用 符号分隔 位于 URL 参数之后 例如 http example com foo bar jsp p1 v1 test label 我希望标签成为 request getQueryString 的一部分和 req
  • 使用 gcc 调用纯虚函数时出现链接器错误

    我和一个朋友对对象的构造进行了一次非常有趣的讨论 最终得到了这段代码 include