i thought i understood virtual functions, but

Started by
5 comments, last by MaulingMonkey 18 years, 8 months ago
Hello, I'm having trouble figuring out how virtual functions are working; plz help :) I have 2 classes (Base and Derived) with one virtual function called "printString". Derived overwrites Base's printString (as it should) - but if i store Derived in a vector, and call printString - it calls Base's printString!!?? Here is the source, it should work fine if you paste it into a new workspace Am i doing something wrong?



#include <vector>
#include <iostream>

using namespace std;

// Base class
class Base
{
public:
	Base(){};
	~Base(){};

	virtual void printString(void){ cout << "in parent \n"; };
};

// Derived class
class Derived : public Base
{
public:
	Derived(){};
	~Derived(){};

	virtual void printString(void){cout << "in child \n"; };
};

// Main
void main (void)
{
	Base *d = new Derived();

	d->printString();         // Prints in child

	// put in a vector
	vector <Base> v;
	v.push_back(*d);
	v[0].printString();       // Prints out parent, whats happening? :\
}

Any comments would be great Muncher
Advertisement
Virtual functions only work with pointers. You would need to have a Vector<Base *> rather than a Vector<Base>
Quote:Original post by Muncher
Hello,

I'm having trouble figuring out how virtual functions are working; plz help :)

I have 2 classes (Base and Derived) with one virtual function called "printString".
Derived overwrites Base's printString (as it should) - but if i store Derived in a vector, and call printString - it calls Base's printString!!??


Here is the source, it should work fine if you paste it into a new workspace
Am i doing something wrong?

*** Source Snippet Removed ***

Any comments would be great
Muncher


Try making your vector of type <Base*> - when you create a vector of type <classname>, it'll create a copy of that class - hence, it'll create a Base version of it here... if you store the pointer to the class (base or derived), the vtable pointers should remain intact and the runtime should be able to determine which classtype to call from.

(at least I think that's right! =)
That's because it's a vector specifically of type Base
If you wish to use abstract storage you'll need a vector of pointers to type base instead:

std::vector<Base*> vector;vector.push_back(new Derived());vector[0]->printString();delete vector[0];vector.pop();


Also another way to look @ why it can't work with a fixed type like that is that you're only allocating enough space for type Base - later derived types might be larger
Thus a go-between pointer is used to access the variable of abstract size (guarenteed to have a minimum of Base)

edit: LOL I'm sloooooww
_______________________________ ________ _____ ___ __ _`By offloading cognitive load to the computer, programmers are able to design more elegant systems' - Unununium OS regarding Python
yep, it works with <Base*> :)
thanks, that makes more sense now :)
Don't forget the virtual destructor.
Quote:Original post by Jingo
Don't forget the virtual destructor.


To expand on this:

The base class must have a virtual destructor so that the derived class has it's destructor correctly called. Failure to do so will cause only ~Base() to be called if delete is called on a pointer of type (Base *). Generally, if there's a chance the object will be destroyed through a base pointer, the destructor should be made virtual. It will not induce any extra overhead if other members of the class are virtual, so it's considered good practice by many to make any class with virtual members have a virtual destructor, just to be on the safe side. There's even talk of making this automatic in a future revision of the C++ standard...

Also, I might recommend using The Boost Librarys, specifically their shared_ptr smart pointer. It allows one to store pointers and thus polymorphic behavior just like normal raw pointers, but will automatically delete the object as well when all the pointers are destroyed so that one does not end up with memory leaks:

#include <boost/shared_ptr.hpp>#include <vector>void this_leaks( void ) {    std::vector< foo * > foos;    foos.push_back( new foo );    foos[0]->function();    //leak: when foos goes out of scope, the pointers will be destroyed but the object pointed to not.}void this_dosnt_leak( void ) {    std::vector< boost::shared_ptr< foo > > foos;    boost::shared_ptr< foo > my_foo( new foo );    foos.push_back( my_foo );    foos[0]->function();    //no leak: when both shared_ptrs go out of scope (my_foo and the one inside of foos) the object will be automatically destroyed.}

This topic is closed to new replies.

Advertisement