What Is virtual?

Lines 26 and 27 of Listing 22.4 show both functions qualified with the keyword virtual. This is important when functions are to be overridden, because it is the only way to make sure that class polymorphism works properly.

When a function outside an object calls a function in the object, the compiler generates code to perform the function call. If a function does not have the virtual keyword, the compiler assumes that the caller will want to call the function as implemented in the class the caller has at hand. Unfortunately, if the caller has a reference to a superclass of the class actually used to instantiate the object, and the derived class has overridden the function being called, the caller will not use the derived class's improved version of the function.

The keyword virtual tells the compiler that a function will be overridden in derived classes. The compiler prepares for this by performing any calls to that function through a function pointer. It maintains that function pointer to always point to the implementation of the function in the deepest derived class that overrode it.

This is especially powerful because it even works for calls from functions in the superclass to other member functions in the superclass. That is, a function in the superclass will end up calling the implementation of the function from the derived class if that function has the virtual keyword and if the instantiated object is actually of the derived class. That is exactly what the implementation of aPersistentTapeExternalInterface depends on.

Listing 22.5 shows one relevant section of the implementation of the superclass (anExternalInterface).

Listing 22.5. GetOperatorChar() in Superclass anExternalInterface
 *1:    char anExternalInterface::GetOperatorChar(void)
 *2:    {
 *3:       char OperatorChar;
 *4:       cin >> OperatorChar;
 *5:       return OperatorChar;
 *6:    } ;
  7:
  8:    aRequest::anOperator
           anExternalInterface::GetOperator(void) const
  9:    {
*10:       return aRequest::CharacterAsOperator (GetOperatorChar());
 11:    } ;

Lines 1–6 are the superclass implementation of GetOperatorChar(). Line 10 calls GetOperatorChar(). But in Listing 22.6 from aPersistentTapeExternalInterface, GetOperatorChar() is overridden to first read from the tape file.


Listing 22.6. GetOperatorChar() in Derived Class aPersistentTapeExternalInterface
  1: char aPersistentTapeExternalInterface::GetOperatorChar
  2:    (void)
  3: {
  4:    if
  5:       (
  6:          myTapeSourceInputStream.is_open() &&
  7:          !myTapeSourceInputStream.eof()
  8:       )
  9:    {
 10:       char OperatorChar;
 11:       myTapeSourceInputStream >> OperatorChar;
 12:
 13:       if (OperatorChar == '') // The file is empty
 14:       {
 15:          myTapeSourceInputStream.close();
*16:          return anExternalInterface::GetOperatorChar();
 17:       }
 18:       else
 19:       {
 20:          return OperatorChar;
 21:       } ;
 22:    }
 23:    else
 24:    {
 25:       if (myTapeSourceInputStream.is_open())
 26:       {
 27:          myTapeSourceInputStream.close();
 28:       } ;
 29:
*30:       return anExternalInterface::GetOperatorChar();
 31:    } ;
 32: } ;

When, in the new implementation of main.cpp, main() gives Calculator aPersistentTapeExternalInterface, and Calculator calls myExternalInterface.NextRequest(), NextRequest() calls anExternalInterface::GetOperator() which, as a result of virtual, calls aPersistentTapeExternalInterface:: GetOperatorChar() rather than anExternalInterface:: GetOperatorChar(). This allows you to write only a very small amount of very specific code in aPersistentTapeExternalInterface and reuse most of the code in anExternalInterface. In fact, on lines 16 and 30 of Listing 22.6, aPersistentTapeExternalInterface even delegates any need for input from the console to the superclass function implementation.


..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.115.71