Click to See Complete Forum and Search --> : Virtual Functions Please???


matu
September 29th, 2002, 05:59 PM
Friends ,
I have a question about virtual functions.
The basic idea behind them is that they help us provide a mechanism to redine(or Override a definition) them in the derived classes.And also a constant interface(that is we can access the correct redefinition of the function depending upon the object assigned to the base class pointer.Also called polymorphism).

All this comes at the cost associated with Late or Dynamic Binding and the space needed to maintain the VTABLES.

So then if we need to redefine the functions , then why not add standalone functions each time we need a new redefinition of the function.And add separate functions calls(as the redefinied functions will have a different name).

Each time we realize that a class should provide some redefinition , then instead of declaring the function as a Virtual function in the base class and then provide an overriding redefinition , We , On the contrary , Add our standalone function and also a function call to it .
NO dynamic binding AND no extra space consumption due to Vtables.
Kindly Help
Thanks in advance Matu
:D

CBasicNet
September 29th, 2002, 11:52 PM
If you redefine the functions, you defeat the purpose of polymorphism. And you also have to write diff code to use your class.

For an example,

A virtual base class called Animal and a virtual function call piss(); and three derived classes namely Human, Cow and Dog.

These 3 animals piss differently, therefore the function need to be overrided.

This external function below uses this class


void AnimalTakingLeak(Animal & Myanimal){
MyAnimal.piss();
}

This is how to call it

....
AnimalTakingLeak(MyHuman);
.......
AnimalTakingLeak(MyCow);
......
AnimalTakingLeak(MyDog);

=============================
If using what you said above, it will be different.


void AnimalTakingLeak(Animal & Myanimal){
//determine if animal is Human, then
MyAnimal.humanpiss();
//determine if animal is cow, then
MyAnimal.cowpiss();
//determine if animal is dog, then
MyAnimal.dogpiss();
}

humanpiss(), cowpiss() and dogpiss() are your re-defined functions

Your idea defeats the purpose of polymorphism and gives those ppl, who use your class, he11 of the time coding.

Hope I explain clearly.;)

CBasicNet
September 30th, 2002, 12:27 AM
Just found out 1 syntax error in my code.

MyHuman, MyCow and MyDog are object pointers so this is how you call the AnimalTakingLeak() function.

....
AnimalTakingLeak(*MyHuman);
.......
AnimalTakingLeak(*MyCow);
......
AnimalTakingLeak(*MyDog);

Paul McKenzie
September 30th, 2002, 01:59 AM
Originally posted by matu So then if we need to redefine the functions , then why not add standalone functions each time we need a new redefinition of the function.And add separate functions calls(as the redefinied functions will have a different name).
Here is where your idea is not going to work:

class Base
{
public:
// A function that performs a set of tasks in a specific order.
void DoTasks() { Initialize(); Start(); Cleanup(); }
virtual void Initialize() { }
virtual void Start() { }
virtual void Cleanup() { }
virtual ~Base() { }
};

class Derived : public Base
{
public:
// These will never be called!
void DerivedInitialize( );
void DerivedStart();
void DerivedCleanup();

// These will be called
void Initialize( );
void Start();
void Cleanup();
};

The base class has a function called DoTask() that performs the Initialize, Start, and Cleanup function, in that order. The Initialize, Start, and Cleanup functions *must* be done in that order, and DoTask enforces this rule. In a real-world environment, you have no control over Base's interface or rules -- you can't just pull out functions out of Base and replace them with your own.

Given the above scenario, when DoTask is called, how do you propose to add your own function so that DoTask calls it correctly? You have no choice but to provide implementations for the virtual functions. You can't create new member functions in your derived class called DerivedInitialized, DerivedStart, and DerivedCleanup, since none of them will ever get called. Add to that the possibility that the implementation of Base might be in an external object file and may not be inline (like the example above), so you have no access to the source code to Base. You have to use the implementation as-is.

Also, if you plan on deriving from a base class, your destructor should be virtual if at least one function is virtual, therefore the v-table must exist. I will also state that a class should not be derived from if it doesn't have a virtual destructor. If you do derive from such a class, you must be very careful in how the derived object is used.

But in general, if you have none of these (virtual functions, virtual destructor) in your base class, then it shouldn't be a base class, but a standalone class that should not be derived from. The STL is a perfect example of classes that do not have virtual functions or virtual destructors, and they are specifically not meant to be derived from because of these missing pieces. Instead, these classes are used as building blocks (i.e. members) within other classes. So the class you are now using should not be derived from (you can use it, but you will be in trouble if your code delete's a dynamically allocated derived object through the base class pointer).

We , On the contrary...Who is "we"?

Regards,

Paul McKenzie

matu
October 1st, 2002, 02:25 PM
Hi ,
I may have killed a common interface but i can think of the
following idea .
I may be wrong , i am sorry.
Regards,
Matu

class Base {
public :
void baseFunc()
{
Call whichever functions(non-virtual) we want as we do in C , in whichever order we want to do;(Stanalone functions like in C)
// i know that this kills the polymorphism

}
}

class Derived : public base {
public:
void DerivedFunc()
{
Call whichever functions(non-virtual) we want as we do in C , in
whichever order we want to do;These are standalone
// these functions could be redefinitions of the virtual functions
// in the normal case.
}
}


void main(void)
{
Base * BasePtr;
Base B;
Derived * DerivedPtr; //Extra Declerations because i didnt use Virtual Functions.
Derived D;

Base * BasePtr = &B;
BasePtr->baseFunc(); // will call the base class Virtual Function , which
// will inturn call (in whichever order)
//BaseInitialize(),
//BaseDoSomething(),
//BaseCleanUp()
// All the three functions are implemented standalone.

//In the second case........................

DerivedPtr = &D;
DerivedPtr->DerivedFunc();
// Derived function would then call the three functions
// DerivedInitialize , DerivedDoSomething , DerivedCleanUp (depending upon its needs)
// Derived class may as well call the BaseInitialize etc etc..
} // end of Main()


// I feel that i may Re-define functions interms of Virtual Functions Or as independent functions.
void BaseInitialize() { }
void BaseDoSomething() { }
void BaseCleanUp() { }

void DerivedInitialize() {}
void DerivedDoSomething() {}
void DerivedCleanUp() {}


// For general purposes of code reuse i have shown the derived class as inheriting from the Base Class

jfaust
October 1st, 2002, 04:53 PM
The whole point of polymorphism is that you deal with a base class pointer, and you don't care what it points to. Sure, you can take on the responsibility yourself and make all the decisions at compile time, but it won't be very extendible (extensible?).

A Shape class hierarchy is frowned on for various reasons, but I'm going to use it as an example anyway:


// an overly-simplified and contrived example:
class Shape
{
public:
virtual void Draw();
};

class Rectangle : public Shape
{
public:
virtual void Draw();
}

class Circle : public Shape
{
public:
virtual void Draw();
}

int main()
{
std::vector<Shape*> shapes;
shapes.push_back(new Rectangle());
shapes.push_back(new Circle());
shapes.push_back(new Rectangle());

for( std::vector<Shape*>::iterator iter = shapes.begin(); iter != shapes.end(); ++iter )
{
(*iter)->Draw(); // here's where polymorphism shines.
}

return 1;
}


Jeff