Inheritance (הורשה) מאפשרת פיתוח של class חדש בהתבסס על class קיים. למה צריך את זה? code reuse! נראה את התהליך בעזרת דוגמא.
נגדיר תחילה שני מושגים:
base class: זה ה-class הקיים, ממנו נרצה לרשת (inherit).
derived class: זה ה-class היורש.
ה-derived class יורש את כל מרכיבי ה-base class, ומוסיף להם חברי class חדשים. למעשה הוא יורש את כל מרכיבי ה-base class, חוץ מ-3 ההסתיגויות הבאות:
1. ה-constructor וה-destructor לא עוברים בירושה.
2. friends - (ראה פוסט בנושא) - לא עוברים בירושה.
3. לגבי operator overloading - כל האופרטורים חוץ מ = מועברים בירושה.
1. ה-constructor וה-destructor לא עוברים בירושה.
2. friends - (ראה פוסט בנושא) - לא עוברים בירושה.
3. לגבי operator overloading - כל האופרטורים חוץ מ = מועברים בירושה.
והנה תאור הדוגמא:
נניח שיש לנו class בשם Citizen. ה-class הזה מכיל את בסיסי הנתונים הקשורים לאזרח רגיל:
ת"ז,
כתובת מגורים,
תאריך לידה,
שם האב,
שם האם.
ה-class מכיל גם מתודות לעדכון כתובת ולהצגה של הנתונים.
כעת ברצוננו לצור class בשם Policeman. ה-class הזה יכיל את הנתונים הבסיסיים של כל אזרח, ובנוסף יכיל:
דרגה,
מתודה לעידכון הדרגה.
אז ניגש לעבודה ונתחיל בהצגת ה-base class.
הנה הגדרת ה-class:
- /*
- * citizen.h
- *
- * Created on: Mar 14, 2012
- * Author: ronen halevy
- */
- #ifndef CITIZEN_H_
- #define CITIZEN_H_
- #include <string>
- using namespace std;
- class Citizen{
- protected:
- std::string address;
- string birth_date;
- int id;
- string father_name;
- string mother_name;
- public:
- Citizen(string address, string birth_date, int id, string father_name, string Mother_name);
- void show();
- void change_address(string new_address);
- };
- #endif /* CITIZEN_H_ */
נעבור על הנקודות המעניינות בקובץ הנ"ל:
שורה 11: header file עבור string.
שורה 12: using namespace - עפ"י פקודה זו התוכנה תדע לגשת לספריית std ולמצוא את האובייקט. בלי שורה זו, הסוג string לא ימצא, אלא אם יכתב כ: std:string - כמו בשורה 15.
שורה 14-19: הגדרת חברי ה-class שהם עם access level ברמת protected. מה המשמעות של protected? נסביר: עד עתה נתקלנו ב-access level משני סוגים: public ו-private.
לחבר ב-class מסוג public, ניתן לגשת גם מתוך ה-אובייקט וגם מבחוץ. לחבר class מסוג private ניתן לגשת רק מתוך האובייקט. עד כאן, protected מתנהג כמו private. ההבדל בין protected ל-private קשור בדיוק לעניין ה-inheritance. אל חבר class מסוג private לא ניתן לגשת ישירות מתוך ה-derived class. אל חבר class מסוג protected, ניתן לגשת מתוך ה-derived class.
בהמשך נראה גישה לחברי ה-class הנ"ל מתוך ה-derived class.
שורה 20: זה ה- constructor/
שורות 21-22: מתודות של ה-class.
נציג את מימוש המתודות של ה-class:
- /*
- * citizen.cpp
- *
- * Created on: Mar 14, 2012
- * Author: ronen halevy
- */
- #include "citizen.h"
- #include <iostream>
- #include <string>
- using namespace std;
- Citizen::Citizen(string address, string birth_date, int id, string father_name, string mother_name){
- Citizen::address = address;
- Citizen::birth_date = birth_date;
- Citizen::id = id;
- Citizen::father_name = father_name;
- Citizen::mother_name = mother_name;
- cout << "\nCitizen constructor. address: " << address << "birth_date: "<<birth_date<<"id: "<<id<<"father's name: "<< father_name<<"mother's name: "<<mother_name;
- }
- void Citizen::show(){
- cout << "\naddress = " << address << "\nbirth_date: "<<birth_date<<"\nid: "<<id<<"\nfather's name: "<< father_name<<"\nmother's name: "<<mother_name;
- }
- void Citizen::change_address(string new_address){
- Citizen::address = new_address;
- }
התוכנית הנ"ל כוללת שלוש מתודות - מודגשות בצבעם שונים:
המתודה הראשונה (שורה 14): זהו ה- constructor. הוא מקבל את כל הפרמטר לאתחול רשומת הנתונים של Citizen.
המתודה השניה (שורה 24): show מדפיס לפלט את רשימת הנתונים.
המתושה השלישית (שורה 29): מתודה לעדכון כתובת.
עד כאן תאור ה-base class. מיד נצור ממנו derived class.
הנה ה-policeman: נציג את הגדרת ה-class ואח"כ את מימוש המתודות.
הנה הגדרת ה-class:
- /*
- * policeman.h
- *
- * Created on: Mar 14, 2012
- * Author: ronen halevy
- */
- #ifndef POLICEMAN_H_
- #define POLICEMAN_H_
- #include "citizen.h"
- #include <string>
- using namespace std;
- class Policeman : public Citizen{
- private:
- string rank;
- public:
- Policeman(string rank, string address, string birth_date, int id, string father_name, string mother_name);
- };
- #endif /* POLICEMAN_H_ */
כאן נתייחס לשלושת החלקים המודגשים בצבע:
חלק ראשון - שורה 15: זה המקום בו מוגדירים את ה-base class. ההכרזה:
: public Citizen
קובעת שני דברים:
1. Citizen הוא ה-base class של Policeman.
2. public היא דרגת ה-access level המקסימלית ב-base class.
נקודה 2 הנ"ל דורשת הסבר. קיימות שלוש דרגות אפשרויות של access. הנה הן בסדר עולה:
א. private.
ב. protected.
ג. public.
בהגדרת ה-base class, מגדירים את דרגת ה-access המקסימלית. נבחן את התוצאה עבור כל אחת מ-3 הדרגות.
1. נניח שההגדרה ב-class הנ"ל היתה:
: private Citizen
במקרה הזה כל חברי ה-base class היו הופכים להיות private.
2. נניח שההגדרה של ה-base class היתה:
: protected Citizen
במקרה זה, חברי ה-base class עם access level ברמת public היו הופכים ל-protected.
3. ובמקרה שלנו, בו ההגדרה היא (ראה שורה 15):
: public Citizen
ה-access level של חברי ה-base class נשאר ללא שינוי.
חלק שני - שורה 16-17: הגדרה של חברי ה-derived class מסוג protected. כאן הוספנו משתנה דרגה (rank).
החלק השלישי- שורות 18-21: כולל הגדרת ה-constructor של ה-derived class ועוד מתודה שמאפשרת שינוי הדרגה.
נעבור כעת למימוש ה-constructor והמתודה של ה-class.
- /*
- * policeman.cpp
- *
- * Created on: Mar 14, 2012
- * Author: ronen halevy
- */
- #include "policeman.h""
- #include <iostream>
- #include <string>
- using namespace std;
- Policeman::Policeman(string rank, string address, string birth_date, int id, string father_name, string mother_name) : Citizen(address, birth_date, id, father_name, mother_name){
- //Policeman::Policeman(string rank){
- Policeman::rank = rank;
- cout << "\n Policeman constructor rank is: " << rank;
- }
- void change_rank(string rank){
- Policeman:rank = rank;
- }
החלק המעניין כאן הוא ה-constructor - מודגש בצהוב.
נשאת השאלה: מי מפעיל את ה-constructor של ה-base class, ואיך זה מתבצע?
התשובה: ה-constructor של ה-base class מופעל לפני הפעלת ה-constructor של ה-derived class.
* אם לא מוגדר constructor ב-base class, יופעל ה-default constructor.
* אם מוגדר constructor שלא מקבל פרמטרים - הוא יופעל.
* אם מוגדר constructor שמקבל פרמטרים, אפשר להפעיל אותו, כפי שמודגם בשורה 13 כאן למעלה.
הפרמטרים שמועברים ל-base class constructor צריכים להיות מועברים גם ל derived class constructor.
במקרה שלנו לדוגמא, הconstructor נראה כך:
Citizen(string address, string birth_date, int id, string father_name, string mother_name);
הוא מקבל 5 פרמטרים. לכן הגדרתי את ה-constructor של ה-derived class כך:
:Policeman(string rank, string address, string birth_date, int id, string father_name, string mother_name)
הערה - העברת הפרמטרים ל-constructor של ה-base class נעשית על פי הפורמט של ה-initialization list. ראה פוסט בנושא.
זהו ההסבר על ה-constructors.
זהו ההסבר על ה-constructors.
נציג את main, ונדגים את ההפעלה של מערכת ה-classes הנ"ל.
- /*
- * my_inheritance.cpp
- *
- * Created on: Mar 14, 2012
- * Author: ronen halevy
- */
- #include "citizen.h"
- #include "policeman.h""
- #include <iostream>
- using namespace std;
- int main(){
- Policeman policeman("sergeant", "levanon st. tel aviv", "22.2.`1922", 77777777, "yosef", "rivka");
- policeman.change_address("11, habonim st. Jerusalem");
- policeman.show();
- }
שורה 14: יצירת אובייקט מסוג Policeman והפעלת ה-constructor תוך הכנסת 6 הפרמטרים. כמו שהוסבר קודם, רק אחד מהפרמטרים ("sergant") באמת דרוש לderived class constructor. שאר 5 הפרמטרים דרושים עבור ה-base class constructor.
שורה 15: כאן ניתן לראות שהמתודה change_address השייכת ל-base class, הועברה בירושה ל-derived class.
16: גם המתודה show שייכת במקור ל-Citizen, אבל העברה בירושה ל-Policeman.
הנה הפלט שהודפס על הצג:
- Citizen constructor. address: levanon st. tel avivbirth_date: 22.2.`1922id: 77777777father's name: yosefmother's name: rivka
- Policeman constructor rank is: sergeant
- address = 11, habonim st. Jerusalem
- birth_date: 22.2.`1922
- id: 77777777
- father's name: yosef
- mother's name: rivka
שורה 1 הודפסה ע"י ה-base class constructor.
שורה 2 הודפסה ע"י ה-derived class constructor
שורות 3-7 הודפסן על ידי המתודה show.
זהו המבוא ל-inheritance.
קישור לקבצי המקור להורדה.
אין תגובות:
הוסף רשומת תגובה