简体   繁体   中英

Does a base class method marked as `virtual final` introduce additional overhead?

Suppose I want to have a class Base with two methods: foo(int) and bar(int) . I want them to be defined in a way that:

  • Base::foo has to be overridden in a derived non-abstract class
  • Base::bar cannot be overridden in a derived class

The first objective can be accomplished by marking foo as virtual int foo(int) = 0 , to make it abstract. The second requirement can be met by marking bar as virtual int bar(int) final to make it final. This is the resulting code:

class Base
{
public:
    virtual int foo(int n) = 0;
    virtual int bar(int n) final
    {
        return n + 42;
    }
};

And an example class derived from Base :

class Derived : public Base
{
public:
    virtual int foo(int n) override
    {
        return n * n;
    }
    int bar(int n) // compilation error here
    {
        return n + 43;
    }
};

Trying to override Base::bar has triggered a compilation error just as we wanted.

Now, my question is: Does marking a method as virtual final introduce overhead because of the function being virtual (dynamic dispatch) even though the function cannot be overridden anyway?

Edit

Don't mind the lack of the virtual destructor ~Base() it isn't here to make the code shorter.

Compiler is likely to devirtualize this call:

struct Base {
    virtual int bar(int n) final {
        return n + 42;
    }
};

struct Derived : Base { };

int foo(Derived& d, int n) {
    return d.bar(n);
}

becomes with -O1 :

foo(Derived&, int):
        lea     eax, [rsi+42]
        ret

whereas without final , we get an indirect call:

foo(Derived&, int):
        sub     rsp, 8
        mov     rax, QWORD PTR [rdi]
        call    [QWORD PTR [rax]]
        add     rsp, 8
        ret

In your case No overhead because your class doesn't inherit from any class defines your final function so the compiler will generate direct call to its address regardless virtual declaration.

Here it is from actual code:

b->FoA(); //virtual inherited
002829A7  mov         eax,dword ptr [b]  
002829AA  mov         edx,dword ptr [eax]  
002829AC  mov         esi,esp  
002829AE  mov         ecx,dword ptr [b]  
002829B1  mov         eax,dword ptr [edx]  
002829B3  call        eax  
002829B5  cmp         esi,esp  
002829B7  call        __RTC_CheckEsp (02812E9h)  
    b->FoB(); // final
002829BC  mov         ecx,dword ptr [b]  
002829BF  call        A::FoB (0281366h)  

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM