Re: Interview questions

From: Niklas Borson (niklasb_at_microsoft.com)
Date: 07/03/04


Date: 2 Jul 2004 15:19:32 -0700

Sorry I'm slow in replying. I was out of time and offline for a week.
Please do not construe my silence as agreement.

"E. Robert Tisdale" <E.Robert.Tisdale@jpl.nasa.gov> wrote in message news:<cbhpjb$3fp$1@nntp1.jpl.nasa.gov>...
> Niklas Borson wrote:
> > E. Robert Tisdale wrote:
> >>The user should *not* call the functions out of the vtable directly
> >>but implement *virtual* functions in foo.c or bar.c that do so.
> >
> > If I understand correctly, you're saying [that]
> > the users of the class should call a wrapper function
> > which in turn calls the actual function
> > through the pointer in the vtable.
> > Yes, one could do this.
>
> What I am saying is that this is what your C++ compiler does for you.

Maybe your compiler does this, but not mine. Here's an example:

class Foo {
public:
    virtual ~Foo();
    virtual void Hello();
};
void Test(Foo* foo)
{
    foo->Hello();
}

And here's the assembly code my compiler generates for Test:

?Test@@YAXPAVFoo@@@Z PROC NEAR
    mov ecx, DWORD PTR _foo$[esp-4]
    mov eax, DWORD PTR [ecx]
    jmp DWORD PTR [eax+4]
?Test@@YAXPAVFoo@@@Z ENDP

The first instruction loads the foo parameter into a register.
The second instruction loads the vtable pointer into a different
register. The third instruction performs a tail call by jumping
to the entry point of the Hello function, which it gets directly
from the vtable.

In short, the Test function accesses the vtable directly without
calling a wrapper function.

> A virtual function is actually a wrapper
> (that's why it's called a virtual function) that calls
> the actual function through the corresponding function pointer
> in the virtual function table.

According to Stroustrup, the word virtual means "may be redefined
later in a class derived from this one". Nothing about wrapper
functions there.

> > Personally,
> > I don't see the advantage of this extra function call.
> > IMO, exposing the structure of the vtable
> > does not violate encapsulation.
>
> > It doesn't expose the class's data, for example.
> > It tells you only what virtual functions the class has --
> > i.e., its interface.
>
> No!
> It is an implementation detail.

It's an implementation detail of the virtual call mechanism.
That's not the same thing as exposing the representation or
inner workings of the class.

> Siemel Naran used an array
> to represent the virtual function table.

Which did not work very well because (1) all the function
pointers had to have the same type, and (2) the call site
had to specify the array index of the virtual function
rather than its name.

> > Moreover, anyone who wants to derive from the class
> > needs to know the structure of the vtable anyway so
> > as to provide a compatible vtable for the derived class.
>
> That's because the C computer programming language
> does *not* support inheritance.
>
> Yes, the application programmer (user) must know the *order*
> in which function pointers appear in struct Foo_VTable

The user needs to know the order and types of the function
pointers, which is to say *everything* about Foo_VTable.

> but the application programmer does *not* need the definition
> of struct Foo_VTable to define struct Bar_VTable.

The implementor of Bar_VTable needs to ensure that it has
the same members in the same order as Foo_VTable. Therefore
he needs access to the definition of Foo_VTable, or
equivalent documentation.

He may not actually *reference* that definition in the code,
but that doesn't mean it's hidden or encapsulated in any
meaningful way.

> The structure of a C++ vtable isn't defined
> in *any* public C++ header [file].

It is implied by the class definition, which is typically in
a header file. That is, the compiler can deduce the vtable
layout from the class definition, though *how* it does so
(or whether there's a vtable at all) is implementation
dependant.

See the example assembler output I gave earlier. To generate
the object code for the Test function, the compiler relied on
its knowledge of the vtable layout for Foo, which it inferred
from the class definition.

> I don't see any reason why it should be defined
> in any public C header file.
> What is happening here is that the C programmer
> is playing the role of a C++ compiler in simulating inheritance.

Exactly. The programmer is playing the role of the compiler.
Therefore, things like vtables and virtual calls, which a C++
compiler creates for you, must be coded explicitly in C.

> The C programmer can and should infer
> the structure of the virtual function table from the definition
> of class Foo (struct Foo + virtual function declarations).

What virtual function declarations? There is no such thing in C.
In C++ the compiler determines the vtable layout (or whatever)
based on the virtual function declarations. In C, the programmer
must determine the vtable layout. A vtable structure seems like
a natural and obvious way of doing so.

Yes you could use wrapper functions to make the virtual function
calls, but this is not what a typical C++ compiler does. Moreover,
since implementors of derived classes still need to know both the
virtual call mechanism and the vtable layout for the base class,
hiding the actual declaration of the vtable does not actually
buy you anything in terms of encapsulation.

> Run-time polymorphism has been discussed at length
> in the comp.lang.c newsgroup. See Google Groups
>
> http://groups.google.com/
>
> and search for
>
> Tisdale Shape group:comp.lang.c.*

I did. Perhaps you didn't notice that you and I both participated
in that thread. (I posted under a different email address then, but
used my real name then and now.) At the time, you argued that it's
impossible to do OOP in C because it's not really OO unless you use
specific language features, e.g., keywords like class and virtual.
I argued to the contrary. Now you appear to have changed your tune,
and our quibble is over merely *how* one might implement virtual
functions in C. (Of course, I'm not saying there's only one way,
just that my way is valid and reasonable. A better way, of course,
is to just use C++.)



Relevant Pages

  • Re: Interview questions
    ... The compiler has access to the definition of the Foo class. ... it knows that Hello is the second virtual function in the class so it ... I see no reason to suppose that a wrapper function ever existed. ... call mechanism and the vtables -- again, ...
    (comp.lang.cpp)
  • Re: Inspecting object virtual function table & memory layout?
    ... > table and memory layout of an C++ object. ... > virtual function table in a series of relocation tables. ... However, after multiple inheritance, the vtable is kinda ... to familiarize yourself with the in-memory layout of vtables for objects ...
    (microsoft.public.vc.language)
  • Re: What are vTables?
    ... I have a feeling that vTables are used when you override ... function addresses (a virtual function table) that is set up in the ... doesn't mean that they aren't used by the JIT compiler (I can't think of any ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: I wonder if Windows REALLY support the C++ language
    ... >> layout that COM requires. ... two slots per virtual function - one for a pointer and another for a ... every Windows C++ compiler uses vtables and lays them out exactly like VC++. ...
    (microsoft.public.vc.language)
  • Re: Inspecting object virtual function table & memory layout?
    ... > He Shiming wrote: ... >> virtual function table in a series of relocation tables. ... >> So is there a tool available that is able to produce a memory layout ... > to familiarize yourself with the in-memory layout of vtables for objects ...
    (microsoft.public.vc.language)