440 likes | 644 Views
EEL 3801. Part VII Fundamentals of C and C++ Programming Inheritance. 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.
E N D
EEL 3801 Part VII Fundamentals of C and C++ Programming Inheritance
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 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 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 is-a is-a Sedan Convertible SUV is-a is-a is-a Taurus Mustang Explorer
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 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 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: • 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: 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 { public: void display(); void create_rec(char *, int); private: char * name; int year; };
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 { 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 class value cout << form(“Dorm ..”, dorm, room); }
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.display(); On_campus y; y.new_student(Billy Bob”, 1, “Seminole Hall”, “L301”); y.a_disp(); }
Example #2 - 2nd Derived Class class Off_campus : Student { public: void a_disp(); void new_student(char *, int, char *, char *, char *, char *); private: char *street; char *city; char *state; char *zip; };
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 *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 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 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 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() 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() 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 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 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 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 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 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 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. • 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 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() { 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) { 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*, 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 * 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 y(“Alex Gonzalez”, 1, “Seminole Hall”, “D301”); y.display(); // local display() }
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.
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
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; 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 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 in the derived class header. class Derived : public Base { public: Derived(int, int); do_it(); private: int y; };