Go4Expert

Go4Expert (http://www.go4expert.com/)
-   C++ (http://www.go4expert.com/forums/cpp/)
-   -   Virtual Constructor in C++ (http://www.go4expert.com/forums/virtual-constructor-cpp-t23033/)

micsom_micsom 17Aug2010 15:27

Virtual Constructor in C++
 
I did a lot of googling and Binging but i have still not been able to get an answer which can satisfy me. This is regarding an age old doubt ..why cant constructors be virtual

following are the reasons i found:
1)The object doesnt exist in the memory when the constructor is called, even Lookup table is not ready...but so what, can't it just add the function pointer to the constructor in the static array it uses for implementing the lookup table...

2)But then we cannot take the address of the Constructor..but then how can we have a Virtual Destructor..we can't take its address either...

Any inputs which can explain me this in a better way will be appriciated.

Thanks
:shy::pleased::surprised:nice:;):happy:

somshekhar 18Aug2010 10:31

Re: Virtual Constructor in C++
 
Hi,
Well when we think of virtual functions we usually think of " The ability of an object to behave differently at run time" and "over riding the functionality of the base class".

Practically if we think this is possible only when fully fledged object is created not when the object is created, because a object can behave differently only when it is created not while being created. It would be absurd to think that object should start behaving differently while it is still in the creation process.

For example I have three hierarchical classes Men, Father And Son. Now lets assume that constructors have been defined virtually in all of the three classes then when i say

Men* pMen = new Son;
Now if we take the virtual function concept then it should call the son's constructor right.
For instance i make this kind of provision also then the basic property of the inheritance will go for a toss, because then i wont be able to access the base class functionality since they are not created.


If you want to understand some more, see the following example:

Code:

class Base
{
  public:
  Base()
{
myFunction();
}
virtual myFunction()
{
//some stuff
}
};

class derived : public
{
public:
derived()
{
 myfunction();
}
};

//Now i create an object of the derived class and see which function will be called
Base* b = new Derived;
Derived* der = new Derived;


somshekhar 18Aug2010 10:32

Re: Virtual Constructor in C++
 
Quote:

Originally Posted by somshekhar (Post 71658)
Hi,
Well when we think of virtual functions we usually think of " The ability of an object to behave differently at run time" and "over riding the functionality of the base class".

Practically if we think this is possible only when fully fledged object is created not when the object is created, because a object can behave differently only when it is created not while being created. It would be absurd to think that object should start behaving differently while it is still in the creation process.

For example I have three hierarchical classes Men, Father And Son. Now lets assume that constructors have been defined virtually in all of the three classes then when i say

Men* pMen = new Son;
Now if we take the virtual function concept then it should call the son's constructor right.
For instance i make this kind of provision also then the basic property of the inheritance will go for a toss, because then i wont be able to access the base class functionality since they are not created.


If you want to understand some more, see the following example:

Code:

class Base
{
  public:
  Base()
{
myFunction();
}
virtual myFunction()
{
//some stuff
}
};

class derived : public
{
public:
derived()
{
 myfunction();
}
virtual myFunction()
{
//some stuff
}
};

//Now i create an object of the derived class and see which function will be called.
Base* b = new Derived;
Derived* der = new Derived;


I guess this helps

xpi0t0s 18Aug2010 13:07

Re: Virtual Constructor in C++
 
Quote:

Originally Posted by micsom_micsom (Post 71625)
2)But then we cannot take the address of the Constructor..but then how can we have a Virtual Destructor..we can't take its address either...

You can have a virtual destructor because the object exists. This has nothing to do with whether or not you can get a pointer to a function. But to answer your question I will need to step back a bit and explain what virtual functions do.

The point of virtual functions is to make polymorphism work. If you have a set of objects, each of which is derived from the same base class, that set can be a set of pointers to the base class. You can then manipulate the entire set using pointers to the base class by using virtual functions.

Taking the common example of a Vehicle class, you might have a Service function which is implemented differently in each derived class. You want to be able to manipulate the collection via the base class so you define virtual Vehicle::Service() (maybe with code, or an empty function, or virtual void=0 it if you never want the base class to be created).

Motorbike::Service() would have a different implementation than Car::Service() and Lorry::Service() etc. But a set of Vehicles, e.g. Vehicles myvehs[20]; where myvehs[0] is a Motorbike, [1] is a Car, [2] is a Lorry etc (maybe I'm writing a program for a garage), could have all servicing done with a simple
Code:

for (int i=0; i<20; i++)
  myvehs[i]->Service();

So if myvehs[i] is a Motorbike, then what you're doing here is calling Vehicle::Service(), but the Vehicle vtable (virtual function table) is updated when you create a Motorbike object which means Vehicle::Service() actually calls Motorbike::Service().

This works fine when you have virtual destructors. We can delete all objects in the above array with
Code:

for (int i=0; i<20; i++)
  delete myvehs[i];

(although note that if Vehicle::~Vehicle() isn't virtual, this will only delete the Base part of all objects and this will leak memory, plus the objects won't be cleaned up properly because, e.g., Motorbike::~Motorbike() will not be invoked. For this reason it's *always* recommended to make destructors virtual, because most code is in perpetual development. The only time you wouldn't make a destructor virtual is when you know absolutely definitely and finally that for all time and in all circumstances your class will NEVER EVER be derived from (footnote #1)).



But your question is about virtual constructors. So let's have a look at some code. Because virtual functions are to do with polymorphism we're going to try to create a Motorbike() using a pointer to a Vehicle.

Code:

class Vehicle {...};
class Motorbike : public Vehicle {...};
class Lorry : public Vehicle {...};

void func()
{
  Vehicle *a;
  a=new Vehicle();
}

So this will create a Vehicle object and call Vehicle::Vehicle(). You want this constructor to be virtual. So what exactly is the compiler going to do here? Is it going to call the Vehicle constructor, or the Motorbike constructor, or the Lorry constructor? How would it know which you want?

OK, let's specify it by calling new Motorbike():

Code:

void func1()
{
  Vehicle *m;
  m=new Motorbike();
}

This is valid code, but there is no need for a virtual constructor here. Motorbike::Motorbike() will be invoked because you're calling "new Motorbike()".

The only place you would need a virtual constructor is if you're calling new on a base object and trying to create a derived object. But the compiler cannot possibly know what derived class to use.

Arguably if you have a virtual base class Base and only one derived class Derived, where new Base() is impossible due to virtual void someFunc()=0; you could make the case that new Base() should create a Derived and invoke Derived::Derived(), but this would be inconsistent with the general problem that where you have multiple derived classes the compiler would have no clue which derived class you want when you invoke "new Base()".

It would also create the problem that adding new code would break old unmodified code; suppose new Base did call new Derived on the grounds that there was no other choice, then you add new code that creates Derived2 from Base (thus introducing a choice), this would create an ambiguity that would then stop the old call to new Base working. That old code might be stable, debugged, finalised and unmodifiable without vast expenditure, and without touching it it's now been broken. This is a Very Bad Thing(TM).

#1 You could argue that you could make the destructor virtual when you add the derived class. This means you then need to modify old code. See the paragraph immediately above this footnote for why that's not a good idea.

somshekhar 18Aug2010 13:34

Re: Virtual Constructor in C++
 
Hi xpi,
That was pretty good information. Only reason we use virtual destructors is for proper destruction of the derived class object when the derived class object is assigned to the base pointer.

Well this wont be necessary if you cast the base pointer to the required derived object and call delete.

Thanks,
Som Shekhar

micsom_micsom 18Aug2010 14:07

Re: Virtual Constructor in C++
 
Thanks for your explanations ... They have been helpful in clearing my concepts..

:)

xpi0t0s 18Aug2010 20:46

Re: Virtual Constructor in C++
 
Quote:

Originally Posted by somshekhar (Post 71667)
Hi xpi,
That was pretty good information. Only reason we use virtual destructors is for proper destruction of the derived class object when the derived class object is assigned to the base pointer.

Well this wont be necessary if you cast the base pointer to the required derived object and call delete.

Thanks,
Som Shekhar

Well, yes. That's true for any virtual function. You don't have to use polymorphism if you don't want to, but it makes the code more complicated not to.

Code:

Vehicle *v=new Motorbike();
// if Vehicle::Service() is virtual, this
v->Service();
// is exactly the same as:
((Motorbike*)v)->Service();

delete ((Motorbike*)v); // no need for a virtual destructor

// and from my previous example
for (int i=0; i<20; i++)
{
  switch (some way of determining what object it is)
  {
  // (syntax may be incorrect)
  case MOTORBIKE: delete ((Motorbike)myvehs[i]); break;
  case LORRY: delete ((Lorry)myvehs[i]); break;
  }
}

Personally I'd make the destructors virtual and not use such horrible-looking code. Anyone reading the above code would think "why the hell don't they just use polymorphism".


All times are GMT +5.5. The time now is 17:48.