850 likes | 1.09k Views
Chapter 13 Object-Oriented Programming: Polymorphism. 13.1 Introduction. Example: Animal hierarchy Animal base class – every derived class has function move. Different animal objects maintained as an array of Animal pointers.
E N D
13.1 Introduction • Example: Animal hierarchy • Animal base class – every derived class has function move. • Different animal objects maintained as an array of Animal pointers. • Program invoke same function (move) to each animal generically. • Proper function gets called: • A Fish will move by swimming • A Frog will move by jumping • A Bird will move by flying
13.1 Introduction Animal Fish Frog Bird Fish a1; Frog a2; Bird a3; Animal *Aptr[3]; Aptr[0] = &a1; Aptr[1] = &a2; Aptr[2] = &a3; for (inti=0; i<3; i++) Aptr[i]->move(); 0 1 2 Aptr: a1 a2 a3
13.2 Polymorphism Examples • Polymorphism occurs when a program invokes a virtual (實質上的) function through a base-class pointer or reference • C++ dynamically chooses the correct function for the class from which the object was instantiated. • Polymorphism promotes extensibility.
13.3 Relationships Among Objects in an Inheritance Hierarchy • Key concept • An object of a derived class can be treated as an object of its base class. • Demonstration • Invoking base-class functions from derived-class objects • Aiming derived-class pointers at base-class objects • Derived-class member-function calls via base-class pointers • Demonstrating polymorphism using virtual functions • Base-class pointers aimed at derived-class objects
在此,我們回到上一章中CommissionEmployee和BaseCommissionEmployee兩個類別在此,我們回到上一章中CommissionEmployee和BaseCommissionEmployee兩個類別
請注意色塊標註的區域。 基本類別與衍生類別都具有同名的成員函式用來執行共同的功能;然而,執行的功能卻略有差異。
請注意此頁中類別的使用例;它用來說明以下的觀念:請注意此頁中類別的使用例;它用來說明以下的觀念: • An object of a derived class can be treated as an object of its base class. 首先,產生一個基本類別的物件,以及宣告一個指向基本類別物件的指標變數
接著,產生一個衍生類別的物件,以及宣告一個指向衍生類別物件的指標變數接著,產生一個衍生類別的物件,以及宣告一個指向衍生類別物件的指標變數 將第一個指標指向基本類別物件,並呼叫此類別的print()函式
將第二個指標指向衍生類別物件,並呼叫此類別的print()函式將第二個指標指向衍生類別物件,並呼叫此類別的print()函式 Aiming base-class pointer at derived-class object and invoking print() 將指向基本類別的指標指向衍生類別的物件。 請問第59行中所呼叫的print(),是呼叫基本類別的print()?還是衍生類別的print()?
13.3.2 Aiming Derived-Class Pointers at Base-Class Objects • Can we aim a derived-class pointer at a base-class object? • C++ compiler generates error • CommissionEmployee (base-class object) is not a BasePlusCommissionEmployee (derived-class object) • If this were to be allowed, programmer could then attempt to access derived-class members which do not exist.
We cannot assign base-class object to derived-class pointer because is-a relationship does not apply 例如:「Fish」為基本類別「Animal」的衍生類別。 則「Animal *」可指向「Fish」的物件。 Fish f1; Animal *aptr = &f1; 因為「Fish」一定是「Animal」。反過來說,「Animal」不一定是「Fish」,所以以下的寫法不正確: Animal a1; Fish *fptr = &a1; 因為如果透過fptr去存取「Fish」的某些屬性或函式有可能找不到,因為a1為基本類別的物件,衍生類別中的某些新的成員在a1中並不存在。
13.3.3 Derived-Class Member-Function Calls via Base-Class Pointers • Aiming base-class pointer at derived-class object • Calling functions that exist in base class causes base-class functionality to be invoked • Calling functions that do not exist in base class (may exist in derived class) will result in error • Derived-class members cannot be accessed from base-class pointers. • However, they can be accomplished using downcasting.
即使此指標實際上指向的是衍生類別的物件,仍無法呼叫衍生類別中新增的成員函式。因為現在此物件被視為基本類別的物件看待。即使此指標實際上指向的是衍生類別的物件,仍無法呼叫衍生類別中新增的成員函式。因為現在此物件被視為基本類別的物件看待。
Software Engineering Observation 13.3 • It is acceptable to cast that base-class pointer back to a pointer of the derived-class type (downcasting). Fish f1; Animal *aptr = &f1; Fish *fptr = (Fish *) aptr; Fish &fref = *aptr; 注意: 請勿把一個基本類別的物件downcast成衍生類別的物件。
13.3.4 Virtual Functions • Which class’s function should be invoke? • Normally, handle determines which class’s functionality to invoke. • With virtual functions • Type of the object being pointed to, not type of the handle, determines which function is virtually invoked. • It allows a program to dynamically (at runtime rather than compile time) determine which function to use • Called dynamic binding or late binding 簡單地說,被宣告成virtual的成員函式會自動根據物件實際的型態來決定自己可不可以被呼叫。
13.3.4 Virtual Functions • Declared by preceding the function’s prototype with the keyword virtual in base class • Derived classes override function as appropriate. • Once declared virtual, a function remains virtual all the way down the hierarchy. • Static binding • When calling a virtual function using specific object with dot operator, function invocation resolved at compile time • Dynamic binding • Dynamic binding occurs only off pointer and reference handles
Good Programming Practice 13.1 • Even though certain functions are implicitly virtual, explicitly declare these functions virtual at every level of the hierarchy to promote program clarity.
Software Engineering Observation 13.5 • When a derived class chooses not to override a virtual function from its base class, the derived class simply inherits its base class’s virtual function implementation.
現在,讓我們改寫上一章中的CommissionEmployee和BaseCommissionEmployee類別現在,讓我們改寫上一章中的CommissionEmployee和BaseCommissionEmployee類別
宣告earnings()與print()為virtual;代表此兩個函式將依據物件實際的型態來呼叫。宣告earnings()與print()為virtual;代表此兩個函式將依據物件實際的型態來呼叫。 以下,其衍生類別中的earnings與print函式也將自動為virtual,程式設計者可選擇是否多載它們。
雖然衍生類別中的這兩個函式自動為virtual,但習慣上為求詳實,我們仍加註virtual。雖然衍生類別中的這兩個函式自動為virtual,但習慣上為求詳實,我們仍加註virtual。 註:函式的實作,就不需再加註virtual關鍵字。此關鍵字只在宣告使用。
請注意此頁中類別的使用例;它用來說明以下的觀念:請注意此頁中類別的使用例;它用來說明以下的觀念: • The correct function can be dynamically chosen for the class from which the object was instantiated.
Aiming base-class pointer at base-class object and invoking base-class functionality 請注意,此時print()被宣告為virtual。那麼請問指標變數commissionEmployeePtr指向的物件其型態為何?_______ 所以,因為print()是virtual function,所以實質上是基本類別的print()被呼叫?還是衍生類別的print()被呼叫?
commissionEmployeePtr指向的物件其型態為何?_______commissionEmployeePtr指向的物件其型態為何?_______ 所以,因為print()是virtual function,所以實質上是CommissionEmployee的print()被呼叫?還是BaseCommissionEmployee的print()被呼叫?
請說明,如果要使以下的程式碼成立(讓每個物件找到屬於自己的成員函式來呼叫),則其move函式必須宣告為__________。請說明,如果要使以下的程式碼成立(讓每個物件找到屬於自己的成員函式來呼叫),則其move函式必須宣告為__________。 Animal Fish Frog Bird Fish a1; Frog a2; Bird a3; Animal *Aptr[3]; Aptr[0] = &a1; Aptr[1] = &a2; Aptr[2] = &a3; for (inti=0; i<3; i++) Aptr[i]->move(); 0 1 2 Aptr: a1 a2 a3
13.3.5 Summary of the Allowed Assignments Between Base-Class and Derived-Class Objects and Pointers • Four ways to aim base-class and derived-class pointers at base-class and derived-class objects • Aiming a base-class pointer at a base-class object • Is straightforward • Aiming a derived-class pointer at a derived-class object • Is straightforward • Aiming a base-class pointer at a derived-class object • Is safe, but can be used to invoke only member functions that base-class declares (unless downcasting is used) • Can achieve polymorphism with virtual functions • Aiming a derived-class pointer at a base-class object • Generates a compilation error
13.3.5 Summary of the Allowed Assignments Between Base-Class and Derived-Class Objects and Pointers • Four ways to aim base-class and derived-class pointers at base-class and derived-class objects straightforward Base-class object Base-class pointer • Safe. • Can be used to invoke only member functions that base-class declares (unless downcasting is used). • Can achieve polymorphism with virtual functions. Compilation error Derived-class pointer straightforward Derived-class object
13.5 Abstract Classes and Pure virtual Functions • Abstract classes (抽象類別) • Classes from which the programmer never intends to instantiate any objects • Incomplete—derived classes must define the “missing pieces” • 抽象類別存在的目的在提供類別的基本要素,主要的作用就是讓其他類別繼承,而不是在產生物件。 • Concrete classes(具體類別) • Classes used to instantiate objects • Must provide implementation for every member function they define
13.5 Abstract Classes and Pure virtualFunctions • 怎麼樣才是一個抽象類別? • 只要類別中包含一個以上的pure virtual function,則此類別即為抽象類別。 • Pure virtual function • Placing “= 0” in its declaration • Example • virtual void draw() const = 0; • “= 0” is known as a pure specifier. • Do not provide implementations • Every concrete derived class must override all base-class pure virtual functions with concrete implementations • If not overridden, derived-class will also be abstract • Used when the programmer wants all concrete derived classes to implement the function.
Software Engineering Observation 13.8 • An abstract class defines a common public interface for the various classes in a class hierarchy. • An abstract class contains one or more pure virtual functions that concrete derived classes must override.
Common Programming Error 13.3 • Attempting to instantiate an object of an abstract class causes a compilation error.
Common Programming Error 13.4 • Failure to override a pure virtual function in a derived class, then attempting to instantiate objects of that class, is a compilation error. • Why?
Software Engineering Observation 13.9 • An abstract class has at least one pure virtual function. • However, an abstract class also can have data members and concrete functions (including constructors and destructors).
13.5 Abstract Classes and Pure virtualFunctions • We can use the abstract base class to declare pointers and references • Then, we can refer to objects of any concrete class derived from the abstract class • Programs typically use such pointers and references to manipulate derived-class objects polymorphically.
13.6 Case Study: Payroll System Using Polymorphism • 在本節中,我們將結合多型的觀念以擴充之前CommissionEmployee與BasePlusCommissionEmployee的範例,目的在加深各位對抽象類別與virtual函式的瞭解。 • 本案例使用一個抽象類別Employee用來代表一個雇員的一般性資料。 • 這個抽象類別將定義一個雇員類別應有的「介面」,以及共同的資料,如姓名、身分證號碼。 • 函式earnings()與print()的實作內容必須依衍生類別的不同而有所差異。
1. Creating Abstract Base Class Employee • Class Employee • Provides various get and set functions • Provides functions earnings and print • Function earnings depends on type of employee, so declared pure virtual • Not enough information in class Employee for a default implementation • Function print is virtual, but not pure virtual • Default implementation provided in Employee • Example maintains an array of Employee pointers • Polymorphically invokes proper earnings and print functions.
Employee.h (1 of 2)
Employee.h (2 of 2) Function earnings is pure virtual, not enough data to provide a default, concrete implementation Function print is virtual, default implementation provided but derived-classes may override
Employee.cpp (1 of 2)
Employee.cpp (2 of 2) 請注意,print()是一個virtual函式,僅在宣告時標註,實作時並無載明 請問,earnings()為何沒有被實作? 因為earnings()是一個__________函式。 因此,類別Employee是一個______類別。 代表___________________
2. Creating Concrete Derived Class SalariedEmployee • SalariedEmployee inherits from Employee • A weekly salary is included • The function earnings() is overridden to incorporate weekly salary. • The function print() is overridden to incorporate weekly salary. • This is a concrete class (implements all pure virtual functions in abstract base class).
SalariedEmployee.h (1 of 1) SalariedEmployee inherits from Employee, must override earnings to be concrete Functions will be overridden (or defined for the first time)