April 19, 2024, 07:40:16 PM

News:

IonicWind Snippit Manager 2.xx Released!  Install it on a memory stick and take it with you!  With or without IWBasic!


Virtual Functions

Started by Zen, December 11, 2005, 02:55:27 PM

Previous topic - Next topic

0 Members and 6 Guests are viewing this topic.

Zen

Hi. I need an explanation on Virtual functions. Im not really sure what they are or what they do different to a normal function.

Lewis

Parker

A virtual function works like one declared with IMPORT: it's called through a pointer. When you declare a class, it creates a variable called ClassName_vtable_ which contains the addresses of all the functions in the class. So take for example this class:
class Sample
{
declare virtual Thing();
}

The variable Sample_vtable_ will contain a reference to Thing(). When you call the method Thing(), the compiler calls it through the vtable. This allows you to overwrite the function. For example,
class Computer : Sample
{
declare Thing();
}


By default, Computer inherits all the methods of Sample. But when you overwrite the Thing() method, the vtable changes to point to Computer@Thing instead of Sample@Thing (internal names of class functions). Paul added the !! operator so you can call the base classes function though. So you could do something like this:
Computer comp;
comp.Thing();
...
Computer::Thing()
{
writeln("In Computer::Thing\n");
Sample!!Thing(); // call the base class' Thing()
return;
}

which would write "In Computer::Thing" and then do whatever was stored in Sample's Thing() method.

I hope you understand, if not, maybe Paul can explain it better.

Zen

Yes i understand now. Its basicly a method that does something as standard but allows the user to overwrite what it does by default.

Thanks Parker
Lewis

Ionic Wind Support Team

Not a bad description.  I'll have a go at it....

Virtual functions allow polymorphism.  Thats is to say being able to call a derived classes function when you only have a pointer to the base class.  Or in the case of a base class method calling a virtual function it will call the correct function in the derived class.

Virtual functions are also known as 'overridables'.  Lets consider the window class for a moment.  Deep in the bowels of the window class is the message handler which calls the proper virtual function based on a message received.  For sake of argument we'll use a select/case construct.


class window
{
    declare virtual OnClose(),INT;
    declare virtual OnCreate(),INT;
    ....a bunch more
    declare virtual WndProc(message as int, wparam as int, lparam as int);
}


And the window class simply impliments the virtual functions as do nothing 'stubs'.


window::OnClose(),int
{
return 0;
}

window::OnCreate(),int
{
return 0;
}


Now since the functions are declared as virtual a 'virtual function table' is created with addresses to those functions.  In assembly:


window_vtable_
dd $window@OnClose
dd $window@OnCreate
dd $window@WndProc


Which is just an array of address.  So now the fun and magic begins.  Lets code the WndProc function which processes the messages and calls the virtual functions


window::wndProc(message as int,lparam as int,wparam as int),int
{
    select message
    {
        case WM_CLOSE:
               result = OnClose();
        case WM_CREATE:
               result  = OnCreate();
    }
    return result;
}


Now lets say we use the window class directly.

window win;
win.Create(...)

When the WM_CREATE message is received by the internal handler it calls OnCreate.  OnCreate is a virtual function whose address is in the table we presented earlier.  Not much goes on since it just calls the base class stub function which returns 0.

However deriving a class from window, and overriding those functions is how we make things happen.


class MyWindow : window
{
   declare OnClose(),int;
   declare OnCreate(),int;
}


It is not necessary to use the 'virtual' keyword when overriding a virtual function.  It's ok to do so of course but the compiler is smart enough to know what you want.

MyWindow now has its own vtable which looks like this:

mywindow_vtable_
dd $MyWindowOnClose
dd $MyWindow@OnCreate
dd $window@WndProc


As you can see a vtable of a derived class will have as many entries as the base class plus any entries for virtual functions first declared in the derived class.  In proper order of course.

Now when a message is received by WndProc it calls OnCreate,looking up the address in the vtable to perform the call.  So instead of calling the base classes function it will call the derived class function.

As mentioned earlier polymorphism allows using a pointer to a base class while still calling the correct function in any derived classed.  As an example lets say you wanted to create a generic function that would close a window, regardless of how many derivations of the base there are.

SUB CloseMyWindow(window *win)
{
*win.OnClose();
*win.Destory();
}

You could pass this a pointer to a MyWindow class, a YourWindow class, etc.  It would still call the correct virtual function in the derived class.

Hope that helps.

Paul.
Ionic Wind Support Team

Zen

Great, thanks a lot guys. That helped a lot. Its just ive never used these before or even heard of them so now thats that understood i can get on with things now.

Lewis