Lec11. Polymorphism and Virtual Functions
Lec11. Polymorphism and Virtual Functions
Polymorphism and
Virtual Functions
• Program must:
– Compute daily gross sales (which is sum of all the individual sales bills)
– Calculate largest/smallest sales of day and perhaps average sale for day
• All of these can be calculated from individual bills
– But many functions for computing bills will be added "later"!
• When different types of sales added!
15-6
//This is the file sale.cpp. Implementation for the class Sale.
#include <iostream>
15-8
Derived Class DiscountSale Defined
//This is the file discountsale.h.
//This is the interface for the class DiscountSale.
#ifndef DISCOUNTSALE_H
#define DISCOUNTSALE_H
#include "sale.h"
class DiscountSale : public Sale {
public:
DiscountSale( );
DiscountSale( double thePrice, double theDiscount);
//Discount is expressed as a percentage of the price.
//A negative discount is a price increase.
double getDiscount( ) const;
void setDiscount( double newDiscount);
double bill( ) const;
private: • Since bill was declared virtual in the base class, it is
double discount; automatically virtual in the derived class DiscountSale.
}; • You can add the modifier virtual to the declaration of
#endif //DISCOUNTSALE_H bill or omit it as here; in either case bill is virtual
in the class DiscountSale .
• (We prefer to include the word virtual in all virtual
function declarations for readability, even if it is not
required. We omitted it here to illustrate that it is not
required.)
// discountsale.cpp is the implementation for the class DiscountSale.
//The interface for the class DiscountSale is in discountsale.h.
#include "discountsale.h"
discountsale.cpp
DiscountSale::DiscountSale( ) : Sale( ), discount(0) {}
DiscountSale::DiscountSale(double thePrice, double theDiscount)
: Sale(thePrice), discount(theDiscount){}
double DiscountSale::getDiscount( ) const{
return discount;
}
void DiscountSale::setDiscount( double newDiscount){
discount = newDiscount;
}
double DiscountSale::bill( ) const{
double fraction = discount / 100;
return (1 - fraction) * getPrice( );
}
15-13
int main( ) {
Dog vdog;
Pet vpet;
vdog.name = "Tiny";
Pets.cpp
vdog.breed = "Great Dane";
vpet = vdog; //Derived objects can be assigned to objects of type Base But NOT the other
way!
cout << "The slicing problem:\n";
//vpet.breed; is illegal since class Pet has no member named breed.
vpet.print( );
cout << "Note that it was print from Pet that was invoked.\n";
cout << "The slicing problem defeated:\n";
The slicing problem:
Pet *ppet; name: Tiny
Dog *pdog; Note that it was print from Pet that was invoked.
pdog = new Dog; The slicing problem defeated:
pdog->name = "Tiny"; name: Tiny
pdog->breed = "Great Dane"; breed: Great Dane
ppet = pdog; name: Tiny
ppet->print( ); breed: Great Dane
pdog->print( );
//The following, which accesses member variables directly
//rather than via virtual functions, would produce an error:
//cout << "name: " << ppet->name << " breed: “ << ppet->breed << endl;
//It generates an error message saying class Pet has no member named breed.
return 0;
} 15-14
Using Classes Pet and Dog and slicing problem
vdog.name = "Tiny";
• Anything that "is a" dog "is a" pet: vdog.breed = "Great Dane";
vpet = vdog;
• Can assign values to parent-types, but not reverse
– A dog is a pet but a pet "is not a" dog (not necessarily)
• Slicing problem
– Notice value assigned to vpet "loses" its breed field!
• cout << vpet.breed; //Produces ERROR msg! slicing problem
• Slicing problem fix
– In C++, slicing problem is nuisance
• It still "is a" Great Dane named Tiny
• We’d like to refer to its breed even if it’s been treated as a Pet
– Can do so with pointers to dynamic variables
• Must use virtual member function: ppet->print();
– Calls print member function in Dog class!
– Because print() is virtual, C++ "waits" to see what object pointer ppet
is actually pointing to before "binding" call 15-15
Virtual Destructors
• Recall: destructors needed to de-allocate dynamically allocated
data
• Consider:
Base *pBase = new Derived;
…
delete pBase;
– Would call base class destructor even though pointing to Derived class
object!
– Making destructor virtual fixes this!
• Good policy for all destructors to be virtual
15-16
Casting
• Consider: Pet vpet;
Dog vdog;
…
vdog = static_cast<Dog>(vpet); //ILLEGAL!
– Static downcasting is not allowed: Casting from ancestor type to descendant
– Can’t cast a pet to be a dog,
– but upcasting is OK: From descendant type to ancestor type
vpet = vdog; // Legal!
vpet = static_cast<Pet>(vdog); //Also legal!