c++ - 来自 Base Ctor 的纯虚函数调用

标签 c++ constructor linker-errors runtime-error pure-virtual

考虑以下示例代码:

#include <iostream>

using namespace std;

class base
{
   public:
      base()
      {
         bar(); //Line1
         this->bar(); //Line2
         base *bptr = this; 
         bptr->bar(); //Line3
         ((base*)(this))->bar(); //Line4
      }

      virtual void bar() = 0;
};

class derived: base
{
   public:
      void bar()
      {
         cout << "vfunc in derived class\n";
      }
};

int main()
{
   derived d;
}

上面的代码在基类中有纯虚函数bar(),它在派生类中被重写了。纯虚函数bar()在基类中没有定义。

现在关注 Line1Line2Line3Line4

我明白了:第 1 行 给出了编译错误,因为不能从 ctor 调用纯虚函数。

问题:

  1. 为什么 Line2Line4 没有编译错误,原因与我理解中提到的相同> 上面的声明? Line2Line4 中的调用最终只会导致 linker-error

  2. 为什么 Line3 既不给出编译错误也不给出链接器错误而只给出运行时异常

通过构造函数调用纯虚函数时 UB 的真实示例:

Real-Life example of UB when Pure virtual function call through constructor

最佳答案

在所有四种情况下,行为都是未定义的;所以究竟会发生什么取决于你的编译器在面对无效输入时碰巧做了什么。

编译器可能会尝试诊断问题并发出警告;这对于第 1 行很容易,而对于其他行则更难,这可以解释为什么您只看到第 1 行的警告。

当从构造函数调用虚函数时,编译器知道应该调用哪个重载,因此它可能会生成静态调用。这就是您从第 2 行和第 4 行收到链接错误的原因。

在第 3 行中,编译器肯定认为确定它是否可以生成静态调用太难了,所以它生成了一个动态调用。跟踪变量的值比确定临时指针必须引用 this 更难,而且通常根本不可能。这就是为什么会出现运行时错误的原因。

当然,所有这些都是未定义的行为,并且可能会因编译器而异,或者根据月相变化。

如果函数有一个实现,那么静态调用它是有效的,如Base::bar(),或bptr->Base::酒吧()。动态调用它仍然会产生未定义的行为。

关于c++ - 来自 Base Ctor 的纯虚函数调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9212212/

相关文章:

c++ - 搜索嵌套类对象数组?

c++ - 在指针指向一个指针字段的场景中访问值,每个指针都指向 int

c++ - 在构造函数的链式调用中复制省略

constructor - 如何检查变量是否已使用构造函数构造?

c++ - 什么是 undefined reference /未解析的外部符号错误,我该如何解决?

c++ - 实例化 Mat 对象时 opencv 3.0.0 链接器错误

c - 将代码与 `floor();` 、 `ceil();` 和 `pow();` 链接时出错

c++ - 不使用嵌套的 if 语句只打印改变的值

C++ Doxygen 隐藏注释

c++ - 缺少第一个构造函数参数