Contents Basic Inheritance Why inheritance Inheritance Inheritance How inheritance works Inheritance Design I h it D i Protected members Exploring different Constructors and destructors inheritance structure inheritance structure Derivation tree Direct solution to reuse code Function overriding and hiding Alternative solutions Alternative solutions C++ Object Oriented Programming C++ Obj t O i t d P i Example class hierarchy l l hi h Better design Pei-yih Ting Final solutions NTOUCS NTOUCS Design rules (IS-A relationship, Proper inheritance) Dubious designs 25-1 25-2 Object-Oriented Analysis j y Inheritance The distinction between an "object- based language" and an "object- An object-orientated design provides a more natural and systematic oriented language" is the ability to support inheritance (or derivation). g g y pp ( ) framework for specifying and designing a programming solution framework for specifying and designing a programming solution. Composition/aggregation and inheritance are the most important two Program designs are almost always based on the program ways to construct object hierarchies . y j specification , i.e. a document describing the exact requirements a specification , i.e. a document describing the exact requirements a program is expected to achieve. In the OOA process, after objects are identified from the problem domain and attributes and behaviors are modeled with classes in the analysis process, the next important phase is the identification of Four phases of the object-oriented analysis process: super-classes in the problem domain The identification of objects from the program specification. j p g p In the language level, a super-class defines the attributes and I h l l l l d fi h ib d The identification of the attributes and behaviours of these objects. behaviors that are common to all its sub-classes. The identification of any super-classes. y p Base class Derived class The specification of the behaviours of the identified classes. vs. Super-class Sub-class Parent class Child class 25-3 25-4
The Basic Problem: Extension Imagine you have a class for describing students class Student { class Student { class Student { class Student { public: public: Student(); Student(); Basic Inheritance Basic Inheritance ~Student(); ~Student(); ~Student(); void setData(char *name, int age, void setData(char *name, int age); int stipend); int getAge() const; int getAge() const; int getAge() const; i t tA () t const char *getName() const; const char *getName() const; private: int getStipend() const; char *m_name; private: char *m_name; int m_age; int m_age; }; }; int m_stipend; }; Want to add fields to handle the requirements for graduate students W t t dd fi ld t h dl th i t f d t t d t What is the problem of this design? 25-5 25-6 Not Good! No Good! A Solution – Separate Classes p No redundant members, old codes class Graduate { In the above design p public: for Student need only change the for Student need only change the Student becomes a general purpose class, a set of attributes and S d b l l f ib d Graduate(); name to UnderGraduate. ~Graduate(); interfaces are used for undergraduate students, while another set class Undergraduate { void setData(char *name, of attributes and interfaces are used for graduate students of attributes and interfaces are used for graduate students public: int age, int stipend); … a form with many redundant fields int getAge() const; Undergraduate(); ~Undergraduate(); const char *getName() const; In the process of this change, all previously developed programs, In the process of this change, all previously developed programs, int getStipend() const; i S i d() void setData(char *name, int age); including those implementations of the Student class and those private: int getAge() const; char *m_name; codes that are the client programs of the Student class, have to const char *getName() const; int m age; int m_age; private: pri ate: be recompiled…. This change is global, not limited to the part int m_stipend; char *m_name; you plan to add. }; int m_age; Why is this still a poor solution ? Why is this still a poor solution ? }; }; OCP: open-closed principle A client program cannot treat both classes of objects in a uniform way, ex. The library circulation system wants to check which students are ex. The library circulation system wants to check which students are Software entities (classes modules functions etc ) Software entities (classes, modules, functions, etc.) holding books overdue, it has to handle undergraduate and graduate should be open for extension, but closed for modification . Also, a lot of redundancy. students with separate pieces of codes. 25-7 25-8
Basic Inheritance in C++ Basic Inheritance (cont’d) ( ) Note: A Graduate object is a Student object because Declare a class Graduate that is derived from Student a Graduate object provides the complete set of Usages : g class Graduate: public Student { class Graduate: public Student { Student is called the base Student is called the base interface functions of a Student object i e interface functions of a Student object, i.e., public: class, Graduate is called Student student; they looks the same from the outside. Graduate(char *name, int age, int stipend); Student the derived class int getStipend() const; student.setData("Mel", 19); private: private: new member functions new member functions Graduate gradStudent("Ron", 24, 3000); int m_stipend; Graduate }; new data member : Graduate ctor(), dtor() (), () : Student : Student ctor(), dtor() All the data members (m_name and m_age) and most the member getStipend() m_name = "Mel" : Student setData() m_age = 19 m_name = "Ron" functions (setData(), getAge(), getName()) of class Student are getAge() setData() m_age = 24 getName() getName() getAge() getAge() automatically inherited by the Graduate class i ll i h i d b h d l getName() m_stipend = 3000 New member functions cout << student.getName() << " is " << student.getAge() cout << student.getName() << is << student.getAge() Graduate::Graduate(char *name, int age, int stipend) : m_stipend(stipend) { << " years old undergraduate student\n"; setData(name, age); // this is inherited from Student } cout << gradStudent.getName() << " is " << gradStudent.getAge() g g g g g int Graduate::getStipend() const { << " years old and has a stipend of " << gradStudent.getStipend() return m_stipend; << " dollars.\n"; } 25-9 25-10 Basic Inheritance (cont’d) ( ) Protected Data and Functions Can we give the derived class access to "private" data of base class? This would be illegal int Graduate::getStipend() const { int Graduate::getStipend() const { class Student { class Student { if (m_age > 30) public: return 0; Student(); return m_stipend; ~Student(); ~Student(); } void setData(char *name, int The following is now legal age); Private data member of the base class is implicitly declared/defined int getAge() const; g g () ; int Graduate::getStipend() const { g p () { but is still kept private from its derived class. (the boundary of base b t i till k t i t f it d i d l (th b d f b const char *getName() const; if (m_age > 30) class is maintained) return 0; protected : return m_stipend; char m_name; char *m name; This is legal This is legal } int m_age; int Graduate::getStipend() const { }; if (getAge() > 30) Note: the encapsulation Note: the encapsulation return 0; t 0 Who can access protected fields? perimeter is enlarged return m_stipend; a great deal with } base class and friends of base class "protected" in your protected in your Back to OCP : Did you extend the functionality of the class Student? derived class and friends of derived design classes Did you edit student.h or student.cpp? 25-11 25-12
More recommend