Virtual functions are used to achieve runtime polymorphism

https://www.educba.com/virtual-keyword-in-c-plus-plus/

Uses of the virtual keyword

See https://en.cppreference.com/w/cpp/keyword/virtual

Related keywords: override, final

virtual function specifier

The virtual specifier specifies that a non-static member function is virtual and supports dynamic dispatch. It may only appear in the decl-specifier-seq of the initial declaration of a non-static member function (i.e., when it is declared in the class definition).

Virtual functions are member functions whose behavior can be overridden in derived classes. As opposed to non-virtual functions, the overriding behavior is preserved even if there is no compile-time information about the actual type of the class. That is to say, if a derived class is handled using pointer or reference to the base class, a call to an overridden virtual function would invoke the behavior defined in the derived class. Such a function call is known as virtual function call or virtual call. Virtual function call is suppressed if the function is selected using qualified name lookup

virtual base class specifier

  • when to declare a virtual destructor
  • virtual function dispatch
  • Virtual base class

Cannot be declared virtual

Non-member functions and static member functions cannot be virtual. Function templates cannot be declared virtual. This applies only to functions that are themselves templates - a regular member function of a class template can be declared virtual.

Virtual tables

A non-virtual class has a size of 1 because in C++ classes can’t have zero size.

A virtual class has a size of 8 on a 64-bit machine because there’s a hidden pointer inside it pointing to a vtable. vtables are static translation tables, created for each virtual-class.

#include <iostream>

int main() {

    struct A {
    } a;

    struct B {
        virtual void func(){;}
    } b;
    

    std::cout << (sizeof a) << "\n";
    std::cout << (sizeof b) << "\n";
}
Program returned: 0
1
8

https://godbolt.org/z/Wen6EP9Wx

Virtual base classes

The usual wisdom is that the base class destructor must be declared virtual if deleting a derived class via a base class pointer is not to leak. In a hierachy of classes you can get away with only declaring virtual in the class instance that you call delete on. However, getting it slightly wrong can cause a crash so just put it in the base class.

#include <iostream>
#include <memory>

struct A {
    ~A(){ std::cout << "~A\n"; }
    int i;
    int j;
};

struct B : A {
    ~B(){ std::cout << "~B\n"; }
};

struct C : B {
     virtual ~C(){ std::cout << "~C\n"; }
};

struct D : C {
     ~D(){ std::cout << "~D\n"; }
};

int main() {
    std::unique_ptr<C> a = std::make_unique<D>();
}

https://godbolt.org/z/Gnee41v4M

vtables

int main() {
    struct A {
        virtual void blah(){;}
    } a;
}

https://godbolt.org/z/5G9zcd3KP

Assembly

Note the vtable section. Adding the virtual keyword generates a lot more code.

main:                                   # @main
        push    rbp
        mov     rbp, rsp
        sub     rsp, 16
        lea     rdi, [rbp - 8]
        call    main::A::A() [base object constructor]
        xor     eax, eax
        add     rsp, 16
        pop     rbp
        ret
main::A::A() [base object constructor]:                       # @main::A::A() [base object constructor]
        push    rbp
        mov     rbp, rsp
        mov     qword ptr [rbp - 8], rdi
        mov     rax, qword ptr [rbp - 8]
        movabs  rcx, offset vtable for main::A
        add     rcx, 16
        mov     qword ptr [rax], rcx
        pop     rbp
        ret
main::A::blah():                    # @main::A::blah()
        push    rbp
        mov     rbp, rsp
        mov     qword ptr [rbp - 8], rdi
        pop     rbp
        ret
vtable for main::A:
        .quad   0
        .quad   typeinfo for main::A
        .quad   main::A::blah()

typeinfo name for main::A:
        .asciz  "Z4mainE1A"

typeinfo for main::A:
        .quad   vtable for __cxxabiv1::__class_type_info+16
        .quad   typeinfo name for main::A

See also