CS170 Lab: C++ Virtual Functions

(Click HERE for the importance of Virtual Functions.)

Highlights of this lab:

In this lab,  you will:

Note: To see the version of this lab WITHOUT pointers in the code, refer to this link.

Lab Exercise:


Click the little computer above for a detailed description.

NOTE: You do NOT have to hand in this lab exercise, but doing it will help you in your class work. There will be questions on the class quizzes and exams based on the lab material.

If you need help during the week, you are welcome to go to CL119 during Office Hours posted for lab instructors.


Virtual Functions and Polymorphism.

Before getting into the details of virtual functions, let's have a look at why you need such things at all!!

In C++ The Complete Reference, Schildt says that a class that contains a virtual function is called a polymorphic class. This begs the question "What is polymorphism?". Schildt gives a very nice example of this term. He says to consider a house with an ordinary thermostat to control temperature. You know the house has a furnace but you don't know what kind. If you want to set the temperature you simply set the thermostat to the desired temperature. You don't know (or likely really care at all) how the furnace accomplishes its task. It might be a gas furnace, an electric heater, solar power - you don't care. You leave it up to the furnace to do its own task in a manner appropriate to that device.

How does this relate to polymorphism? Well, an analogy to computer programming is the concept of push/pop operations on various kinds of stacks.

The idea behind all this is to simplify the life of the operator - the programmer.

Declaring a Virtual Function in C++.

A virtual function is declared in a base class of a program and can then be redefined in each derived class. The declaration in the base class acts as a kind of template which can be enhanced by each derived class.

Here is a simple example.

#include <iostream>
using namespace std;

/*-------------------------------------------------
  Class Name:	base_class
-------------------------------------------------*/
class base_class {

		// The keyword VIRTUAL must be used here!!
public:		
   virtual void printit() {
       cout << "Print from base class\n";
       } 
}; // end base_class


/*-------------------------------------------------
  Class Name:	first_class
-------------------------------------------------*/
class first_class : public base_class  {
public:
    void printit() {
	cout << "Print from first class\n";
	} 
}; // end first_class


/**************************************************
   Name:	main 
**************************************************/
void main() {

base_class *base_ptr;	// declare a pointer for the base class
base_class base;	// declare an object of the base class

base_ptr = &base;	// point to the new object
base_ptr->printit();	// execute its virtual function

first_class first1;	// declare an object of the derived class

base_ptr = &first1;	// point to the new object
base_ptr->printit();	// execute its virtual function

} // end main function

This is what you would see if you ran that program:
	Print from base class

	Print from first class

A few notes about virtual functions:

Virtual Functions and Inheritance

/* Filename: pub/class/170/ftp/cpp/Vfuncs/ex2-wptrs.cpp   */

#include <iostream>
     using namespace std;


     /*-------------------------------------------------
       Class Name:   base_class
     -------------------------------------------------*/
     class base_class {

                     // The keyword VIRTUAL must be used here!!
     public:
        virtual void printit() {
             cout << endl << "Print from base class" << endl;
            }
     }; // end base_class


     /*-------------------------------------------------
       Class Name:   first_class
     -------------------------------------------------*/
     class first_class : public base_class  {
     public:
         void printit() {
             cout << endl << "Print from first class" << endl;
             }
     }; // end first_class

     /*-------------------------------------------------
       Class Name:   second_class
     -------------------------------------------------*/
     class second_class : public base_class  {
     }; // end second_class

     /*-------------------------------------------------
       Class Name:   coach_class
     -------------------------------------------------*/
     class coach_class : public base_class  {
     public:
         void printit() {
             cout << endl << "Print from coach class" << endl;
             }
     }; // end coach_class

     /*-------------------------------------------------
       Class Name:   tourist_class
     -------------------------------------------------*/
     class tourist_class : public coach_class  {
     }; // end tourist_class





/**************************************************
     Name:        main
**************************************************/
void main() {

     base_class *base_ptr;   // declare a pointer for the base class
     base_class base;        // declare an object of the base class

     base_ptr = &base;         // point to the new object
     base_ptr->printit();    // execute its virtual function

     first_class first1;     // declare an object of the derived class

     base_ptr = &first1;       // point to the new object
     base_ptr->printit();    // execute its virtual function

     second_class second1;     // declare an object for second
     base_ptr = &second1;
     base_ptr->printit();

     coach_class coach1;     // declare an object for coach
     base_ptr = &coach1;
     base_ptr->printit();

     tourist_class tour1;     // declare an object for tourist
     base_ptr = &tour1;
     base_ptr->printit();

} // end main function

Here is what happens when that program is run:

mercury[20]% ex2

Print from base class

Print from first class

Print from base class

Print from coach class

Print from coach class
mercury[21]%
Examine the program and the output carefully to understand how it works.
Line PrintedSource of printing
Print from base class This is the base class virtual function.
Print from first class This is the first class virtual function.
Print from base class This is the second class virtual function.
But since there is no virtual function defined in "second class", the definition in the predecessor function is used. i.e. The base function.
Print from coach class This is the coach class virtual function.
Print from coach class This is the tourist class virtual function.
But since there is no virtual function defined in "tourist class", the definition in the predecessor function is used. In this case, the predecessor class is not "base" class, but "coach" class.

If you would like to experiment with that program you can copy it from Mercury's ftp site. There are some comments in the program suggesting how you might modify the classes. To copy the program use the Hercules command-line ftp program from Mercury's anonymous ftp site.

The path:	pub/class/170/ftp/cpp/Vfuncs

The file:      ex2-wptrs.cpp

Pure Virtual Functions

As you've seen in the previous example, if a derived class does not override a virtual function, it is the function definition in a predecessor class that is used. If the immediate predecessor has not overriden its predecessor, then the one before that is referenced to find a function definition. This search could continue (if predecessors don't override the virtual function) until, ultimately, it is the function definition in the base class that is used.

However, in some cases, it does not make sense for the base class to define the virtual function at all. The actual method should really be implemented in each one of the descendent classes. The base function should simply provide a kind of placeholder for the virtual function and leave it up to the descendents to specify the individual methods.

A virtual function that is declared but not defined in a base class is referred to as a pure virtual function. Here is the general syntax for declaring a pure virtual function:

virtual type function_name(parameter_list)=0;
Now when the base class uses a PURE virtual function, each descendent must override that function, or you will get a compile error. This makes sense, because the function has to be defined somewhere.

Here's another definition for you:
If a class contains a pure virtual function, that class is called an abstract class.
Because there is no definition for the function, you cannot create an object of that class. You can however, declare pointers to it.

Think of an abstract class as a general class that lays the foundation for descendent classes that define their own methods. This is the heart of polymorphism - let each class define its own operation.

The lab exercise in the next section illustrates these concepts. Study the C++ program for the exercise carefully, and be sure to read the comments.



Lab Exercise -- C++ Virtual Functions

As stated in the first lab, there is nothing to hand in for lab exercises. There will be question on lab material in class tests. Also, you will learn the lessons presented in the lab material more easily when you perform the lab exercise.


This page last modified:
Friday, 21-Aug-2020 15:23:39 CST
Accessed     times.

CS Dept Home Page
CS Dept Class Files
CS170 Class Files


Copyright: Department of Computer Science, University of Regina.