Today’s Objectives 10-Jul-2006 Announcements Quiz #3 Turn in HW #3 Turn in Bonus Lab 5 Quiz #3 Object-Oriented Programming: Polymorphism (Ch. 13) Review from last week’s demo Polymorphism Virtual functions Abstract base classes Late binding Downcasting Virtual destructors Review of function overloading Library Demo (Continued)
Please clear your desks and log off from the computer Quiz #3 Closed book 20 minutes Please clear your desks and log off from the computer
Quick Review Last week’s demo
From Last Week’s Demo Object-Oriented Programming: Polymorphism Public inheritance An object of a derived class “is-a” object of the base class The derived class object automatically has all the members that are in the base class //Derived class objects can use base class functions cout << journal.getTitle(); A derived-class object can be assigned to a base-class object Journal journal("Dr. Dobbs","2004"); LibraryItem item = journal; //okay A derived-class object can be used as an argument when the function parameter is declared as a base-class object void checkOut( LibraryItem& item ){ /*...*/ } checkOut(journal); //function call is okay
From Last Week’s Demo Object-Oriented Programming: Polymorphism A derived class can redefine or “override” a function that it inherited from the base class class Journal : public LibraryItem { public: string toString(){ return LibraryItem::toString() + ", " + year; } //... Base class function Overrides the base class function
From Last Week’s Demo Object-Oriented Programming: Polymorphism When an object of a derived class is assigned to an object of the base class, any members in the derived class that are not in the base class are hidden, including redefined versions of the member functions Journal journal("Dr. Dobbs, 2004"); cout << journal.toString(); //prints "Dr. Dobbs, 2004" LibraryItem item = journal; cout << item.toString(); //prints "Dr. Dobbs" prints "Dr. Dobbs" prints "Dr. Dobbs, 2004"
Object-Oriented Programming: Polymorphism Chapter 13
Three Principle Features of Object-Oriented Programming Object-Oriented Programming: Polymorphism Three Principle Features of Object-Oriented Programming Encapsulation Inheritance Polymorphism
Object-Oriented Programming: Polymorphism (Deitel, 686; Budd) Means that multiple meanings can be associated with one variable name We can use a base-class pointer as if it is pointing to an object of a derived class For example, a RentalItem pointer can be used as either a pointer to a Movie object or a pointer to a Game object Features that make it possible Virtual member functions Late binding (also known as “dynamic binding”)
Using a Base-Class Pointer to Point to a Derived-Class Object Object-Oriented Programming: Polymorphism (Deitel, 686) Using a Base-Class Pointer to Point to a Derived-Class Object A base-class pointer can be used to point to a derived-class object If we don’t enable polymorphism by using virtual member functions in the base class, the redefined member functions in the derived class are hidden Journal *pJournal = new Journal("Dr. Dobbs","2004"); LibraryItem *pItem; pItem = pJournal; cout << pItem->toString(); Making a base-class pointer point to a derived-class object (called “upcasting”) The base-class pointer uses the base-class version of toString() and prints "Dr. Dobbs"
Virtual Member Function Object-Oriented Programming: Polymorphism (Deitel, 701–708) Virtual Member Function class LibraryItem { public: virtual string toString(){ return title; } //... In the base class, “virtual” is placed before the declaration of the member function It is not necessary to put “virtual” before the declaration of the function in the derived class, but it is good practice to do so The derived class usually redefines a virtual function (called “overriding”)
Using Virtual Functions with a Base-Class Pointer Object-Oriented Programming: Polymorphism (Deitel, 701–708; Eckel) Using Virtual Functions with a Base-Class Pointer When a base-class pointer points to a derived-class object and it is used to invoke a virtual function, then the version of the virtual function in the derived class is invoked Journal *pJournal = new Journal("Dr. Dobbs","2004"); LibraryItem *pItem; pItem = pJournal; cout << pItem->toString() << endl; Upcasting toString() is defined as a virtual function inside the base class The base-class pointer uses the base-class version of toString() and prints "Dr. Dobbs, 2004"
Object-Oriented Programming: Polymorphism (Deitel, 701–708) Virtual Functions If a member function is virtual, when it is invoked by a base-class pointer, the type of the object that is pointed to determines which version of the function to use class LibraryItem { public: virtual string toString(){ return title; } //...
Advantage of Polymorphism Object-Oriented Programming: Polymorphism (Deitel, 686; Budd) Advantage of Polymorphism If we write programs that use base-class pointers to refer to derived-class objects, then we don’t need to know in advance which derived-class objects we need For example, the Gigaplex program keeps track of a list of both Movies and Games by using polymorphism. Later, we can easily add another kind of rental item to the list, such as Music. Extensibility – Our programs can be written for a general case so that we do not have to anticipate all the specific uses
Array of Base-Class Pointers Object-Oriented Programming: Polymorphism Array of Base-Class Pointers We can use an array of base-class pointers to store derived-class objects When a virtual function is invoked, if the pointer has the address of a derived-class object then the derived class version of the function will be used const int CAP = 256; int sz = 0; LibraryItem **myData = new LibraryItem*[CAP]; myData[sz] = new Book("C++ How to Program",5); sz++; myData[sz] = new Journal("Dr. Dobbs","2004"); cout << "\nPrinting the array:" << endl; for( int i=0; i<sz; ++i ){ cout << myData[i]->toString() << endl; } Create an array of base-class pointers Put derived-class pointers in the array Output can be different for each pointer in the array
A Derived-Class Argument Object-Oriented Programming: Polymorphism A Derived-Class Argument We can use a derived-class pointer as an argument in a function call when the function’s parameter is defined as a base-class pointer As long as the functions in the base class are virtual, the derived-class versions can be invoked with the base-class pointer void function( LibraryItem *item ){ cout << "In function: " << item->toString() << endl; } int main(){ Journal *pJournal = new Journal("Dr. Dobbs","2004"); function( pJournal ); Base-class pointer used as a parameter A derived-class pointer is used as an argument
A Derived-Class Argument Object-Oriented Programming: Polymorphism A Derived-Class Argument Also, we can use a derived-class object as an argument when the parameter is defined as a base-class reference As long as the functions in the base class are virtual, the derived-class versions can be invoked with the base-class reference void function( LibraryItem &item ){ cout << "In function: " << item.toString() << endl; } int main(){ Journal journal ("Dr. Dobbs","2004"); function( journal ); Base-class reference used as a parameter A derived-class object is used as an argument
Object-Oriented Programming: Polymorphism (Eckel, 633) Extensibility By designing your program so that it uses the base-class interfaces, you make it extensible. You can add new functionality by adding new classes that inherit from the existing base classes. If the functions and the data structures manipulate the base-class interface, then they will not need to be changed to work with the new class. Example, in the Gigaplex program, if you use virtual functions in the RentalItem base class and you use base-class pointers in the implementation of the list, then you can always add new types of RentalItems as long as they inherit from the same base class.
Makes it a pure virtual function, with no implementation. Object-Oriented Programming: Polymorphism (Deitel, 708–710) Abstract Base Classes Class for which the programmer cannot instantiate an object Normally used as a base class that defines a common interface for all its derived classes It must have one or more virtual functions that are “pure virtual functions” virtual string toString() = 0; Makes it a pure virtual function, with no implementation. Every concrete derived class is required to implement all pure virtual functions in the base class
Late Binding The mechanism behind the way that virtual functions work Object-Oriented Programming: Polymorphism (Deitel, 728–731; Eckel, 636) Late Binding The mechanism behind the way that virtual functions work Binding = connecting a function call to the function’s executable code Early binding = binding that is done by the compiler Late binding = binding that occurs at runtime, based on the object’s type, also called “dynamic binding” Early binding is used for non-virtual member functions Late binding is used for virtual member functions To support late binding, the compiler automatically adds a vtable (virtual function table) for every class with a virtual function
[0]&Journal::toString() Object-Oriented Programming: Polymorphism (Deitel, 728–731; Eckel, 640) vtable The mechanism that enables a function call to find the correct executable code during runtime For every class that has a virtual function: The compiler creates one vtable containing the addresses of the virtual functions The compiler inserts a pointer (vptr) to the vtable into every object instantiated from the class When a virtual function in a derived class is called by a base-class pointer, the compiler follows the vptr to the vtable where it finds the address of the function code. LibraryItemPtr Journal object vptr Journal vtable [0]&Journal::toString()
Downcasting Casting a base-class pointer to a derived-class pointer Object-Oriented Programming: Polymorphism (Eckel, 678) Downcasting Casting a base-class pointer to a derived-class pointer Allowed only if done explicitly, but dangerous due to the possibility of casting to the incorrect type Type-safe downcast can be done with the dynamic_cast LibraryItem *pItem = new Book;//upcasting Book *pBook = dynamic_cast<Book*>(pItem); //returns a pointer if downcasting is OK //returns a 0 if not the correct type
Virtual Destructors Potential problem Solution Guideline Object-Oriented Programming: Polymorphism (Deitel, 728–731; Eckel, 640) Virtual Destructors Potential problem When delete is used on a base-class pointer that points to an object of the derived class There may be an error if the object does not have a virtual destructor – the result is undefined Solution Declare the base-class destructor virtual, making all derived-class destructors virtual Guideline Always provide a virtual destructor for every class with virtual methods Future derived classes may need destructors
Quick Review Function Overloading
Review: Function Overloading Review (Deitel, 219) Review: Function Overloading Using the same name for two or more different functions To perform operations that are similar, but that must be implemented differently for different inputs double maximum( double x, double y ){ return ( x > y ) ? x : y; } int maximum( int x, int y ){ double maximum( double x, double y, double z ){ double temp = ( x > y ) ? x : y; return ( temp > z ) ? temp : z;
Review: Function Signatures Review (Deitel, 219) Review: Function Signatures Function’s name + parameter types Overloaded functions must have different signatures Return types can be the same or different signature double maximum( double x, double y ){ return ( x > y ) ? x : y; } int maximum( int x, int y ){ double maximum( double x, double y, double z ){ double temp = ( x > y ) ? x : y; return ( temp > z ) ? temp : z; signature signature
References Budd, T., An Introduction to Object-Oriented Programming, Third Edition. Boston: Addison Wesley, 2002. Deitel, H. M., and P. J. Deitel, C++ How to Program, Fifth Edition. Upper Saddle River, NJ: Prentice Hall, 2005. Eckel, Bruce, Thinking in C++, Second Edition. Upper Saddle River, NJ: Prentice Hall, 2000.