![]() |
|
![]() |
|
|
Thread Tools | Display Modes |
|
|
#1 |
|
Hobbyist Programmer
Join Date: Aug 2005
Posts: 137
Rep Power: 3
![]() |
What is the point of pure virtual functions?
I was reading up on pure virtual functions in C++ Primer Plus 5th edition and I'm still a little unclear as to what their purpose is. From my understanding, they are used in abstract base classes so that an object cannot directly be created from the class but rather other classes must derive from it. In this case, any function declared as pure virtual using "=0" MUST be defined within the derived classes.
Is this essentially what pure virtual functions are ALL about? |
|
|
|
|
|
#2 |
|
Programming Guru
![]() Join Date: Jun 2005
Location: Adelaide, South Australia
Posts: 1,198
Rep Power: 5
![]() |
Very loosely, yes. You've mixed up a couple of terms.
If you wish to create a set of classes that are all derived from a common base, but don't wish to instantiate the base class, give it at least one pure virtual function. For example, if your base class is Fish, and derived classes represent specific species of fish, it does not make sense to instantiate a Fish. The other purpose of pure virtual functions is to force derived classes to specialise particular behaviours offered by the base class. All a user of the class needs is a pointer (or reference) to the base class, and it can call a member function and know that the behaviour for the actual (instantiated) class will occur. Using my Fish example, one candidate for a pure virtual function would be named Feed(). All types of fish will have some type of feeding behaviour, but it doesn't necessarily make sense for a representation of a generic Fish to to be specific about what that behaviour is. Technically, a base class can declare a pure virtual function, and also [optionally] define it (provide an implementation). A derived class, unless it overrides that inherited function (i.e. declares it) cannot be instantiated. As a rough rule, if a derived class overrides an inherited pure virtual function, it must also provide a definition (i.e. provide an implementation of it). The compiler won't complain about a lack of definition of an overridden virtual function, but the linker probably will (with the result that it is not possible to build the overall application). Destructors can also be pure virtual: a simple way to ensure a base class cannot be instantiated even if it has no other pure virtual functions. |
|
|
|
|
|
#3 | |
|
Professional Programmer
Join Date: Jun 2005
Location: India, The great.
Posts: 435
Rep Power: 4
![]() |
Quote:
__________________
PFO - My daily dose of technology. |
|
|
|
|
|
|
#4 |
|
Programming Guru
![]() Join Date: Jun 2005
Location: Adelaide, South Australia
Posts: 1,198
Rep Power: 5
![]() |
A pure virtual destructor should always be defined, as the base class destructor will always be implicitly invoked when an object in the hierarchy is destroyed. If that pure virtual destructor is not defined, the typical result will be a linker error.
|
|
|
|
|
|
#5 |
|
Professional Programmer
Join Date: Jun 2005
Location: India, The great.
Posts: 435
Rep Power: 4
![]() |
thanks grumpy.
__________________
PFO - My daily dose of technology. |
|
|
|
|
|
#6 |
|
The Oblivious One
Join Date: May 2005
Location: Ontario, Canada
Posts: 630
Rep Power: 4
![]() |
Grumpy: These useful, informative explanations are very helpful. Thanks
![]() Quick question: If the declaration of a pure virtual function in an ABC simply means that the method will be defined in a derived class, what is the point? Why not simply declare a class for each Fish and include a unique definition of feed() for each one?
__________________
Dr. Zoidberg: [ecstatic] I'm going to a movie... with FRIENDS! |
|
|
|
|
|
#7 | |
|
Professional Programmer
Join Date: Jun 2005
Location: India, The great.
Posts: 435
Rep Power: 4
![]() |
Quote:
__________________
PFO - My daily dose of technology. |
|
|
|
|
|
|
#8 |
|
Programming Guru
![]() Join Date: Jun 2005
Location: Adelaide, South Australia
Posts: 1,198
Rep Power: 5
![]() |
To expand on InfoGeek's response, Jessehk, let's say you want to maintain a list of two fish in a tank. You might do this via an array of pointers to fish (as each fish may be a different kind).
// declaration of Fish and derived classes
void FishFeedFrenzy(Fish **list, int nfish)
{
for (int i = 0; i < nfish; ++i)
list[i]->Feed();
}
int main()
{
Fish *fishies[2];
fishies[0] = new GoldFish;
fishies[1] = new Catfish;
drop_food_in_tank();
FishFeedFrenzy(fishies, 2);
// kill the goldfish and replace it with a Guppie
// the following code does this if Fish has a virtual destructor
delete fishies[0];
fishies[0] = new Guppie;
drop_food_in_tank();
FishFeedFrenzy(fishies, 2);
}If Goldfish, Guppy, etc are not derived from a common base class, the code would be much more complicated. For example; // declaration of Fish and derived classes
void FishFeedFrenzy(void **list, int nfish)
{
// note our implementation is more complicated.
// This would be required if
// 1) Feed() is not a virtual member of Fish OR
// 2) Specific types of fish are not derived from the Fish class
for (int i = 0; i < nfish; ++i)
{
// Note: the implementations of IsGoldfish() and similar functions below
// will be non-trivial, and I won't suggest a way of implementing them
if (IsGoldfish(list[i]))
((Goldfish *)list[i])->Feed();
else if (IsGuppy(list[i]))
((Guppy *)list[i])->Feed();
else
// similar entries to be maintained for all fish types
}
}
int main()
{
void *fishies[2];
fishies[0] = new GoldFish;
fishies[1] = new Catfish;
drop_food_in_tank();
FishFeedFrenzy(fishies, 2);
// kill the goldfish and replace it with a Guppie
// the process of destroying a fish is also more involved.
if (IsGoldFish(fishies[0]) delete ((Goldfish *)fishies[0]);
fishies[0] = new Guppie;
drop_food_in_tank();
FishFeedFrenzy(fishies, 2);
} |
|
|
|
|
|
#9 |
|
The Oblivious One
Join Date: May 2005
Location: Ontario, Canada
Posts: 630
Rep Power: 4
![]() |
I get it now. Thank you for taking the time to respond, Grumpy and InfoGeek.
![]()
__________________
Dr. Zoidberg: [ecstatic] I'm going to a movie... with FRIENDS! |
|
|
|
|
|
#10 |
|
Hobbyist Programmer
Join Date: Aug 2005
Posts: 137
Rep Power: 3
![]() |
Thanks for the response. So to take your Fish class example, if the Fish base class specified two methods called Feed() as a pure virtual function and Swim() as just a regular function with a definition (we'll assume all derived fishes swim the same way) then a derived class of GoldFish and Salmon can just use the Swim() function but MUST redefine the Feed() function for their particular type?
|
|
|
|
![]() |
| Bookmarks |
| Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
| Thread Tools | |
| Display Modes | |
|
|