Virtual Functions and Abstract Classes

As discussed previously, OOP is based upon the principle of polymorphism. Polymorphism is supported in C++ both at compile time and at run-time. Operator overloading and function overloading are examples of compile time polymorphism. In addition, C++ has run-time polymorphism that is based upon virtual functions that are discussed in this lecture.

When class B is derived from class A, the class B may have a function show() with the same name as a function show() for the base class A. An object of class B may refer to either. The function show() from class B hides the function from the base class. This can be overridden by using the scope reference operator (::). The question arises as to what happens when several classes are derived from a class A and some of these classes have a function show().

The next question that arises is what if pointers to the base are used to point to objects of the derived class and what if the base and the derived classes all have functions of the same name, then how can we access these functions using pointers to the base. This is done at run-time by defining in the base class: virtual functions.

To define a function as a virtual function, the keyword virtual must precede the definition of the function as in the following:

image from book

 Virtual void show() {.... } 

image from book

A virtual function in the base and its complement in the derived classes must have the same signature and output. Therefore they are not overloaded because overloaded functions would require that they have different signatures.

If a class is derived from a base class that has a virtual function, then if the derived class has a function with the same name as the virtual function in the base class, the derived class' function is also a virtual function whether the word virtual appears in the derived class or not.

A class that contains a virtual function or any class that is derived from such a class is called a polymorphic class. Therefore a single polymorphic class generates a family of polymorphic classes.

See examples lotdats1.cpp and lotdats2.cpp. Notice the only difference between these two programs is the existence of the keyword virtual. This sole difference makes the program lotsdats2.cpp larger than the program lotsdats1.cpp. (When I compiled these two programs with Visual Studio .NET 2005, the resulting executable appears to be the same size when viewed in Windows XP. However when compiled with previous versions of C++ and previous versions of Windows, they were of different size which may only be a few bytes different.) Virtual functions are built on the concept of late binding that was discussed above. Therefore additional memory is required to create the table needed to store the addresses of the respective functions.

Suppose that Date is a base class with three derived classes: Invoice, PurchaseOrder and ShippingSlip as in the example: lotsdat3.cpp. Suppose that further an array of 3 pointers to Date was defined and that each of the pointers was assigned to point to an object of one of the derived classes as listed below:

image from book

 Invoice invoice1234; PurchaseOrder purchaseOrder1234; ShippingSlip shippingSlip1234; date *thePointer[3]; char *pointerWord[ ]={ "The invoice date was ", "The purchase order date was ",                        "The shipping slip date was "}; thePointer[0] = &invoice1234; thePointer[1] = &purchaseOrder1234; thePointer[2] = &shippingSlip1234; // Notice that the array of pointers should point to a // date object. However since Invoice, PurchaseOrder and // ShippingSlip are derived from Date, their objects are // permitted to place their respective addresses in the // pointers. invoice1234.get_invoice(); purchaseOrder1234.get_po(); shippingSlip1234.get_ss();;; cout << endl << "Shipping slip date is ";; cout << endl << endl       << "Notice that the output above is different than below."       << endl << endl; // // Notice that even though the pointer array thePointer[ ] is // pointing to objects of the classes: Invoice, // PurchaseOrder and ShippingSlip, the output below deals with // show() for the base class instead. // for(int index=0;index < 3;++index) {    cout << endl << pointerWord [index] << endl;    thePointer[index] -> show(); } 

image from book

 Note:  In this program the output for the final for() loop would be the show() method of the base class in each case.

What if you wanted instead of accessing the show( ) method of the base, to access the show( ) method for the respective derived class. The answer is to define the base class' method as a virtual function. Notice that the same classes used in lotsdat3.cpp are in lotsdat4.cpp except the keyword virtual is added to the definition of the base method show( ). Notice that the output of these two programs is entirely different.

Suppose that the class C is derived from the class B that in turn is derived from the polymorphic class A. Suppose that B has a function with the same name as the virtual function show( ) in A but C does not have such a function. The question is then how do pointers to A affect an object of the class C. Now since B has a copy of show( ) and A has a copy of show( ) that is virtual, the pointer ptr1 that points to an object of the class B will point to the show( ) of the class B. However what would happen in the case of an object for the class C? Suppose thePointer is a pointer to A but has the address of an object of C, then thePointer-> show( ) will refer to the B member function show( ) since C has no such function. See lotsdat7.cpp.

Since any class may become a base class later and there may be a need to have functions in the derived class with the same name as the ones in the base class, it might be desirable to define member functions of a class to be virtual functions so that if the class is defined as the base class in some inheritance, the virtual property would already be there.

There are times when the only property that a function in the base class needs is the fact that it is a virtual function. In this case the virtual function can be defined as an abstract virtual function. This is accomplished by the following type of definition:

image from book

 virtual void show()=0; 

image from book

The 0 plays no role except to inform the compiler that the function is an abstract virtual function. Without the =0, the function show( ) above would just be a function that does nothing. A class that contains one or more abstract virtual functions is called an abstract class. Abstract classes may not have objects!!!! See lotsdat8.cpp and notice that it does not compile since it is attempting to define an object of the abstract class A.

See lotsdat5.cpp. The only difference between lotsdat5.cpp and lotsdat4.cpp is that the virtual function in the base class in lotsdat5.cpp is an abstract virtual function.

If a derived class has a pointer as an attribute, then the derived class should have a destructor. In this case the destructors should be virtual to ensure that derived objects call the derived class destructor when passed to other functions. Otherwise the destructor of the base class may be called and not the destructor of the derived class thereby leaving memory open after the program terminates. While a class' destructors may be virtual, the constructors can not be virtual.

A virtual function remains a virtual function in succeeding derivations.

image from book

That is if BaseA has a virtual function show( ), and class DerivedA is derived from BaseA and DerivedB is derived from DerivedA, then show( ) will have the same properties with respect to DerivedB as it does with respect to DerivedA. Further any classes derived from an abstract base class, must have a function with the same name as the abstract virtual function or the program should not compile. See lotsdat10.cpp.

While virtual functions are a part of C++, their use is mainly in large and complex programs and not the type of programs encountered in these lectures.

Intermediate Business Programming with C++
Intermediate Business Programming with C++
ISBN: 738453099
Year: 2007
Pages: 142 © 2008-2017.
If you may any questions please contact us: