0

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?

1201ProgramAlarm
  • 32,384
  • 7
  • 42
  • 56
meng
  • 3
  • 2
  • 1
    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 Aug 12 '19 at 19:04
  • Add code that calls d3.function1(), d3.function2(), and d3.function3(). Check the disassembly. What do you see? – Jeffrey Aug 12 '19 at 19:06
  • 2
    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 Aug 12 '19 at 19:09
  • @1201ProgramAlarm Or the compiler just optimized it out since it's never used. – Jesper Juhl Aug 12 '19 at 19:29
  • 1
    Unrelated: Once a function is declared `virtual` it's virtual in all derived classes ([But also see `final`](https://en.cppreference.com/w/cpp/language/final)). What this means for you is you don't have to keep repeating `virtual`. – user4581301 Aug 12 '19 at 19:54
  • 2
    [override](https://en.cppreference.com/w/cpp/language/override) *is* handy to use with those virtual methods in the derived classes, though. – Shawn Aug 12 '19 at 20:00
  • @JesperJuhl How can (some) virtual functions be optimized out? – curiousguy Aug 13 '19 at 18:22
  • @curiousguy There are situations where the compiler can prove they are never used polymorphically. As an extreme example, consider a `final` class defined in a source file. – Jesper Juhl Aug 13 '19 at 18:40
  • @JesperJuhl How does final "prove" anything? – curiousguy Aug 13 '19 at 18:46
  • @curiousguy It tells the compiler that no other class can inherit from the `final` class. So any `virtual` functions can obviously not be overridden. So the compiler does not need to consider virtual dispatch. – Jesper Juhl Aug 13 '19 at 18:48
  • @JesperJuhl Yes but then what would would that change for the vptr/vtable themselves? – curiousguy Aug 13 '19 at 20:42

2 Answers2

1

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.

SergeyA
  • 61,605
  • 5
  • 78
  • 137
0

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.

krisz
  • 2,686
  • 2
  • 11
  • 18