EEL 3801 Part VII Fundamentals of C and

  • Slides: 43
Download presentation
EEL 3801 Part VII Fundamentals of C and C++ Programming Inheritance

EEL 3801 Part VII Fundamentals of C and C++ Programming Inheritance

Inheritance • A form of software reusability in which new classes are derived from

Inheritance • A form of software reusability in which new classes are derived from existing classes. – Derived classes acquire their parent’s attributes. – They can enhance these attributes. – This encourages software re-use. • Avoids having to repeat general code for several related classes.

Inheritance - Terminology • Base class is the name for the parent from which

Inheritance - Terminology • Base class is the name for the parent from which all is being inherited. Is also called the superclass. • Derived class is the name for the class that does the inheriting. Is also referred to as the subclass. • Inheritance implements an is-a relationship: • For example - a mustang is-a car.

Hierarchical Inheritance • Inheritance is hierarchical: – A derived class can also act as

Hierarchical Inheritance • Inheritance is hierarchical: – A derived class can also act as a base class to a lower-level derived class. – The higher the class in the hierarchy, the more general information it contains. – The lower the class in the hierarchy, the more specific information it contains. • Attributes in a derived class overwrite the same ones in a base class.

Hierarchical Inheritance Automobile is-a Sedan is-a Taurus is-a Convertible is-a Mustang is-a SUV is-a

Hierarchical Inheritance Automobile is-a Sedan is-a Taurus is-a Convertible is-a Mustang is-a SUV is-a Explorer

Inheritance • Defined syntactically in C++ as follows: class Engineer : Employee. . .

Inheritance • Defined syntactically in C++ as follows: class Engineer : Employee. . . }; { • This is referred to as default inheritance. • Can be changed, as we shall see later.

Default Inheritance • A derived class contains all the information in the public: parts

Default Inheritance • A derived class contains all the information in the public: parts of the base class. • A public: member function of the base class is automatically a member function of the derived class. • Therefore, no reference to the base class is needed when calling a (public: ) base class function from the derived class

Inheritance • The derived class does not have access to the private: members of

Inheritance • The derived class does not have access to the private: members of the base class. • It must access private: members in the same way as external client functions through public: access functions. • This can be a significant constraint in the operation of derived class. • So the protected: members exist.

The protected: Members • A new type of access is now defined protected: –

The protected: Members • A new type of access is now defined protected: – Acts as a private: member to outside client functions. – Acts a public: member to derived classes. • All that applies to public: members also applies to protected: members from the point of view of the derived class.

The protected: Members • Member functions of derived classes can directly refer to public:

The protected: Members • Member functions of derived classes can directly refer to public: and protected: members of their base classes. • This means that they do not need to use the scope resolution operator to do so. • Here is an example of inheritance and its use.

Example #1 - Base Class #include <stream. h> #include <string. h> class Student {

Example #1 - Base Class #include <stream. h> #include <string. h> class Student { public: void display(); void create_rec(char *, int); private: char * name; int year; };

Example #1 - Member Functions void Student: : display() { cout << form(“n name:

Example #1 - Member Functions void Student: : display() { cout << form(“n name: . . “, name, year); }; void Student: : create_rec(char * n, int y) { name = new char[strlen(n) + 1]; strcpy(name, n); year = y; }

Example #1 - Derived Class // Derived class definition class On_campus : Student {

Example #1 - Derived Class // Derived class definition class On_campus : Student { public: void a_disp(); void new_student(char*, int, char*, char *); private: char *dorm; char *room; };

Example #1 - DC Functions void On_campus: : a_disp() { display(); // shows base

Example #1 - DC Functions void On_campus: : a_disp() { display(); // shows base class value cout << form(“Dorm. . ”, dorm, room); }

Example #1 - DC Functions Void On_campus: : new_student(char * n, int y, char

Example #1 - DC Functions Void On_campus: : new_student(char * n, int y, char * d, char * r) { create_rec(n, y); dorm = new char{strlen(d) + 1]; strcpy(dorm, d); room = new char[strlen(r) + 1]; strcpy(room, r); }

Example #1 - main() Function main() { Student x; x. create_rec(“Joe Smith”, 1); x.

Example #1 - main() Function main() { Student x; x. create_rec(“Joe Smith”, 1); x. display(); On_campus y; y. new_student(Billy Bob”, 1, “Seminole Hall”, “L 301”); y. a_disp(); }

Example #2 - nd 2 Derived Class class Off_campus : Student { public: void

Example #2 - nd 2 Derived Class class Off_campus : Student { public: void a_disp(); void new_student(char *, int, char *, char *); private: char *street; char *city; char *state; char *zip; };

Example #2 - Functions void Off_campus: : a_disp() { display(); //prints out basic values

Example #2 - Functions void Off_campus: : a_disp() { display(); //prints out basic values cout << form(“address …”, street, city, state, zip); }

Example #2 - Functions void Off_campus: : new_student(char *n, int y, char *s, char

Example #2 - Functions void Off_campus: : new_student(char *n, int y, char *s, char *cty, char *st, char *z) { create_rec(n, y); street = new char[strlen(s) + 1]; strcpy(street, s); city = new char[strlen(s) + 1]; strcpy(city, cty); state = new char[strlen(s) + 1]; strcpy(state, st); zip = new char[strlen(s) + 1]; strcpy(zip, z); }

Example #2 - main() Function main() {. // Up to this point same as

Example #2 - main() Function main() {. // Up to this point same as before. Off_campus z; z. new_student(“Sally Green”, 2, “ 123 Main Street”, “Oviedo”, “FL”, “ 32816”); z. a_disp(); }

Example #2 • Note that the member functions of the two derived classes have

Example #2 • Note that the member functions of the two derived classes have the same name. This is OK, as they are mutually-exclusive. • Both a_disp() functions are able to use the base class’s display() function, as it has public: access. • But their names are NOT the same as that of the base class. This would be ambiguous!

Example #3 • But what if we decided to re-label the function a_disp() within

Example #3 • But what if we decided to re-label the function a_disp() within the derived classes as display()? (change name) • We would need to disambiguate between display() functions in the base class and those in the derived classes. • We can do that with the : : scope resolution operator as follows:

Example #3 • The base class Student and its member functions display() and create_rec()

Example #3 • The base class Student and its member functions display() and create_rec() would remain unchanged from those of Example #1. • The On_campus and Off_campus derived classes would also be the same as in Example #2, except a_disp() would now be renamed display().

Example #3 • The biggest difference is how we disambiguate from the two display()

Example #3 • The biggest difference is how we disambiguate from the two display() functions: one in the base class, and one in the derived class: void On_campus: : display() { Student: : display(); cout << …; }

Over-written Functions • The same thing goes for the display() function in the Off_campus

Over-written Functions • The same thing goes for the display() function in the Off_campus derived class. • These functions are NOT overloaded, since they have exactly the same prototype (and header), and they are not in the same class. • They are over-written functions. • The over-written function that is closest to the object defined takes precedence.

Example #4 • If we use the class hierarchy defined in Example #3, and

Example #4 • If we use the class hierarchy defined in Example #3, and write the following main() function: main() { Student x; Off_campus y; x. display(); //display in base class y. display(); //display in der. class y. Student: : display() // base class }

Constructors and Destructors • Constructors and Destructors are also inherited since they are typically

Constructors and Destructors • Constructors and Destructors are also inherited since they are typically public. • However, there must be some coordination between those of the base and those of the derived classes: – which one executes first – how does the base constructor receive values from the derived constructor, if necessary.

Coordination • If constructors and destructors are defined both for the base and the

Coordination • If constructors and destructors are defined both for the base and the derived classes, – the base constructor is always called first. – the derived constructor is always called only after the base class constructor finishes. – The derived destructor is always called first. – the base destructor is always called only after the derived class destructor finishes.

Value Exchange • This is a little more difficult to describe. • When a

Value Exchange • This is a little more difficult to describe. • When a variable object of a derived class is being instantiated, an object of the base class must also implicitly be instantiated. • That base class “object” (it does not really exist explicitly) must also have run its constructor. • It needs values for that constructor to run.

Value Exchange • The required values must be appended to the definition of the

Value Exchange • The required values must be appended to the definition of the derived class object’s constructor when the object is instantiated. • The syntax is simple: Der_class(int x, int y, int z) : (x, y); • Where (x, y) are the values needed by the base class constructor. z is only required by the derived class constructor.

Value Exchange • For destructors, it is significantly easier, as they accept no arguments.

Value Exchange • For destructors, it is significantly easier, as they accept no arguments. • C++ takes care of any coordination and value exchanges to be done, if any, for the destructors.

Example #5 • This example shows the student class hierarchy with the constructors and

Example #5 • This example shows the student class hierarchy with the constructors and destructors added. • Only the differences will be shown for efficiency of space and lower confusion. • Note that the create_rec()function is replaced by the constructor as the means of creating a record for a student.

Example #5 - Base Class class Student { public: Student(char *, int); ~Student() {

Example #5 - Base Class class Student { public: Student(char *, int); ~Student() { delete name; } void display(); // void create_rec(char *, int); is // no longer needed private: char * name; int year; };

Example #5 - Base Class Constr. Student: : Student(char * n, int y) {

Example #5 - Base Class Constr. Student: : Student(char * n, int y) { name = new char[strlen(n) + 1]; strcpy(name, n); year = y; }

Example #5 - Derived Class class On_campus : Student { public: On_campus(char*, int, char*);

Example #5 - Derived Class class On_campus : Student { public: On_campus(char*, int, char*); ~On_campus() { delete dorm; delete room; } void display(); // void new_student() this function is // no longer used private: char * dorm; char * room; };

Example #5 - DC Constructor On_campus: : On_campus(char * n, int y, char *

Example #5 - DC Constructor On_campus: : On_campus(char * n, int y, char * d, char * r) : (n, y) { dorm = new char[strlen(d) + 1]; strcpy(dorm, d); room = new char[strlen(r) + 1]; strcpy(room, r); }

Example #5 - main() Function main() { Student x(“Joe Smith”, 1); x. display(); On_campus

Example #5 - main() Function main() { Student x(“Joe Smith”, 1); x. display(); On_campus y(“Alex Gonzalez”, 1, “Seminole Hall”, “D 301”); y. display(); // local display() }

Types of Inheritance • The default inheritance discussed before is also referred to as

Types of Inheritance • The default inheritance discussed before is also referred to as private inheritance: – Public members of the base class are inherited as private in the derived class. – Protected members of the base class are inherited as private in the derived class. – Private members of the base class are not inherited at all.

Example #6 - Private Inheritance class Base { public: Base(int); int display(); private: int

Example #6 - Private Inheritance class Base { public: Base(int); int display(); private: int x; }; class Derived : Base{ public: Derived(int, int); do_it(); private: int y; };

Example #6 - Private Inheritance class Sub_derived : Derived public: Sub_derived(int, int); do_it(); private:

Example #6 - Private Inheritance class Sub_derived : Derived public: Sub_derived(int, int); do_it(); private: int y; }; {

Example #6 - Private Inheritance main() { Base a(10); Derived b(5, 20); Sub_derived c;

Example #6 - Private Inheritance main() { Base a(10); Derived b(5, 20); Sub_derived c; a. display(); // permissible because // it is public in Base c. display(); // results in error // because it is // derived as private. }

Types of Inheritance • To rectify the problem, C++ also has two other types

Types of Inheritance • To rectify the problem, C++ also has two other types of inheritance: – public: • Public members in Base become public Members in Derived • Protected members in Base become protected members in Derived – protected: • Public and protected members in Base become protected members in Derived.

Public Inheritance • Can be accomplished by adding the word public after the colon

Public Inheritance • Can be accomplished by adding the word public after the colon in the derived class header. class Derived : public Base { public: Derived(int, int); do_it(); private: int y; };