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 said:
Niklas said:
E. Robert Tisdale said:
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.
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.
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++.)