Friday, November 28, 2003

Re: Polymorphism

Some questions which have arised and what I think are the answers...


are u sure about this? ... cause i always thought that the pointer created on the object directly points to the v-table of the class


Right, each object points to its own v-table. This is separate from the base class v-table.


that is if i were to write

Base* ptr;
ptr = new Derv();
ptr->pr();

the object created on the free store would have a pointer to Derv's v-table directly .. so why does it have to look at Base's v-table? for the index?


The object created on the free store ONLY has knowledge of itself. It has no idea that the address returned is going to be stored in a Base class pointer. So it would make sense for that (derived) object to have its own v-table.


In your example Dinesh, only the base class has a virtual function and therefore pr only figures in the v-table of base. pr wouldn't figure in the v-table of derv (if it had one) at all since it's not virtual in derv.


Actually, I believe that if a function is declared virtual in a base class, it is implicitly virtual in ALL derived classes as well, whether or not you declare it virtual. So, in Dinesh's example, pr() is virtual in Derv as well.

I dunno if there is a way in c++ to prevent making a function that is already virtual in a base class, virtual in a derived class. Any idea?

Regardless, ALL classes in that hierarchy will have v-tables. One virtual function is ALL you need.


from "Inside the C++ Object Model" by Stanley Lippman ... the constructor of Derv makes the pointer created in the object point to Derv's v-table .. but the index is calculated using knowledge from Base .. cool :):) .. was this what u were trying to say mohnish? .. what i was confused about was to which v-table does the pointer point to ... well thats that :):)


Yes, this is what I was saying. The function addresses in the v-table will appear in the same index, but there will be DIFFERENT v-table for each derived class object. I just didn't phrase it right.

If you have a base class pointer to a derived class object, you will still have a derived class v-table right? So when you call a method on that base class pointer, it will go to the correct index, since they are the same in both the base and derived v-tables, and call the derived class method.


I am still quite confused about the whole thing. If the pointer points to Derv's v-table, how the hell does it even know of the virtual functions in base? That info would only be contained in base's v-table. So how exactly would the index be calculated from base?


Derived classes don't know about base class virtual functions.

Ok consider this...

class Base
{
virtual void fun() { std::cout << "Base"; }
}

class Derived1 : public Base
{
virtual void fun() { std::cout << "Derived1"; }
}

class Derived2 : public Base
{

}

Base class objects have a v-table with one index. That index, say index 0, has the address of Base's fun(). Derived1 also has a v-table with one index. Index 0 has the address of Derived1's fun(). Now, Derived2 does NOT override Base's fun(). But it also has a v-table with one index. That index has the address of Base's fun(). If a derived class choses NOT to override a virtual function, the index in the v-table will point to the address of the base class function.

So when you do...

Base* p;

p = new Derived1;

p->fun() // goes to Derived1's v-table, index 0, which calls Derived1's fun()

p = new Derived2;

p->fun() // goes to Derived2's v-table, index 0, which calls Base's fun()

These indices are calculated by the compiler at compile time and are implementation dependant. I guess the performance penalty is in the indirection. Instead of going straight to the function, you have to go to a table and then from there go to the function.


for(vector< Base* >::iterator g = ptr.begin(); g != ptr.end(); ++g)
(*g)->pr();


This is just a minor thing, but I don't think this is correct...

(*g)->pr()

g is an iterator. An iterator behaves like a pointer. When you dereference an iterator, just like a pointer, you get back an object. So you have to use the dot operator, not the arrow....

(*g).pr();

Like I said, no big deal.

No comments: