תכנות מונחה עצמים Object Oriented Programming (OOP) אתגר מחזור ב' Inheritence ( הורשה Inheritence ( הורשה ( השקפים מבוססים על שקפים של אליהו ברוטמן ומרינה ביברשטיין
© Copyright Eliyahu Brutman Inheritance Basics - 2 What is Inheritance A worker is a person It inherits person ’ s characteristics And may add some of its own How shall we model this? Class person Class worker
© Copyright Eliyahu Brutman Inheritance Basics - 3 Augmenting the original class Specializing the original class Inheritance Concept RealNumber ComplexNumber ImaginaryNumber Rectangle Triangle Shape Point Circle real imag real imag 3D-Point
© Copyright Eliyahu Brutman Inheritance Basics - 4 What is it used for? Code reuse The same code is used several times and not copied Polymorphism Similar reference to objects from different classes
© Copyright Eliyahu Brutman Inheritance Basics - 5 Define a Class Hierarchy Syntax: class DerivedClassName : access-level BaseClassName where access-level specifies the type of derivation private by default, or public Any class can serve as a base class Thus a derived class can also be a base class
© Copyright Eliyahu Brutman Inheritance Basics - 6 What to inherit? In principle, every member of a base class is inherited by a derived class just with different access permission
© Copyright Eliyahu Brutman Inheritance Basics - 7 Access Control Over the Members Two levels of access control over class members class definition inheritance type class Point{ protected: int x, y; public: void set(int a, int b); } class Circle : public Point{ … }
© Copyright Eliyahu Brutman Inheritance Basics - 8 The type of inheritance defines the minimum access level for the members of derived class that are inherited from the base class With public inheritance, the derived class follow the same access permission as in the base class With protected inheritance, only the public members inherited from the base class can be accessed in the derived class as protected members With private inheritance (default mode), none of the members of base class is accessible by the derived class Access Rights of Derived Classes privateprotectedpublic private protectedprivateprotected publicprivateprotectedpublic Type of Inheritance Access Controlfor Members
© Copyright Eliyahu Brutman Inheritance Basics - 9 Class Derivation mother daughterson class mother{ protected: int x, y; public: void set(int a, int b){x=a;y=b;} private: int z; }; class daughter : public mother{ private: double a; public: void foo ( ); }; void daughter :: foo ( ){ x = y = 20; set(5, 10); cout<< “ value of a ” <<a<<endl; z = 100; // error, a private member } daughter can access 3 of the 4 inherited members
© Copyright Eliyahu Brutman Inheritance Basics - 10 Class Derivation mother daughterson class mother{ protected: int x, y; public: void set(int a, int b); private: int z; } class son : protected mother{ private: double b; public: void foo ( ); } void son :: foo ( ){ x = y = 20; set(5, 10); cout<< “ value of b ” <<b<<endl; z = 100; // error, not a public member } son can access only 1 of the 4 inherited member
© Copyright Eliyahu Brutman Inheritance Basics - 11 Constructor Rules for Derived Classes The default constructor and the destructor of the base class are always called when a new object of a derived class is created or destroyed. class A { public: A ( ) {cout<< “ A:default ” <<endl;} A (int a) {cout<< “ A:parameter ” <<endl;} }; class B : public A { public: B (int a) {cout<< “ B ” <<endl;} }; B test(1); A:default B output:
© Copyright Eliyahu Brutman Inheritance Basics - 12 Constructor Rules for Derived Classes You can also specify a constructor of the base class other than the default constructor class A { public: A ( ) {cout<< “ A:default ” <<endl;} A (int a) {cout<< “ A:parameter ” <<endl;} }; class C : public A { public: C (int a) : A(a) {cout<< “ C ” <<endl;} }; C test(1); A:parameter C output: DerivedClassCon ( derivedClass args ) : BaseClassCon ( baseClass args ) { DerivedClass constructor body }
© Copyright Eliyahu Brutman Inheritance Basics - 13 Define its Own Members Point Circle class Point{ protected: int x, y; public: void set(int a, int b); }; class Circle : public Point{ private: double r; public: void set_r(double c); }; xyxy xyrxyr protected: int x, y; private: double r; public: void set(int a, int b); void set_r(double c); The derived class can also define its own members, in addition to members inherited from the base class
© Copyright Eliyahu Brutman Inheritance Basics - 14 Even more … A derived class can override methods defined in its parent class. With overriding, the method in the subclass has the identical signature to the method in the base class. a subclass implements its own version of a base class method. class A { protected: int x, y; public: void print () {cout<< “ From A ” <<endl;} }; class B : public A { public: void print () {cout<< “ From B ” <<endl;} };
© Copyright Eliyahu Brutman Inheritance Basics - 15 class Point { protected: int x, y; public: void set(int a, int b) {x=a; y=b;} void foo (); void print(); }; class Circle : public Point{ private: double r; public: void set (int a, int b, double c) { Point :: set(a, b); //same name function call r = c; } void print(); }; Access a Method Circle c; c.set(10,10,100); // from class Circle c.foo (); // from base class Point c.print(); // from class Circle Point a; a.set(30,50); // from base class Point a.print(); // from base class Point
Example University keeps data about all its students The following are defined for all students: Name Id For undergraduate students only: Study track (3-year, 4-year) For graduate students only: Thesis name Advisor’s name
Inheritance at a glance Class Student holds data and behavior common for all students Undergrad, graduate, doctoral, … Undergrad (graduate, …) students inherit all the data and behavior from class Student and extend it
Implementation: inheritance class Student { private: char* name; int id; char * ; public: Student(char* newName, int newId, char* new ); char* getName(); int getId(); char* get (); } class Undergrad: public Student{ private: char *trackName; public: Undergrad(char* newName, int newId, char* new , char* newTrack); char* getTrack(); } class Graduate: public Student{ private: char *thesisName; char *advisorName; public: Graduate(char* newName, int newId, char* new , char* newThesis, char* newAdvisor); char* getThesisName(); char* getAdvisorName(); }
Some details… class Student{ private: char* name; int id; char * ; public: Student(char* newName, int newId, char* new ); char* getName(); int getId(); char* get (); } class Undergrad: public Student{ private: char *trackName; public: Undergrad(char* newName, int newId, char* new , char* newTrack): Student(newName, newId, new ), trackName(newTrack) {} char* getTrack(){return trackName;} }
Typing rules Inheritance describes an is-a relationship Graduate student is a student Steamboat is a ship Apple is a fruit Derived classes have all the data and behavior of the base classes Can use objects of derived class as objects of base class Compiler will generate a cast But not vice-versa Can use pointers to derived class’s object as pointers to base class
Examples Student s, *s_ptr; Undergrad u, *u_ptr; Graduate g, *g_ptr; s = u; //ok u = g; //error u = s; //error s_ptr = &g; //ok g_ptr = &s; //error s = *g_ptr; //ok g = * s_ptr; // error s_ptr = g_ptr; //ok g_ptr = (Graduate*)s_ptr; //ok at compile-time //but unsafe
Method overriding Inherited methods can be overridden Example: Let’s add two more methods to Student: int Student::average() -- compute current average grade int Student::isSound() -- compute whether student’s academic state is sound Student::isSound(){ return (average() >= 55);} Graduate student’s state is sound only if the average is at least 65 Override the behavior defined by Student Graduate::isSound(){ return (average() >= 65);} To call the method as defined by Student from the Graduate class, call Student::isSound()
Example: listing students in unsound state Create a list of all the students, graduate and undergraduate Student*[N_STUDENTS] allStudents; For each student, call isSound for (int i = 0; i isSound()){ … } } If isSound returns false, print the student’s name Oops Will call Student::isSound for graduate students as well!
Overriding and typing With overriding, which method to call is determined using the static type Student* s_ptr = new Graduate(…); s_ptr->isSound(); //called Student::isSound Graduate* g_ptr = new Graduate(…); g_ptr->isSound(); //called Graduate::isSound How can we fix this code?