Programming Forums
User Name Password Register
 

RSS Feed
FORUM INDEX | TODAY'S POSTS | UNANSWERED THREADS | ADVANCED SEARCH

Reply
 
Thread Tools Display Modes
Old Apr 13th, 2006, 9:29 PM   #1
aznluvsmc
Hobbyist Programmer
 
Join Date: Aug 2005
Posts: 137
Rep Power: 3 aznluvsmc is on a distinguished road
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?
aznluvsmc is offline   Reply With Quote
Old Apr 13th, 2006, 11:44 PM   #2
grumpy
Programming Guru
 
grumpy's Avatar
 
Join Date: Jun 2005
Location: Adelaide, South Australia
Posts: 1,198
Rep Power: 5 grumpy is on a distinguished road
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.
grumpy is offline   Reply With Quote
Old Apr 14th, 2006, 2:30 AM   #3
InfoGeek
Professional Programmer
 
InfoGeek's Avatar
 
Join Date: Jun 2005
Location: India, The great.
Posts: 435
Rep Power: 4 InfoGeek is on a distinguished road
Quote:
Originally Posted by grumpy
Technically, a base class can declare a pure virtual function, and also [optionally] define it (provide an implementation).
In what situation should we define a pure virtual function?
__________________
PFO - My daily dose of technology.
InfoGeek is offline   Reply With Quote
Old Apr 14th, 2006, 2:42 AM   #4
grumpy
Programming Guru
 
grumpy's Avatar
 
Join Date: Jun 2005
Location: Adelaide, South Australia
Posts: 1,198
Rep Power: 5 grumpy is on a distinguished road
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.
grumpy is offline   Reply With Quote
Old Apr 14th, 2006, 2:56 AM   #5
InfoGeek
Professional Programmer
 
InfoGeek's Avatar
 
Join Date: Jun 2005
Location: India, The great.
Posts: 435
Rep Power: 4 InfoGeek is on a distinguished road
thanks grumpy.
__________________
PFO - My daily dose of technology.
InfoGeek is offline   Reply With Quote
Old Apr 14th, 2006, 9:02 AM   #6
Jessehk
The Oblivious One
 
Jessehk's Avatar
 
Join Date: May 2005
Location: Ontario, Canada
Posts: 630
Rep Power: 4 Jessehk is on a distinguished road
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!
Jessehk is offline   Reply With Quote
Old Apr 14th, 2006, 9:12 AM   #7
InfoGeek
Professional Programmer
 
InfoGeek's Avatar
 
Join Date: Jun 2005
Location: India, The great.
Posts: 435
Rep Power: 4 InfoGeek is on a distinguished road
Quote:
Why not simply declare a class for each Fish and include a unique definition of feed() for each one?
That's called polymorphism. One interface, multiple methods. You can have a pointer(pointing to base class fish) that may contain the address of an object of either fish and you don't need to bother yourself about which fish object it is. Simply call the feed() method and the fish will be apropriately feeded.
__________________
PFO - My daily dose of technology.
InfoGeek is offline   Reply With Quote
Old Apr 14th, 2006, 9:47 AM   #8
grumpy
Programming Guru
 
grumpy's Avatar
 
Join Date: Jun 2005
Location: Adelaide, South Australia
Posts: 1,198
Rep Power: 5 grumpy is on a distinguished road
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 Feed() is a virtual function of Fish, the FishFeedFrenzy() function doesn't need to know what each type of fish is; it just tells each fish to feed itself. If Feed() is a pure virtual function of Fish, then every derived class (Goldfish, Guppie, etc) is forced to implement appropriate feeding behaviour by overriding the Feed() member function.

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);
}
The first example, which makes use of polymorphism, is (I would suggest) somewhat easier to implement. It would also be easier to introduce new types of fish (by deriving from Fish) into the program without rewriting most of it. It would also be easier to reconfigure the program so it doesn't rely on having a Goldfish as the first fish put in the tank.
grumpy is offline   Reply With Quote
Old Apr 14th, 2006, 10:07 AM   #9
Jessehk
The Oblivious One
 
Jessehk's Avatar
 
Join Date: May 2005
Location: Ontario, Canada
Posts: 630
Rep Power: 4 Jessehk is on a distinguished road
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!
Jessehk is offline   Reply With Quote
Old Apr 14th, 2006, 2:48 PM   #10
aznluvsmc
Hobbyist Programmer
 
Join Date: Aug 2005
Posts: 137
Rep Power: 3 aznluvsmc is on a distinguished road
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?
aznluvsmc is offline   Reply With Quote
Reply

Bookmarks

« Previous Thread in Forum | Next Thread in Forum »

Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump




DaniWeb IT Discussion Community
All times are GMT -5. The time now is 3:13 AM.

Powered by vBulletin® Version 3.7.0, Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Copyright ©2007 DaniWeb® LLC