Search code examples
c++methodsvtable

Where virtual functions use vpointers to vtables to resolve the method call, where are non-virtual methods stored and how are they resolved?


A class with the definition

class A
{
    void AFunc1(){}
    void AFunc2(){}
    void AFunc3(){}
    virtual void AVirtualFunc1(){}
};

Will have a sizeof() value of 4 bytes because of the hidden vpointer member that points to the shared vtable which has the pointers to the methods.

However, an instance of the class

class B
{
    void BFunc1(){}
    void BFunc2(){}
    void BFunc3(){}
};

will only have a sizeof() value of 1 byte because there's no need for the vpointer and as well, there exists no vtable. If that is the case, where are the functions BFunc1(), BFunc2(), and BFunc3() stored and how are they referenced by the object instance?


Solution

  • For every non virtual function which is really used somewhere, the code for the function is emitted to the object file, maybe in multiple files if the code comes from a included header and is used in multiple translation units. In addition, the symbol is inserted also to the object file. You can see the table of defined methods/fuctions/... with nm if you are a linux user like this:

    nm main.o |c++filt

                        U __cxa_atexit
                        U __dso_handle
    0000000000000062 t _GLOBAL__sub_I_main
    0000000000000000 T main
    0000000000000024 t __static_initialization_and_destruction_0(int, int)
    0000000000000000 W A::AVirtualFunc1()
    0000000000000000 W A::AFunc1()
    0000000000000000 r __gnu_cxx::__default_lock_policy
                        U std::ios_base::Init::Init()
                        U std::ios_base::Init::~Init()
    0000000000000000 b std::__ioinit
    0000000000000000 V typeinfo for A
    0000000000000000 V typeinfo name for A
    0000000000000000 V vtable for A
                        U vtable for __cxxabiv1::__class_type_info
    

    As you see A::AFunc1() is defined as a weaksymbol. It is defined weak, because we can have multiple instances in different translation units but we know, they are all identical. ( That's wy we have the "One Definition Rule" in C++). BTW: If you have multiple definitions which are using the same label, the linker puts also only one and also without a error message. The behavior of your program is than defined by the link order. A very bad thing! Back to the weak symbols, the linker should not emit an error, if we we have multiple times the same method stored in the object files. The linker can now simply pick up one of them without any error message. For example the main function is tagged with 'T' in the table. If you have multiple times the same symbol tagged with T, the linker will emit a error message for multiple defined functions.

    You see, that the address of the symbol in the object file is 0000000. This means, it currently have no address. The address will be relocated during link time for a static executable or during dynamic link time on startup of the program.

    As you also can see, the virtual function is also stored in teh same way and there is no difference at all for it. The method itself can also be called with A::AVirtualFunc without jumping over the vtable.

    What you also can see, the vtable itself is part of the object file and marked as V. You can also have the same vtable in multiple object files. The linker also takes only one of them in final link.