C++11 には仮想関数をそれ以上オーバーライドできないようにする final という指定が書けますが、final が付いていると呼ぶときに vtable を参照して間接callするのではなく直接呼ぶようになります。(とりあえず GCC の場合)

[umezawa@umezawa-cent7:pts/0 ~]$ cat a.cc
struct A {
        virtual void foo();
};

struct B : public A {
        virtual void foo() final;
};

struct C : public A {
        virtual void foo();
};

void bar(B* b)
{
        b->foo();
}

void baz(C* c)
{
        c->foo();
}
[umezawa@umezawa-cent7:pts/0 ~]$ g++ -std=c++11 -S -o- -O0 a.cc
        .file   "a.cc"
        .text
        .globl  _Z3barP1B
        .type   _Z3barP1B, @function
_Z3barP1B:
.LFB0:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        subq    $16, %rsp
        movq    %rdi, -8(%rbp)
        movq    -8(%rbp), %rax
        movq    %rax, %rdi
        call    _ZN1B3fooEv
        leave
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE0:
        .size   _Z3barP1B, .-_Z3barP1B
        .globl  _Z3bazP1C
        .type   _Z3bazP1C, @function
_Z3bazP1C:
.LFB1:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        subq    $16, %rsp
        movq    %rdi, -8(%rbp)
        movq    -8(%rbp), %rax
        movq    (%rax), %rax
        movq    (%rax), %rax
        movq    -8(%rbp), %rdx
        movq    %rdx, %rdi
        call    *%rax
        leave
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE1:
        .size   _Z3bazP1C, .-_Z3bazP1C
        .ident  "GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-16)"
        .section        .note.GNU-stack,"",@progbits

興味深いのは最適化なしでもそうなるという点でしょうか。

直接呼ばれるとシンボルを参照するようになるため、リンク順でハマるケースがあるかもしれません。

Trackback

no comment untill now

Add your comment now