Where is my virtual function???

Discussion in 'C++' started by Maxim Rogozhin, Jul 24, 2010.

  1. HI, All!
    I've created the following class hierarchy in MS Visual Studio:

    class B {
    };

    class D : public B {
    public:
    virtual void g();
    };

    void D::g() {}

    and created my object:
    D* p = new D;

    So far so good. I can see an "B" entry and __vfptr (const
    D::'vftable') entry under 'p' entry in "Locals" window, and I can see
    an [0x0] entry for function g() under __vfptr.

    But if I add a virtual function f() in class B:
    class B {
    public:
    virtual void f();
    };

    void B::f() {}

    class D : public B {
    public:
    virtual void g();
    virtual void f();
    };

    void D::g() {}
    void D::f() {}

    then virtual function g() disappears from __vftbl. Moreover - __vfptr
    entry has moved under the "B" entry in "Locals" windows (it was under
    'p' entry formerly).

    So my question is where has my function g() got?? And why __vfptr
    moves from 'p' to 'B' ?

    Thanks in advance!!!
    Maxim Rogozhin, Jul 24, 2010
    #1
    1. Advertising

  2. Maxim Rogozhin

    SG Guest

    On 24 Jul., 12:10, Maxim Rogozhin wrote:
    > [...] MS Visual Studio [...]
    > [...] __vfptr (const D::'vftable') [...]
    > [...] __vfptr moves from 'p' to 'B' [...]


    You are not supposed to care about these implementation details. They
    are not part of the C++ standard.

    Cheers!
    SG
    SG, Jul 24, 2010
    #2
    1. Advertising

  3. On Jul 24, 5:20 pm, SG <> wrote:
    > On 24 Jul., 12:10, Maxim Rogozhin wrote:
    >
    > > [...] MS Visual Studio [...]
    > > [...] __vfptr (const D::'vftable') [...]
    > > [...] __vfptr moves from 'p' to 'B' [...]

    >
    > You are not supposed to care about these implementation details. They
    > are not part of the C++ standard.
    >
    > Cheers!
    > SG


    OK. But VS shows me vtable and its entries. I want to figure out why
    function g() is missing.
    Maxim Rogozhin, Jul 24, 2010
    #3
  4. Maxim Rogozhin

    SG Guest

    On 24 Jul., 13:06, Maxim Rogozhin wrote:
    > I want to figure out why function g() is missing.


    Why do you care?
    SG, Jul 24, 2010
    #4
  5. Maxim Rogozhin <>, on 24/07/2010 04:06:01, wrote:

    > On Jul 24, 5:20 pm, SG<> wrote:
    >> On 24 Jul., 12:10, Maxim Rogozhin wrote:
    >>
    >>> [...] MS Visual Studio [...]
    >>> [...] __vfptr (const D::'vftable') [...]
    >>> [...] __vfptr moves from 'p' to 'B' [...]

    >>
    >> You are not supposed to care about these implementation details. They
    >> are not part of the C++ standard.
    >>
    >> Cheers!
    >> SG

    >
    > OK. But VS shows me vtable and its entries. I want to figure out why
    > function g() is missing.


    I'm not 100% sure if this very case falls under the implementer
    freedoms, but surely a compiler can drop parts of code if it can prove
    that those parts are never ever used during runtime - i.e. just
    optimizing the executable size.

    If you really feel you want to investigate the issue, you might try
    creating different tests, some where you define and use some functions,
    some other where you define but /don't/ use them.

    In any case, this is an off-topic issue for this NG, strictly speaking -
    you would find more ad-hoc information in a MS group/forum, but you
    could also generalize the issue if you are interested in the mechanism
    as one of the C++ features and continue the discussion here.

    --
    FSC - http://userscripts.org/scripts/show/59948
    http://fscode.altervista.org - http://sardinias.com
    Francesco S. Carta, Jul 24, 2010
    #5
  6. On Jul 24, 6:34 pm, SG <> wrote:
    > On 24 Jul., 13:06, Maxim Rogozhin wrote:
    >
    > > I want to figure out why function g() is missing.

    >
    > Why do you care?


    I learn COM. COM technology is based on binary layout of vtbl. I just
    wanted to experiment with my custom interfaces and classes to make
    sure that things go as described in COM and C++ books)
    Maxim Rogozhin, Jul 24, 2010
    #6
  7. Maxim Rogozhin

    Öö Tiib Guest

    On 24 juuli, 17:45, Maxim Rogozhin <> wrote:
    > On Jul 24, 6:34 pm, SG <> wrote:
    >
    > > On 24 Jul., 13:06, Maxim Rogozhin wrote:

    >
    > > > I want to figure out why function g() is missing.

    >
    > > Why do you care?

    >
    > I learn COM. COM technology is based on binary layout of vtbl. I just
    > wanted to experiment with my custom interfaces and classes to make
    > sure that things go as described in COM and C++ books)


    You mean DCOM? That port 135 worm-hole. The various registered objects
    fill registry with various crap and turn it slow. It has been
    deprecated in favor of .NET framework ... so no surprize if MS
    announces 5 years later that "Oh sorry Maxim, all you studied was
    worthless junk so it will be removed from next Windows Budget-Extra-
    Ultima .NET-64#."
    Öö Tiib, Jul 24, 2010
    #7
  8. Maxim Rogozhin

    ralph Guest

    On Sat, 24 Jul 2010 07:45:08 -0700 (PDT), Maxim Rogozhin
    <> wrote:

    >On Jul 24, 6:34 pm, SG <> wrote:
    >> On 24 Jul., 13:06, Maxim Rogozhin wrote:
    >>
    >> > I want to figure out why function g() is missing.

    >>
    >> Why do you care?

    >
    >I learn COM. COM technology is based on binary layout of vtbl. I just
    >wanted to experiment with my custom interfaces and classes to make
    >sure that things go as described in COM and C++ books)


    Then here are two major points about COM you should keep in mind. Both
    are well known, but often under-appreciated.

    1) "COM" is a protocol. "OLE" is its implementation.
    While common conventions have come about for implementing (coding) COM
    and Microsoft's implementation has become a "standard" on its own (ie,
    OLE 2), as long as COM protocol is obeyed (a COM participate can
    consume or source a COM object) a coder/compiler/libraries are
    relatively free on how it goes about its implementation.

    2) There is no implementation inheritance in COM. (Only interface
    inheritance is supported). Thus no matter what mechanical construction
    is going on under the covers - COM sees a single result. While a
    compiler might be able to mine or resolve elements of a particular
    construct, COM is limited to what it first sees - a resultant
    interface.

    -ralph
    ralph, Jul 24, 2010
    #8
  9. Maxim Rogozhin <> writes:

    > HI, All!
    > I've created the following class hierarchy in MS Visual Studio:
    >
    > class B {
    > };
    >
    > class D : public B {
    > public:
    > virtual void g();
    > };
    >
    > void D::g() {}
    >
    > and created my object:
    > D* p = new D;
    >
    > So far so good. I can see an "B" entry and __vfptr (const
    > D::'vftable') entry under 'p' entry in "Locals" window, and I can see
    > an [0x0] entry for function g() under __vfptr.
    >
    > But if I add a virtual function f() in class B:
    > class B {
    > public:
    > virtual void f();
    > };
    >
    > void B::f() {}
    >
    > class D : public B {
    > public:
    > virtual void g();
    > virtual void f();
    > };
    >
    > void D::g() {}
    > void D::f() {}
    >
    > then virtual function g() disappears from __vftbl. Moreover - __vfptr
    > entry has moved under the "B" entry in "Locals" windows (it was under
    > 'p' entry formerly).
    >
    > So my question is where has my function g() got??


    I can only guess at what is happening here, but the following feels like
    an at least possible way of looking at it.

    In your first version, g() is declared a virtual member of D with no
    counterpart in B. I am guessing that the presence of the virtual
    keyword in some way requires a vtable to be generated, even though it is
    not `used' by your code. D::g() is then added to the vtable because
    *something* must be but, as it is not used in a way that /requires/ it to
    be virtual, it /could/ be left out as an optimisation if there
    were something else to replace it, so to speak. (Remember, D::g() does
    not override anything and is not overriden itself, virtually or otherwise.)

    In the second version, there is indeed `something else' - your pairing
    of B::f() and D::f() for which, now, the virtual specifier has meaning
    (or rather, /effect/). D::g() can now be dropped from the vtable as the
    proposed optimization. D::f(), however, cannot be, since it overrides
    B::f() and *could* be called virtually.

    To `ressurect' your D::g(), merely add the virtual member B::g() to B
    and you will see two entries in your vtable.

    > And why __vfptr moves from 'p' to 'B' ?


    p is of type D*. Since, in your first example, there are no virtual
    members declared in B, D is the `highest' (or `lowest', if you visualize
    hierarchies from the bottom up) class that requires the vtable. In your
    second example, however, the requirement of a vtable is shifted up (or
    down) owing to the presence of a virtually-declared member in B, hence
    VS's representation of the vtable shifts likewise to interpose B in the
    visual tree. Well... something like that. :)

    Regards

    Paul Bibbings
    Paul Bibbings, Jul 24, 2010
    #9
  10. On Jul 24, 10:54 pm, Paul Bibbings <> wrote:
    >
    > I can only guess at what is happening here, but the following feels like
    > an at least possible way of looking at it.
    >
    > In your first version, g() is declared a virtual member of D with no
    > counterpart in B.  I am guessing that the presence of the virtual
    > keyword in some way requires a vtable to be generated, even though it is
    > not `used' by your code.  D::g() is then added to the vtable because
    > *something* must be but, as it is not used in a way that /requires/ it to
    > be virtual, it /could/ be left out as an optimisation if there
    > were something else to replace it, so to speak.  (Remember, D::g() does
    > not override anything and is not overriden itself, virtually or otherwise..)
    >
    > In the second version, there is indeed `something else' - your pairing
    > of B::f() and D::f() for which, now, the virtual specifier has meaning
    > (or rather, /effect/).  D::g() can now be dropped from the vtable as the
    > proposed optimization.  D::f(), however, cannot be, since it overrides
    > B::f() and *could* be called virtually.
    >
    > To `ressurect' your D::g(), merely add the virtual member B::g() to B
    > and you will see two entries in your vtable.
    >
    > > And why __vfptr moves from 'p' to 'B' ?

    >
    > p is of type D*.  Since, in your first example, there are no virtual
    > members declared in B, D is the `highest' (or `lowest', if you visualize
    > hierarchies from the bottom up) class that requires the vtable.  In your
    > second example, however, the requirement of a vtable is shifted up (or
    > down) owing to the presence of a virtually-declared member in B, hence
    > VS's representation of the vtable shifts likewise to interpose B in the
    > visual tree.  Well... something like that. :)
    >
    > Regards
    >
    > Paul Bibbings


    Paul, thank you for your detailed answer!

    But I have investigated assembler code generated for p->g() call and
    it coincides with assembler code generated for p->f() call. On the
    other hand for non-virtual function h() compiler has generated
    completely different code:
    p->f();
    0041159D mov eax,dword ptr [p]
    004115A0 mov edx,dword ptr [eax]
    004115A2 mov esi,esp
    004115A4 mov ecx,dword ptr [p]
    004115A7 mov eax,dword ptr [edx]
    004115A9 call eax
    004115AB cmp esi,esp
    004115AD call @ILT+365(__RTC_CheckEsp) (411172h)
    p->g();
    004115B2 mov eax,dword ptr [p]
    004115B5 mov edx,dword ptr [eax]
    004115B7 mov esi,esp
    004115B9 mov ecx,dword ptr [p]
    004115BC mov eax,dword ptr [edx+4] // different offset
    004115BF call eax
    004115C1 cmp esi,esp
    004115C3 call @ILT+365(__RTC_CheckEsp) (411172h)
    p->h();
    004115C8 mov ecx,dword ptr [p]
    004115CB call D::h (4110C3h)

    Looks like there's an entry for virtual function g() in vtbl of class
    D, but VS doesn't shows it ... for some unknown reason...

    Though I'm guessing about this reason - in the second example vtbl
    entry is located under 'B' entry, i.e. we see part of vtbl related to
    class B. But why VS doesn't show remaining part under entry for
    'p' (for class D) then???
    Maxim Rogozhin, Jul 25, 2010
    #10
  11. Maxim Rogozhin

    James Kanze Guest

    On Jul 24, 11:10 am, Maxim Rogozhin <> wrote:

    > I've created the following class hierarchy in MS Visual Studio:


    > class B {
    > };


    > class D : public B {
    > public:
    > virtual void g();
    > };


    > void D::g() {}


    > and created my object:
    > D* p = new D;


    > So far so good. I can see an "B" entry and __vfptr (const
    > D::'vftable') entry under 'p' entry in "Locals" window, and
    > I can see an [0x0] entry for function g() under __vfptr.


    > But if I add a virtual function f() in class B:
    > class B {
    > public:
    > virtual void f();
    > };


    > void B::f() {}


    > class D : public B {
    > public:
    > virtual void g();
    > virtual void f();
    > };


    > void D::g() {}
    > void D::f() {}


    > then virtual function g() disappears from __vftbl. Moreover
    > - __vfptr entry has moved under the "B" entry in "Locals"
    > windows (it was under 'p' entry formerly).


    How do you determine this? If it is with the debugger, it may
    be just an artifact of the way the debugger displays
    information. However...

    > So my question is where has my function g() got?? And why
    > __vfptr moves from 'p' to 'B' ?


    This is all very implementation dependent, but in general, in
    all of the implementations I know, your class D will only have
    one vptr. (Multiple inheritance will introduce more.) In the
    same way the compiler puts the data in B in front of the data
    added by D, it will put the entries for B in the vtable in front
    of those for D. The debugger is probably just displaying those
    which are valid for both B and D as for B, and those only valid
    for D as for D.

    --
    James Kanze
    James Kanze, Jul 26, 2010
    #11
  12. Maxim Rogozhin wrote:
    > But I have investigated assembler code generated for p->g() call and
    > it coincides with assembler code generated for p->f() call.


    What? You even marked the place where these two calls differ from each
    other.

    > On the
    > other hand for non-virtual function h() compiler has generated
    > completely different code:
    > p->f();
    > 0041159D mov eax,dword ptr [p]
    > 004115A0 mov edx,dword ptr [eax]
    > 004115A2 mov esi,esp
    > 004115A4 mov ecx,dword ptr [p]
    > 004115A7 mov eax,dword ptr [edx]
    > 004115A9 call eax
    > 004115AB cmp esi,esp
    > 004115AD call @ILT+365(__RTC_CheckEsp) (411172h)
    > p->g();
    > 004115B2 mov eax,dword ptr [p]
    > 004115B5 mov edx,dword ptr [eax]
    > 004115B7 mov esi,esp
    > 004115B9 mov ecx,dword ptr [p]
    > 004115BC mov eax,dword ptr [edx+4] // different offset
    > 004115BF call eax
    > 004115C1 cmp esi,esp
    > 004115C3 call @ILT+365(__RTC_CheckEsp) (411172h)
    > p->h();
    > 004115C8 mov ecx,dword ptr [p]
    > 004115CB call D::h (4110C3h)
    >
    > Looks like there's an entry for virtual function g() in vtbl of class
    > D, but VS doesn't shows it ... for some unknown reason...


    Yup. VC shows the vtable of the derived class if the base class has no
    vtable. Else it will show the vtable of the base class (note the name
    of the vtable: B::__vfptr 0x004157cc const D::`vftable', this means
    that VC recognizes that it displays the partial vtable of D). This is
    probably by design, and if not, this will probably be classified as
    "by design" as soon as you complain about it ;-)

    > Though I'm guessing about this reason - in the second example vtbl
    > entry is located under 'B' entry, i.e. we see part of vtbl related to
    > class B. But why VS doesn't show remaining part under entry for
    > 'p' (for class D) then???


    Who knows what the people at MS are thinking.

    Regards,
    Stuart
    Stuart Redmann, Jul 26, 2010
    #12
  13. On Jul 26, 9:30 pm, Stuart Redmann <> wrote:
    > Maxim Rogozhin wrote:
    > > But I have investigated assembler code generated for p->g() call and
    > > it coincides with assembler code generated for p->f() call.

    >
    > What? You even marked the place where these two calls differ from each
    > other.


    Mmm... almost coinsides :)


    > Who knows what the people at MS are thinking.


    I have also investigated windbg output (dt -v p) and got the analogous
    result - only B-class related part of vtbl is shown. There definitely
    must be a reason for such behaviour of MS debuggers!

    I have also posted a question here
    http://social.msdn.microsoft.com/Forums/en/vsdebug/thread/23f0a79b-1ca9-467a-9c28-70be30a4ea5a
    Maxim Rogozhin, Jul 26, 2010
    #13
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Xiangliang Meng
    Replies:
    2
    Views:
    405
    Jack Klein
    Jun 21, 2004
  2. IK
    Replies:
    2
    Views:
    593
    hemraj
    Jul 23, 2004
  3. Ashwin
    Replies:
    2
    Views:
    337
    Pierre Barbier de Reuille
    Aug 1, 2006
  4. Replies:
    11
    Views:
    681
    James Kanze
    Sep 10, 2006
  5. Replies:
    7
    Views:
    578
    James Kanze
    May 2, 2007
Loading...

Share This Page