为什么成员函数是 virtual 会影响实际上不需要虚拟调度的 TU 的编译代码?

问题描述 投票:0回答:1

在这样的TU中

#include "Foo.hpp"
int main() {
    // stuff
    Foo* foo{new Foo{}};
    foo->foo();
    // stuff
}

其中

Foo.hpp
包含

#pragma once
struct Foo {
    virtual void foo(); // implmented somewhere
};

除了

Foo::foo
之外,不会发生任何调用,对吗?
foo
virtual
并且它和类都不是
final
,所以是的,在 another TU 中可能存在
override
foo
的派生类的对象,依此类推,但是...就这个 TU 而言,我认为
foo->foo()
调用
Foo::foo()
是非常清楚的。我不明白怎么会是这样。

那为什么生成的程序集是这样的呢?

main:                                   # @main
        push    rax
        mov     edi, 8
        call    operator new(unsigned long)@PLT
        mov     rcx, qword ptr [rip + vtable for Foo@GOTPCREL]
        add     rcx, 16
        mov     qword ptr [rax], rcx
        mov     rdi, rax
        call    Foo::foo()@PLT
        xor     eax, eax
        pop     rcx
        ret

我不太了解详细,但我清楚地阅读了

vtable
。为什么它还在那里?

我预计上面的 TU 的程序集 与删除

virtual
关键字后得到的程序集相同:

main:                                   # @main
        push    rax
        mov     edi, 1
        call    operator new(unsigned long)@PLT
        mov     rdi, rax
        call    Foo::foo()@PLT
        xor     eax, eax
        pop     rcx
        ret

这是CE上的示例。)

这个其他答案我读到了

A* a = new B;
a->func();

在这种情况下,编译器可以确定

a
指向
B
对象,因此无需动态调度即可调用
func()
的正确版本。 […]当然,编译器是否做相应的分析取决于其各自的实现。

答案是否只是 Clang 没有进行分析来推断不需要运行时调度?

或者我错过了什么?也许我完全误解了大会?

c++ inheritance virtual-functions dynamic-dispatch virtual-table
1个回答
0
投票

virtual
成员函数始终使用 ODR。所以它必须始终被定义。

© www.soinside.com 2019 - 2024. All rights reserved.