Sign in to follow this  
boxerfangg

Help on Virtual Methods

Recommended Posts

Hi everyone, So I've been reading my c++ book and have gotten to the part on virtual functions but I don't seem to understand the need for them. Don't they do the same as if you override a function? For example: Wouldn't this
class Mammal
{
 public:
 virtual void speak() { cout << "mammal speak"<<endl; }
}

class Duck : public Mammal
{
 public:
 void speak() { cout << "quack"<<endl; }
}

int main()
{
 Mammal* pDuck = new Duck;
 pDuck->speak();
 return 0;
}


be the same as this?
class Mammal
{
 public:
 void speak() { cout << "mammal speak"<<endl; }
}

class Duck : public Mammal
{
 public:
 void speak() { cout << "quack"<<endl; }
}

int main()
{
 Duck myDuck;
 myDuck.speak();
 return 0;
}


If anyone could clear this up for me it would be appreciated, Thanks. [Edited by - boxerfangg on February 14, 2010 8:50:31 AM]

Share this post


Link to post
Share on other sites
Yes, however, that assumes that you will always deal with the concrete type of Duck. If you use your original example that uses a base pointer (Mammal*) to a Duck instance, then the overridden function is not as useful as a virtual function.

You might not have any uses for this functionality at the moment, but later on you'll start to see endless uses for it.

For example, if you have a list of Mammal pointers, you can make them point to anything that inherits from Mammal - Ducks, Dogs, Cats, etc. Then you can call speak() on each Mammal pointer and the appropriate virtual function will run without you explicitly knowing whether it's a Duck or a Dog, etc.


std::vector<Mammal*> mammals;
mammals.push_back(new Duck());
mammals.push_back(new Dog());
mammals.push_back(new Cat());
for (int i = 0; i < mammals.size(); ++i)
mammals[i]->speak(); // call the appropriate speak() for each mammal

// BTW, don't forget to 'delete' each instance in the vector

Share this post


Link to post
Share on other sites
The difference is when you are storing pointers or reference to the base class. When you do so with a non-virtual function, the base class version is always called. With a virtual function, the correct function is called based on the runtime type of the value passed.

Most polymorphic types are stored or manipulated by pointers to the base class. The case you showed is highly unusual, and arguably bad style because the subclass method shadows the base class version, and there can be ambiguities about which implementation is called. After all, is there any case where you want a Duck to default to "mammal speak" because you have changed the code so that the duck is being passed to a function?

Share this post


Link to post
Share on other sites
@nullsquared Forgive me for not understanding, but wouldn't this do the same?


#include <iostream>
using namespace std;
int choice;

class Mammal
{
public:
void speak() { cout<<"Mammal Speak"<<endl; }
};

class Dog : public Mammal
{
public:
void speak() { cout << "Woof"<<endl; }
};

class Duck : public Mammal
{
public:
void speak() { cout << "Quack" <<endl; }
};

int main()
{
cout << "(1)Mammal (2)Dog (3)Duck";
cin >> choice;

switch(choice)
{
case 1: Mammal myMammal;
myMammal.speak();
break;

case 2: Dog myDog;
myDog.speak();
break;

case 3: Duck myDuck;
myDuck.speak();
break;

}
cin.get();
return 0;
}




Again sorry if I didn't understand what you were saying.

Share this post


Link to post
Share on other sites
Not really. In non-trivial examples you will typically have a semi-persistant container of (smart) pointers to the base class, and they will be manipulated over a period of time. You would not know the exact types involved at any particular point in time.

Its hard to demonstrate the benefits of polymorhism in small programs, because as you rightly point out, the equivalent non-polymorphic code is usually as easy or easier to understand.

Share this post


Link to post
Share on other sites
Quote:
Original post by boxerfangg
@nullsquared Forgive me for not understanding, but wouldn't this do the same?

*** Source Snippet Removed ***

Again sorry if I didn't understand what you were saying.


In that specific case, yes, it would.

The problem is that you can't always know ahead of time what the type will be, as demonstrated by my code example above. (Yes, in that specific example you will know that mammals[0] is a duck, mammals[1] is a dog, etc. but imagine that you ask the user for input on what type of mammal to create - now you can't be sure anymore).

Just keep doing things the way they seem to be most understandable for now, and as you write more code eventually you'll stumble upon a case where virtual functions are useful - experience is the best teacher [smile]

Share this post


Link to post
Share on other sites
Quote:
Original post by boxerfangg
@nullsquared Forgive me for not understanding, but wouldn't this do the same?

*** Source Snippet Removed ***

Again sorry if I didn't understand what you were saying.



Very true, but say you have 50 objects instead of 3. Now the switch statement has 50 cases whereas the polymorphic version doesn't even need to be re-written.

Share this post


Link to post
Share on other sites
Quote:
Original post by 14 Molgash Avenue
Quote:
Original post by boxerfangg
@nullsquared Forgive me for not understanding, but wouldn't this do the same?

*** Source Snippet Removed ***

Again sorry if I didn't understand what you were saying.



Very true, but say you have 50 objects instead of 3. Now the switch statement has 50 cases whereas the polymorphic version doesn't even need to be re-written.


Hmm, I haven't thought of it that way, Thanks.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this