C++ 使用gcc调用纯虚拟函数时发生链接器错误

C++ 使用gcc调用纯虚拟函数时发生链接器错误,c++,linker,C++,Linker,我和一位朋友就对象的构造进行了一次非常有趣的讨论,最终得到了这段代码: #include <iostream> class Parent { public: Parent( ) { this->doSomething( ); } virtual void doSomething( ) = 0; }; class Child : public Parent { int param; public: Child(

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

#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;
}
#包括
班级家长{
公众:
父项(){
这个->doSomething();
}
虚空剂量测量()=0;
};
类子:公共父类{
int参数;
公众:
子(){
参数=1000;
}
虚空剂量测定法(){

std::cout编译器知道,当您从构造函数内部调用
doSomething
时,该调用必须引用该类中的
doSomething
,即使它是虚拟的。因此它将优化虚拟分派,而只执行普通函数调用。由于函数未在任何地方定义,因此会导致错误或者在链接时。

在调用doSomething()的指针处,编译器可以确定*this的动态类型是父类,因此无需间接调用函数。此行为在很大程度上取决于您使用的编译器/链接器

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

让我们进一步扩展一下

为什么是链接器错误

因为编译器从构造函数中注入了对
Parent::doSomething()
的调用,但是链接器没有找到函数的定义

我希望编译器会抱怨,尤其是因为函数有一个实现

这是不正确的。该函数有一个可通过虚拟分派访问的重写,但函数
Parent::doSomething()
未定义。其中有一个细微但重要的区别,可以通过禁用动态分派以不同的方式进行测试。您可以通过使用类名限定函数来禁用特定调用的动态分派,例如,在
Child::doSomething()
中添加
Parent::doSomething())
,它将生成对
父::doSomething()
的调用,而不使用动态分派来调用最终重写器

为什么这很重要

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

struct base{
虚空f()=0;
};

内联void base::f(){std::cout您没有在基类中实现该函数,您只是尝试调用它。是的,您是对的(这就是我的意思,用词不当)。这实际上可以通过定义函数来测试。感谢您提供的详细答案。
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
}