home account info subscribe login search My ITKnowledge FAQ/help site map contact us


 
Brief Full
 Advanced
      Search
 Search Tips
To access the contents, click the chapter and section titles.

C++ in Plain English
(Publisher: IDG Books Worldwide, Inc.)
Author(s): Brian Overland
ISBN: 1558284729
Publication Date: 04/01/96

Bookmark It

Search this book:
 
Previous Table of Contents Next


Admittedly, this example is not very realistic. There isn't much need to override the cpy implementation except for testing purposes. And because cpy is not likely to be overridden, there isn't much point in its being virtual.

The next section presents a couple of member functions that are designed to be overridden and so are perfect candidates to be made virtual.

Menu Command Example

A simple scenario for object-oriented design is a program menuing system. The program displays a series of menus from which the user makes a selection. The program then responds by carrying out the indicated command.

This system is easy enough to implement using traditional, procedure-oriented programming techniques, but object design offers some advantages. If each menu command is coded as a separate object, then the individual menu commands can manage themselves to a certain extent. This arrangement removes the need for the main program to maintain a look-up table or switch statement, which would have to be continually revised as new commands were added.

The result is a program that is easier to write, less error-prone, and much more flexible, as we'll see.

Declaring and Defining the Base Class

The base class, CMenu, is a prototype for all the menu commands. The program doesn't instantiate this class. In other words, it doesn't define any object of class CMenu; it defines only classes derived from CMenu.

CMenu is a simple class. It contains only two members, as you can see from the class declaration in CMENU.H.

// CMENU.H - declaration of the CMenu base class

class CMenu {
public:
    char title[81];
    virtual void Do_Command(void) = 0;
};

This example introduces a new bit of syntax. The characters =0 at the end of the Do_Command declaration indicate that it is a pure virtual function. This is the same as any other virtual function except that it has no implementation in the base class; it is implemented only in classes derived from CMenu. The Do_Command function is not defined at all in this class; Do_Command becomes a kind of placeholder for functions to be defined later.

I'll discuss these strange functions further in the section “Functions with No Implementation (Pure Virtual Functions),” later in this chapter.

Each menu-command object implements its own version of Do_Command. Then all the main program does to execute a command is to call Do_Command for the selected object. In effect, calling Do_Command sends a message to the object saying, “Execute your command.”

Declaring and Defining the Menu Objects

Each menu command is represented as a CMenu object that implements the CMenu function Do_Command. This example program uses three menu commands. When printed, they appear as follows:

  1. Sound a bell.
  2. Print a wise saying.
  3. Add two numbers.

The declarations for all the menu commands are identical except for the class name. Each declaration must declare Do_Command to indicate that it is overriding the definition in the base class.

// CMDS.CPP - Defines and initializes menu commands

#include <stdio.h>
#include “menu.h”

class CMenuBell : public Cmenu {
   void Do_Command(void);
};

class CMenuSaying : public CMenu {
   void Do_Command(void);
};

class CMenuAdd : public CMenu {
   void Do_Command(void);
};

Each of the Do_Command implementations carries out an actual command. These functions can be of any length. Some of them are relatively shorter, and others are longer.

CMenuBell::Do_Command(void) {
   putc('\007');
}

CMenuSaying::Do_Command(void) {
    puts(“If you know the meaning of the universe,”);
    puts(“Make the sound of one hand clapping.”);
}

CMenuAdd::Do_Command(int n) {
    double    x, y;

printf(“Enter a number: ”);
scanf(“%lf”, &x);
printf(“Enter a number: ”);
scanf(“%lf”, &y);
printf(“The total of the numbers is %f.”, x + y);
}

Finally, the CMDS.CPP file declares an array of pointers to CMenu objects, an integer storing the number of commands, and an initialization function. All these are used by the main program.

int num_commands;
CMenu *commands[20];

void Init_Commands(void) {
   commands[0] = new CMenuBell;
   strcpy(commands[0]->title, “Sound a bell.”);
   commands[1] = new CMenuSaying;
   strcpy(commands[1]->title, “Print a wise saying.”);
   commands[2] = new CMenuAdd;
   strcpy(commands[2]->title, “Add two numbers.”);
   num_commands = 3;
}

Using the Objects

The main program is now almost trivial to write, because almost all the work is being done by the menu objects. This is consistent with the basic theme of object orientation, which tends to decentralize decision-making and resources in favor of objects rather than the main program loop.

The main program must first gain access to the two pieces of global data—num_commands and the commands array—by declaring them with the extern keyword. This keyword is necessary if you want to use variables declared in another module.

// MAIN.CPP - Uses the menu objects to manage a menu

#include <stdio.h>
#include “menu.h”

extern int num_commands;
extern CMenu *commands[];

The main function first calls Init_Commands to initialize the menu. Then it sets up a loop that displays the menu and responds to commands. One additional command, Exit, enables the loop to end.

void main(void) {
   int i, sel;

   Init_Commands();
   do {
        puts (“\nMENU: \n”);
        for (i = 0; i < num_commands; i++)
              printf(“%d. %s”, i+1, commands[0]->title);
        printf(“\nEnter a selection: ”);
        scanf(“%d”, &sel);
        if (sel >= 0 && sel <= num_commands)
               commands[sel]->Do_Command();
   } while (sel <= num_commands);
}

This is the entire program. It shows the effect of the virtual keyword clearly. Suppose that the program were the same except that the Do_Command was not declared virtual. In that case, the following line of code would always execute the same command no matter what the user's selection was:

commands[sel]->Do_Command();

If Do_Command were not virtual, then, during compilation, C++ would resolve the function call based on the class that commands[sel] points to. The variable commands is an array of pointers to CMenu objects. Because Do_Command isn't virtual, the compiler would resolve this as a call to CMenu::Do_Command.

In this case, CMenu doesn't provide any implementation of Do_Command at all, because in CMenu Do_Command is a pure virtual function. But if Do_Command were not virtual, the base class would have to provide some implementation, which we could call the default implementation. Without virtual functions, the main program would always end up executing this default implementation. The actual menu commands would never execute.


Previous Table of Contents Next
[an error occurred while processing this directive]

Products |  Contact Us |  About Us |  Privacy  |  Ad Info  |  Home

Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc.
All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.