0
votes

As can be seen, D3 introduces a new virtual function, @function3(), in the middle of the chain of inheritance. I am wondering what is happening with *--vptr and vtable when this happens. D3 is a 'kind of' a new base class now,

class Base {
public:
    virtual void function1() { std::cout << "Base func1()\n"; };
    virtual void function2() { std::cout << "Base func2()\n"; };
};

class D1 : public Base {
public:
    virtual void function2() { std::cout << "D1 func2()\n"; };
};

class D2 : public D1 {
public:
    virtual void function1() { std::cout << "D2 func1()\n"; };
};

class D3 : public D2 {
public:
    virtual void function2() { std::cout << "D3 func2()\n"; };
    virtual void function3() { std::cout << "D3 func3()\n"; };
};

class D4 : public D3 {
public:
    virtual void function1() { std::cout << "D4 func1()\n"; };
    virtual void function3() { std::cout << "D4 func3()\n"; };
};

int main() {
    D3 d3;  
}

https://imgur.com/a/sxFzrKG

but when I see vtable entries, what I can see are function1(), function2(). I thought entries have to be function2(), function3(). Why can't I get what I thought?

2
NOTE: vptr/vtable are implementation details. Implentations don't have to use them to implement virtual dispatch (though most do) - thwy are free to use other methods to achieve the standard mandated behaviour, if they so choose. The compiler is also free to leave out code for stuff it can prove is never actually needed.Jesper Juhl
Add code that calls d3.function1(), d3.function2(), and d3.function3(). Check the disassembly. What do you see?Jeffrey
Possibly the debugger is only showing two entries because Base only has two entries. There will be an additional entry for function3 that is not shown (or might be below the bottom of the window; check the scroll bar).1201ProgramAlarm
Unrelated: Once a function is declared virtual it's virtual in all derived classes (But also see final). What this means for you is you don't have to keep repeating virtual.user4581301
override is handy to use with those virtual methods in the derived classes, though.Shawn

2 Answers

1
votes

Not clear what you mean by 'what is happening'. All vtables are specific to class (type). vtable for D1 is different from vtable for D2, and so forth.

Vtable for D3 has more functions in it, than D1 one. You can normally call those functions if your static type is D3 or D4, but can't call those if your static type is D1 or D2.

0
votes

The vtable contains all inherited virtual functions and any newly introduced one.

Here is the vtable for D3 generated by MSVC:

const D3::`vftable' DD  FLAT:const D3::`RTTI Complete Object Locator'  ; D3::`vftable'
        DD      FLAT:virtual void D2::function1(void)
        DD      FLAT:virtual void D3::function2(void)
        DD      FLAT:virtual void D3::function3(void)

The reason why the debugger doesn't show all of them might be a bug or a limitation.