51
Inheritance Inheritance

Inheritance. Why inherit? class person { char * name, char * name, * surname; * surname;public: void print_name (); void print_name (); void print_surname();

  • View
    234

  • Download
    4

Embed Size (px)

Citation preview

InheritanceInheritance

Why inherit?Why inherit?

class personclass person{{ char * name,char * name, * surname;* surname;

public:public: void void print_nameprint_name (); (); void void print_surnameprint_surname();();

void void print_allprint_all();();}}

class adultclass adult{{char * name,char * name, * surname,* surname, * ID_card;* ID_card;public:public: void print_name(); void print_name(); void print_surname();void print_surname(); void print_ID_card();void print_ID_card(); void print_all();void print_all();}}

Why inherit?Why inherit?

class personclass person{{ char * name,char * name, * surname;* surname;public:public: void void print_nameprint_name (); (); void void print_surnameprint_surname();(); void void print_allprint_all();();}}

class adult: public personclass adult: public person{{char * ID_card;char * ID_card;public:public: void print_ID_card();void print_ID_card(); void print_all();void print_all();}}

InheritanceInheritance

Reveals hierarchic relations between classesReveals hierarchic relations between classes

To develop (extend) existing classes without To develop (extend) existing classes without need to modify or recompile themneed to modify or recompile them

Reusability of code (one defines only what is Reusability of code (one defines only what is added or changed, all the rest is reused)added or changed, all the rest is reused)

InheritanceInheritance

Base classBase class personperson

Derived classDerived class adultadult

Each Each adultadult is a is a personperson

An An adultadult is a specific kind of is a specific kind of personperson

Derived classDerived class

adult contains fields and methods:adult contains fields and methods:char * name, * surnamechar * name, * surname

— — inherited, inaccessible for class adultinherited, inaccessible for class adult

char *nr_ID_card char *nr_ID_card

— — private in adultprivate in adult

print_name(), print_surname () print_name(), print_surname ()

— — public, inherited from personpublic, inherited from person

person::prperson::priint_all() nt_all()

— — public, inherited, hidden: public, inherited, hidden:

use scope operator (::) to accessuse scope operator (::) to access

Derived classDerived class

contains all the fields of base classcontains all the fields of base class inherits all the methods, may redefine theminherits all the methods, may redefine them to access to access accessibleaccessible but but hiddenhidden names from names from

the base class - use the scope operator (::)the base class - use the scope operator (::) notenote: :

some names (private) may some names (private) may existexist, but not be , but not be accessibleaccessible

some (hidden) may be some (hidden) may be accessibleaccessible, but not , but not visiblevisible

Derived classDerived class

person person o;o;adult adult dd;; // derived from person// derived from person

o.print_name(); o.print_name(); o.print_surname();o.print_surname(); o.print_all();o.print_all(); dd.print_name(); .print_name(); // from person// from person dd.print_surname(); .print_surname(); // from person// from person dd.print_nr_ID_card(); .print_nr_ID_card(); // from adult// from adult dd.print_all(); .print_all(); // from adult// from adult dd.person::print_all(); .person::print_all(); // from person// from person

Accessibility of base class membersAccessibility of base class members

class derivedclass derived : : public base;public base;

class derivedclass derived : : protected base;protected base;

class derivedclass derived : : private base;private base;

class derivedclass derived : : base; base; // // default: private: private

Accessibility of base class membersAccessibility of base class members

section in base classsection in base class

mode of mode of inheritanceinheritance

privateprivate protectedprotected publicpublic

: : privateprivate InaccessibleInaccessible privateprivate privateprivate

: : protectedprotected InaccessibleInaccessible protectedprotected protectedprotected

: : publicpublic InaccessibleInaccessible protectedprotected publicpublic

access section in access section in derivedderived class class

Accessibility of base class membersAccessibility of base class members

class aclass a{{ public:public: int f(int);int f(int);};};// Outside the class the access mode can only be tightened, // Outside the class the access mode can only be tightened, // never weakened beyond the limits defined inside the class// never weakened beyond the limits defined inside the classclass b: private a class b: private a // access restrictions caused by // access restrictions caused by {{ // inheritance mode may be „weakened”// inheritance mode may be „weakened”public:public: a::f; a::f; // now a::f is still a public member// now a::f is still a public member};};

Accessibility of base class membersAccessibility of base class members

class baseclass base{{public:public: int ba_pub,int ba_pub, i;i;

protected:protected: int ba_prot;int ba_prot;

private:private: int ba_priv;int ba_priv;};};

class prot: protected baseclass prot: protected base{{public:public: int i;int i;

void method();void method();

protected:protected: int prot_prot;int prot_prot;

friend void friend_prot();friend void friend_prot();};};

Accessibility of base class membersAccessibility of base class members

void prot::method()void prot::method(){{ int i;int i;

i=base::i;i=base::i;

i=i;i=i; i=prot::i;i=prot::i;

i=ba_pub;i=ba_pub; i=base::ba_pub;i=base::ba_pub; i=prot::ba_pub; i=prot::ba_pub;

i=ba_prot;i=ba_prot; i=base::ba_prot;i=base::ba_prot; i=prot::ba_prot;i=prot::ba_prot;

// i=ba_priv;// i=ba_priv;// i=base::ba_priv;// i=base::ba_priv;// i=prot::ba_priv;// i=prot::ba_priv;

i=prot_prot;i=prot_prot; i=prot::prot_prot;i=prot::prot_prot;}}

Accessibility of base class membersAccessibility of base class members

void not_a_friend()void not_a_friend(){{ base ba;base ba; prot pr;prot pr;

int i;int i;

i=ba.i;i=ba.i; i=ba.ba_pub;i=ba.ba_pub;// i=ba.ba_prot;// i=ba.ba_prot;// i=ba.ba_priv;// i=ba.ba_priv;

// i=pr.base::i; !!!!!// i=pr.base::i; !!!!!

i=pr.i;i=pr.i; i=pr.prot::i;i=pr.prot::i;

// i=pr.ba_pub;// i=pr.ba_pub;// i=pr.base::ba_pub;// i=pr.base::ba_pub;// i=pr.prot::ba_pub;// i=pr.prot::ba_pub;

// i=pr.ba_prot;// i=pr.ba_prot;// i=pr.base::ba_prot;// i=pr.base::ba_prot;// i=pr.prot::ba_prot;// i=pr.prot::ba_prot;

// i=pr.ba_priv;// i=pr.ba_priv;// i=pr.base::ba_priv;// i=pr.base::ba_priv;// i=pr.prot::ba_priv;// i=pr.prot::ba_priv;

// i=pr.prot_prot;// i=pr.prot_prot;// i=pr.prot::prot_prot;// i=pr.prot::prot_prot;}}

Accessibility of base class membersAccessibility of base class members

void friend_prot(void)void friend_prot(void){{ base ba;base ba; prot pr;prot pr;

int i;int i;

i=ba.i;i=ba.i; i=ba.ba_pub;i=ba.ba_pub;// i=ba.ba_prot;// i=ba.ba_prot;// i=ba.ba_priv;// i=ba.ba_priv;

i=pr.base::i; i=pr.base::i; // !!!!!// !!!!!

i=pr.i;i=pr.i; i=pr.prot::i;i=pr.prot::i;

i=pr.ba_pub;i=pr.ba_pub; i=pr.base::ba_pub;i=pr.base::ba_pub; i=pr.prot::ba_pub;i=pr.prot::ba_pub;

i=pr.ba_prot;i=pr.ba_prot; i=pr.base::ba_prot;i=pr.base::ba_prot; i=pr.prot::ba_prot;i=pr.prot::ba_prot;

// i=pr.ba_priv;// i=pr.ba_priv;// i=pr.base::ba_priv;// i=pr.base::ba_priv;// i=pr.prot::ba_priv;// i=pr.prot::ba_priv;

i=pr.prot_prot;i=pr.prot_prot; i=pr.prot::prot_prot;i=pr.prot::prot_prot;}}

Constructor and destructor Constructor and destructor for derived classfor derived class

Cconstructors are Cconstructors are notnot inherited, but: inherited, but:

Order of constructor calls:Order of constructor calls:1.1. virtual base classesvirtual base classes2.2. non-virtual base classesnon-virtual base classes3.3. member objectsmember objects4.4. the class constructorthe class constructor

Destructorss – reverse orderDestructorss – reverse order

Constructor and destructor Constructor and destructor for derived class – initiation listfor derived class – initiation list

To initiate members declared in the class (not To initiate members declared in the class (not inherited)inherited)

To specify arguments for constructors of To specify arguments for constructors of virtual and direct base classes.virtual and direct base classes.

ExampleExampleclass personclass person{{protected:protected: char * name,char * name, * surname;* surname;

char * aloc_string(const char * s);char * aloc_string(const char * s);

public:public: person(const char * theName, const char person(const char * theName, const char

* theSurname)* theSurname) :name(aloc_string(theName)),:name(aloc_string(theName)), surname(aloc_string(theSurname))surname(aloc_string(theSurname)) {{ } }

~person()~person() {{ delete delete [] [] name;name; delete delete [] [] surname;surname; }}

void print_name();void print_name(); void print_surname();void print_surname(); void print_all();void print_all();}}

ExampleExample

char * person::aloc_string(const char * s)char * person::aloc_string(const char * s){{ char * cp=new char[strlen(s) + 1];char * cp=new char[strlen(s) + 1]; strcpy(cp, s);strcpy(cp, s);

return cp;return cp;}}

void person::print_name()void person::print_name(){{ cout << name << " ";cout << name << " ";}}

void person::print_surname()void person::print_surname(){{ cout << surname << " ";cout << surname << " ";}}

void person:print_all ()void person:print_all (){{ print_name();print_name(); print_surname();print_surname();}}

Example – derived class constructorExample – derived class constructor

class adult:class adult: public personpublic person{{protected:protected: char * nr_ID_card;char * nr_ID_card;  public:public:   adult(const char * name, adult(const char * name,

const char * surname, const char * surname, const char * nr_ID_card)const char * nr_ID_card)

:person(name, surname), :person(name, surname), nr_ID_card(aloc_string(nr_ID_card))nr_ID_card(aloc_string(nr_ID_card))

{{ };};

~adult()~adult() {{ deletedelete [] [] nr_ID_card; nr_ID_card; };};

void print_nr();void print_nr(); void print_all();void print_all();};};

ExampleExample

void adult::print_nr()void adult::print_nr(){{ cout << „ID_card: " << nr_ID_card << " ";cout << „ID_card: " << nr_ID_card << " ";}}

void adult::print_all()void adult::print_all(){{ person::print_all();person::print_all(); print_nr();print_nr();}}

Example – multiple derived classesExample – multiple derived classes

personperson

adultadult childchild

class child:class child: public person{{protected:protected: person * mom,person * mom, * dad;* dad;public:public: child(const char * name, const char * surname, child(const char * name, const char * surname,

person * mom, person * dad)person * mom, person * dad) :person(name, surname), mom(mom), dad(dad):person(name, surname), mom(mom), dad(dad) {{ };};// ~child() // default will do – why?// ~child() // default will do – why? void print_all();void print_all();};};

ExampleExample

void child::print_all()void child::print_all(){{ person::print_all();person::print_all(); cout << "mom: " ;cout << "mom: " ; mom->print_all();mom->print_all(); cout << "dad: " ;cout << "dad: " ; dad->print_all();dad->print_all();}}

Example – base and derived classesExample – base and derived classes

personperson

adultadult childchild

deputydeputy each each deputydeputy is is adultadult

class deputy:public adultclass deputy:public adult{{protected:protected: char * nr_access_card;char * nr_access_card;public:public: deputy(const char * name, const char * surname, deputy(const char * name, const char * surname,

const char * dowod, const char * access_card) const char * dowod, const char * access_card) :adult(name, surname, dowod), nr_access_card(aloc_string(access_card)):adult(name, surname, dowod), nr_access_card(aloc_string(access_card)) { { // person constructor cannot be called directly // person constructor cannot be called directly !! };}; ~deputy()~deputy() {{ delete delete [] [] nr_access_card;nr_access_card; }} void print_all();void print_all();};};

void deputy::print_all()void deputy::print_all(){{ adult::print_all();adult::print_all(); cout << "Access card: " << nr_access_card;cout << "Access card: " << nr_access_card;}}

ExampleExample

StructuresStructures Structures in C++ are classes tooStructures in C++ are classes too

struct A { struct A { contents...contents...

} } is equivalent to is equivalent to

class A {class A {public: public:

contents...contents... }}

Structures and classesStructures and classes Initiation in braces { } is Initiation in braces { } is onlyonly valid for classes: valid for classes:

whose all fields are public whose all fields are public that have no explicit constructorthat have no explicit constructor

struct s_xystruct s_xy{{ int x,y;int x,y;};};

s_xy sxy={10,20}; // oks_xy sxy={10,20}; // ok//s_xy sxy1(10,10) – bad!//s_xy sxy1(10,10) – bad!

struct xystruct xy{{ int x,y;int x,y; xy(int x, int y)xy(int x, int y) : x(x), y(y) {}: x(x), y(y) {}};};//xy xy1={10,20}; — //xy xy1={10,20}; — bad!bad!xy xy1(10,10); xy xy1(10,10); //ok//ok

UnionsUnions

In C++ a In C++ a unionunion is a class, but: is a class, but: It cannot contain objects with constructors or It cannot contain objects with constructors or

destructors defineddestructors defined There can be no access restrictions – all the fields There can be no access restrictions – all the fields

are are publicpublic It cannot inherit from a classIt cannot inherit from a class

Example – base and derived classesExample – base and derived classes

pointpoint

circlecircle vectorvector

rectanglerectangle

Declare classes, constructors, move(), +=Declare classes, constructors, move(), +=

Declare fieldsDeclare fields::

pointpoint int int ccolor; xy olor; xy locationlocation

circlecircle :public p:public pointoint int int radrad

vectorvector :public p:public pointoint xy xy sizesize;;

rectanglerectangle :public :public vectorvector

ExampleExample

struct xystruct xy{{ int x,y;int x,y; xy(int x, int y): x(x), y(y) xy(int x, int y): x(x), y(y) {{ }}

};};

class pointclass point{ { int color;int color; xy location;xy location;public:public: point(int color, xy loc) :color(color), location(loc) point(int color, xy loc) :color(color), location(loc) {{ }} void move(int dx, int dy)void move(int dx, int dy) {{ location.x+=dx;location.x+=dx; location.y+=dy;location.y+=dy; }} point & operator+=(int d)point & operator+=(int d) {{ return *this;return *this; }}};};

class circle: public pointclass circle: public point{{ int rad;int rad;  public:public: circle(int color, xy loc, int rad)circle(int color, xy loc, int rad) :point(color, loc), rad(rad) :point(color, loc), rad(rad) {{ }}   circle & operator+=(int d)circle & operator+=(int d) {{ (rad*=100+d)/=100;(rad*=100+d)/=100; return *this;return *this; }}};};

class vector: public pointclass vector: public point{{ xy size;xy size;  public:public: vector(int color, xy loc, int p2_x, int p2_y)vector(int color, xy loc, int p2_x, int p2_y) :point(color, loc), size(p2_x, p2_y) :point(color, loc), size(p2_x, p2_y) {{ }}   vector & operator+=(int d)vector & operator+=(int d) {{ (size.x*=100+d)/=100;(size.x*=100+d)/=100; (size.y*=100+d)/=100;(size.y*=100+d)/=100; return *this;return *this; }}

};};

class rectangle: public vectorclass rectangle: public vector{{public:public: rectangle(int color, xy loc, int p2_x, int p2_y)rectangle(int color, xy loc, int p2_x, int p2_y) :vector(color, loc, p2_x, p2_y) :vector(color, loc, p2_x, p2_y) {{ }}   rectangle & operator+=(int d)rectangle & operator+=(int d) {{ vector::operator+=(d);vector::operator+=(d);   return *this;return *this; }}  };};

Example cont.Example cont.

xyxy

pointpoint

circlecircle vectorvector

rectanglerectangle

How does the hierarchy change?How does the hierarchy change?

xy xy locationlocation int x,yint x,y

point :public xypoint :public xy int int ccolorolor

circlecircle :public p:public pointoint int int radrad

vectorvector :public p:public pointoint xy xy sizesize;;

rectanglerectangle :public :public vectorvector

class class pointpoint :public xy:public xy{{ int int ccolor;olor; // xy // xy locationlocation

public:public: ppointoint(int (int ccolor, xy olor, xy locloc) :) :ccolor(olor(ccolor), olor), xy(xy(locloc) ) {{ }}

void void movemove(int dx, int dy)(int dx, int dy) {{ x+=dx; x+=dx; // public// public in base in base y+=dy;y+=dy; }}

ppointoint & operator+=(int d) & operator+=(int d) {{ return *this;return *this; }}};};

CCononvversersionion derivedderived → → babasese

The cThe cononvversersion from „pointer to derived” to „pointer ion from „pointer to derived” to „pointer to base” is to base” is allowedallowed and and automaticautomatic (without explicit cast (without explicit cast operator)operator)

ifif inheritance was inheritance was publicpublic

Why only one-way conversion?Why only one-way conversion? ExampleExample

personperson o(…); o(…);adultadult d(…); d(…);childchild x(„ x(„WillyWilly”, „”, „SmithSmith”, &o, &d);”, &o, &d);

x.x.print_allprint_all() () // // does does notnot print ID_card of d (daddy) print ID_card of d (daddy)

CCononvversersionion derivedderived → → babasese

The cThe cononvversersion from „pointer to derived” to „pointer ion from „pointer to derived” to „pointer to base” is to base” is allowedallowed and and automaticautomatic (without explicit cast (without explicit cast operator)operator)

ifif inheritance was inheritance was publicpublic

Caution!Caution!: de: deleting converted pointerleting converted pointer

personperson *o=new *o=new adultadult("aa", "bb", "cc");("aa", "bb", "cc");delete o; delete o; // // does does notnot free the third field free the third field

Solution?Solution?: : vvirtualirtual destru destrucctortorss..

CCononvversersionion derivedderived → → babasese

A „A „referencreferencee to base class”to base class” may refer to object of derived class may refer to object of derived class ifif the inheritance was the inheritance was publicpublic

Notes on conversions of pointers and references:Notes on conversions of pointers and references: The cThe cononvversersions areions are transitivetransitive Allowed only with Allowed only with publicpublic inheritance inheritance ( (to avoid a backdoor to avoid a backdoor

access to inherited access to inherited private/protectedprivate/protected fields fields))

CCononvversersionion derivedderived → → babasese

class A {};class A {};class B: public A {};class B: public A {};class C: private A {};class C: private A {};

int fa(A a) {};int fa(A a) {};int fb(B b) {};int fb(B b) {};------------------------------------------------------------ A a;A a; B b;B b; C c;C c;

fa(a); fa(a); // // copy ccopy construonstrucctortor of of A A fa(b); fa(b); // // as aboveas above// fa(c); // // fa(c); // errorerror

// fb(a);// fb(a); fb(b);fb(b);// fb(c);// fb(c);

A *pa0=&a;A *pa0=&a; A *pa1=&b;A *pa1=&b;// A *pa2=&c;// A *pa2=&c;// B *pb=&a;// B *pb=&a;// C *pc=&a;// C *pc=&a;

A &ra0=a;A &ra0=a; A &ra1=b;A &ra1=b;// A &ra2=c;// A &ra2=c;// B &rb=a;// B &rb=a;// C &rc=a;// C &rc=a;

CCononvversersionion derivedderived → → babasese

class A {};class A {};class B: public A {};class B: public A {};class C: private A {};class C: private A {};class D: public B{};class D: public B{};

int fa(A a) {};int fa(A a) {};

------------------------------------------------------

D d;D d; fa(d); fa(d); // // transitivetransitive

Copy cCopy construonstrucctor tor in derived classin derived class

It is a constructor so:It is a constructor so:

Remember the order of constructors: base class(es) Remember the order of constructors: base class(es) constructor(s) will constructor(s) will alwaysalways run run..

One may supply parameters for base class constructor at One may supply parameters for base class constructor at initiation listinitiation list

RememberRemember: : also member objects will be constructedalso member objects will be constructed..

Copy cCopy construonstrucctor tor in derived classin derived class

class class derivedderived:public ba:public basese

{ ... };{ ... };

  

derivedderived::::derivedderived(const (const derivedderived & p) & p)

:ba:basese(p)(p) // // implicit cimplicit cononvversersion to base&ion to base&

{ ... };{ ... };

Copy cCopy construonstrucctor tor in derived classin derived class

A copy constructor may be implicit (generated) as are A copy constructor may be implicit (generated) as are default constructor and destructordefault constructor and destructorNoteNote: A constructor with no parameters is usually calle: A constructor with no parameters is usually calledd a a defaultdefault constructor, whether it is implicitly declared or generated.constructor, whether it is implicitly declared or generated.

If it is not defined explicitly, it will be generatedIf it is not defined explicitly, it will be generated Base class Base class copycopy con. will be called before con. will be called before implicitimplicit copy copy

constructor, (As opposed to the case of constructor, (As opposed to the case of explicitexplicit copy con. copy con. where where defaultdefault base con. is called) base con. is called)

Base class copy con. must be available (exist and be Base class copy con. must be available (exist and be publicpublic))

Assignment operator in derived classAssignment operator in derived class

Automatically generated (implicit) operator= will Automatically generated (implicit) operator= will copy copy member-by-membermember-by-member operator= from operator= from basebase class will be called class will be called beforebefore the the

operator=operator= operator= will not be implicit if operator= will not be implicit if

the class contains const or reference fields (also inherited)the class contains const or reference fields (also inherited) in any parent class or member object operator= is privatein any parent class or member object operator= is private..

will not function well for pointer fields (will not function well for pointer fields (shallowshallow copy) copy) For explicit operator=, the inherited operator= will For explicit operator=, the inherited operator= will

notnot be called automatically; one has to call it be called automatically; one has to call it explicitly. How? See explicitly. How? See →→

Assignment operator in derived classAssignment operator in derived class

class class derivedderived:: public bapublic base se { ... };{ ... };

derivedderived & & derivedderived::operator=(const ::operator=(const derivedderived & p) & p){{ if (this == &p)if (this == &p) return *this;return *this;

this->bathis->basese::operator=(p);::operator=(p); // alternat// alternativelyively: : babasese *pb=this; (*pb)=p; *pb=this; (*pb)=p; // // babasese *pb=this; pb->operator=(p); *pb=this; pb->operator=(p); // // babasese &rb=*this; rb=p; &rb=*this; rb=p;

// // place here assignment code for the fields declared in the derived classplace here assignment code for the fields declared in the derived class

return *this; return *this; // // return a resultreturn a result };};

ExampleExample

Copy constCopy construrucctortorss ans assignmentans assignment operator operators for s for personperson and and adultadult classes. classes.

class personclass person{{ char * name,char * name, * surname;* surname;……}}

class adult: public person class adult: public person

{{

char * nr_ID_card;char * nr_ID_card;

  

……

}}

ExampleExampleperson::person(const person &o)person::person(const person &o):name(aloc_string(o.name)),surname(aloc_string(o.surname)):name(aloc_string(o.name)),surname(aloc_string(o.surname)){}{}  person & person::operator=(const person &o)person & person::operator=(const person &o){{ if (this == &o)if (this == &o) return *this;return *this;

delete delete [] [] name;name; name=aloc_string(o.name);name=aloc_string(o.name); delete delete [] [] surname;surname; surname=aloc_string(o.surname);surname=aloc_string(o.surname);   return *this;return *this;}}

ExampleExampleadult::adult(const adult & d)adult::adult(const adult & d):person(d), nr_ID_card(aloc_string(d.nr_ID_card)):person(d), nr_ID_card(aloc_string(d.nr_ID_card)){}{}  adult & adult::operator=(const adult & d)adult & adult::operator=(const adult & d){{ if (this == &d)if (this == &d) return *this;return *this;

this->person::operator=(d);this->person::operator=(d);   delete delete [] [] nr_ID_card;nr_ID_card; nr_ID_card=aloc_string(d.nr_ID_card);nr_ID_card=aloc_string(d.nr_ID_card);   return *this;return *this;}}