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
}