I am working on an assignment on compiler design. In the code generation part I am stuck with how to create instructions which will ensure that appropriate method is called at run time. The language is a very small subset of C++.
let’s say:
void main()
{
Animal* a;
a = new Cow;
//what code should be generated to ensure that object 'a' calls Cow::Init here
a->Init(5);
}
class Cow : public Animal{
void Init(int h)
{
height = h;
}
}
class Animal {
int height;
virtual void Init(int h){
height = h;
}
}
a very simple way of doing this(note: this excludes optimizing for know calls at compile time):
if your class has any virtual members (including inherited), then its very first member becomes a pointer to a vftable. the vftable is constant per class definition which is why you need only a pointer.
from there, each unique function is assigned an index in that vftable, so each unique name (note: by name I mean the symbol name including types, but no class-namespace qualification) has a unique index, then the table is filled in from the class at the very top of the inheritance tree down to your current working class definition.
In doing so, newer redifinitions of virtual function will overwrite the older entries that share their index. calling the functions then becomes trivial as you just generate a call to the index for that function’s name-index.
So in your example,
Animalhas a vftable with 1 entry,Init(int), which is assigned the unique index of 0. so you have a vftable looking like so:then when you build the vftable for
Cow, you useAnimalsas a base and add in the virtual functions, in this caseInit(int), but it already has a unique index of 0, so we overwrite the function at index 0:then if we have the call:
we simply transform that to:
where 0 was the unique index allocated to
Init(int).an assembly example just in case that helps:
note: this all assumes your symbol table is setup to be able to detect virtual functions passed through inheritance or those that become virtual from inheritance.
If this where to be optimized you could analyze
aand find that its only assigned a value once, thus you can morph its class to the class of the value it was assigned,Cow. then seeing as you have a class at the end of a derivation chain, you can fold away the vftable call and use a call directly toCow::Init, how this is a lot more tricky, and there are many ways of optimizing out vftable calls, for a project it shouldn’t matter.