gpt4 book ai didi

c++ - 为什么调用没有主体的纯虚方法不会导致链接器错误?

转载 作者:搜寻专家 更新时间:2023-10-31 00:26:26 24 4
gpt4 key购买 nike

我今天遇到了一个很奇怪的场景。在接口(interface)构造函数中直接调用纯虚方法时,出现 undefined reference 错误。

class Interface
{
public:
virtual void fun() const = 0;
Interface(){ fun(); }
};

class A : public Interface
{
public:
void fun() const override {};
};

int main()
{
A a;
}

结果:

prog.cc: In constructor 'Interface::Interface()':
prog.cc:5:22: warning: pure virtual 'virtual void Interface::fun() const' called from constructor
5 | Interface(){ fun(); }
| ^
/tmp/ccWMVIWG.o: In function `main':
prog.cc:(.text.startup+0x13): undefined reference to `Interface::fun() const'
collect2: error: ld returned 1 exit status

但是,将对 fun() 的调用包装在不同的方法中,如下所示:

class Interface
{
public:
virtual void fun() const = 0;
Interface(){ callfun(); }
virtual void callfun()
{
fun();
}
};

class A : public Interface
{
public:
void fun() const override {};
};

int main()
{
A a;
}

编译得很好并且(显然)因纯虚拟调用错误而崩溃。我已经在最新的 GCC 8.2.0 和 9.0.0 以及 Clang 8.0.0 上对其进行了测试。其中,只有 GCC 在第一种情况下会产生链接器错误。

带有错误的完整工作示例的 Wandbox 链接:

编辑:我被标记为重复,但我不确定这个问题是如何重复的。它与调用纯虚拟方法(从构造函数或诸如此类)的危险没有任何关系,我知道它们。

我试图理解为什么编译器在一种情况下允许此调用,而在另一种情况下却不允许这样做,Adam Nevraumont 对此进行了很好的解释。

编辑2:看起来,即使 callFun 不是虚拟的,它仍然以某种方式阻止 GCC 去虚拟化和内联 fun 调用。请参见下面的示例:

class Interface
{
public:
virtual void fun() const = 0;
Interface(){ callfun(); }
void callfun()
{
fun();
}
};

class A : public Interface
{
public:
void fun() const override {};
};

int main()
{
A a;
}

最佳答案

您不是在调用纯虚函数,而是在 vtable 中查找该函数的虚函数表中的当前条目。

碰巧,此时它是一个纯虚函数,所以你会因为 UB 而崩溃。

在第一种情况下,您会收到链接器错误,因为 gcc 正在去虚拟化 ctor 中对 fun 的调用。对 fun 的去虚拟化调用直接调用纯虚拟方法。这是可能的,因为在构造 Interface 时,编译器知道虚函数表的状态(派生类对它的修改尚未发生)。

在第二种情况下,编译器可以将构造函数对 callFun 的调用去虚拟化。但是从 callFun 中调用 fun 不能去虚拟化,因为 callFun 可以从 ctor 外部的另一个方法中调用。 在一般情况下对其进行去虚拟化是不正确的。

在这种特定情况下,如果编译器将 callFun 去虚拟化,然后将其内联,那么它可以在内联拷贝中将 fun 去虚拟化。但编译器不会这样做,因此不会发生去虚拟化。

顺便说一句,您可以实现该纯虚函数并使您提供的每个示例都能正常链接和运行。

void Interface::fun() const {}

链接到的任何 .cpp 文件中的任何位置都将使您的代码链接,并且无论如何都是正确的。纯虚拟在 C++ 中并不意味着“没有实现”,它只是意味着“派生类必须提供重写,并且对我来说没有实现是合法的”。

关于c++ - 为什么调用没有主体的纯虚方法不会导致链接器错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52445341/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com