[Skip Navigation] [CSUSB] / [CNS] / [CSE] / [R J Botting] / [CSci202] / inheritance
[Text Version] [Syllabus] [Schedule] [Glossary] [Resources] [Grading] [Contact] [Question] [Search ]
Notes: [01] [02] [03] [04] [05] [06] [07] [08] [09] [10] [11] [12] [13] [14] [15] [16] [17] [18] [19] [20]
Labs: [01] [02] [03] [04] [05] [06] [07] [08] [09] [10]
Tue May 31 15:31:57 PDT 2011

Contents


    Inheritance

      Why You Need It

      Inheritance is a labor-saving device.

      Inheritance lets you create new classes by adding things to an existing class. You don't change the old one. You don't have to recompile it. You tell the compiler that your new class is just like an older with some additional attributes(data) and operations(functions).

      The Problem

      Suppose you are a programmer for a college. They have already have designed, written, coded and tested a class called Person. An object in this class holds personal information about somebody like their Social Security Number, their names, their address, their gender, date_of_birth(dob), phone number, and so on. A Person also has functions (know-how) that can print the information in a standard format, display it, construct a new person from given data, destroy the records of a person, increase the age, change the name, handle a change of address, ... and so on.

      Your task is to create a very similar class called Student. A student object is a special kind of Person - one that can take courses, can add and drop sections, has a GPA, and so on. Just like a Person a student need to be able to print itself, display itself, construct it self, destroy all its data, increase its age, change a name, change an address, ... plus doing student things like adding, dropping, passing, failing, and such.

      In the old days you had to copy the Person class file and edit it to make the Student class. But this will take time and may introduce errors.

      Worse, when we had to change froma 2 digit year to a 4 digit year we had to do a duplicate change in to Student.

      When we had to change from SSNs to Student Ids we had to change the definition of Student as well.

      Now the college also needs a Faculty class, a Student_assistant class, and a Staff class. These are all different kinds of People! So, every time you change the code for Person, you have to edit the code for five other classes as well.

      A Solution form the 1970s

      It would be better to define the class Student so that it explicitly had a field for the personal data and #include the file containing the Person classes code (Person.h), and write a Student.h file like this:
       		#include "Person.h"
       		class Student {
       		  public:
       			//add, drop, pass, fail, ....
       		  private:
       			Person person;
       			float GPA;
       			//data structures pointing to sections
       		};//class Student
      In file Student.cpp would go the code for the implementations of functions specific to Student:
       	Student::add()
      and so on.

      But this does not give Student the public functions that a Person has. Because the person inside Student is a private Person we can not do anything "Personal".

      So you have to include in the public part of Student a list of functions that duplicates the functions in Person.

       		#include "Person.h"
       		class Student {
       		  public:
       			//add, drop, pass, fail, ....
       			//duplicated code from Person.h
       		  private:
       			Person person;
       			float GPA;
       			//data structures pointing to sections
       		};//class Student
      The code in "Student.cpp" must define functions like
       		void Student::add(....){.....}
      and also a complete set of functions like this:
       		void Student::display(){ person.display(); ...}
       		void Student::inc_age(int years){person.inc_age(years);...}
      etc. calling those in Person.


      (DRY): Duplicated code breaks the vital DRY principle of programming:

       		Don't Repeat Yourself!

      Similarly for all other "People-like" classes: Faculty, Staff, etc. you (and other people in your team) would have to write code for every function in People. And they would all be rather boring and similar.

      If Person is changed by adding, deleting or modifying any functions then so must all the People_like classes. This is not a good use of your time!

      Solution by Inheritance

      The modern solution is to use "inheritance". It makes sure that a Student has a complete up-to-date Person as part of the student! More, inheritance automatically gives the functions of Person to a Student! So if Student, Faculty, etc all "inherit from" Person, then when we change Person, its as if they had all changed as well. The computer is now working for us. We say that Student inherits Person's data and functions. We do it by declaring Student like this:
                class Student : public Person { .... };
      and then adding the new Student functions.

      In file Student.h we'd put something like this:

       		#include "Person.h"
       		class Student : public Person {
       		  public:
       			//add, drop, pass, fail, ....
       		  private:
       			float GPA;
       			//data about sections
       		};//class Student
      The above hides an invisible copy of the Person's data in Student. It implicitly makes Student have all the functions defined for a Person.

      In file Student.cpp would go the implementations of the functions like add and so on but not the ones in Person.

      Finally we can (if we need to) give Student its own ways of doing its parent's operations. All we do is list them in the Student specification, and implement them in the usual way.

      There is no need to declare or define functions that can be done by a Person inside Student. All Students inherit them from their parent: Person. However C++ will let a Student have its own version of a function of Person.

      Notice that the data describing a Person is effectively hidden inside the Student. In C++ it the first component in memory before the items added by Student. However these data items are not explicitly mentioned inside Student. There is no Person person item in student... but the data is hidden in there just the same.

      Similarly we can derive Faculty from Person. We would derive Staff from Person. We could derive Student_Assistant from Student or from Person or (perhaps) both.

      And when the Person class is changed, as long as 'Person.h' doesn't change, we don't even have to recompile the Student, Faculty, etc source files! All the other classes continue to link, load, and run with the new Person. We can change any derived class without fiddling with the base class. We can also derive new specializations without changing either the Person class or any of the Student, Faculty, ... classes.

      Simple Example

      We are working on a strange program that has Widgets and Wodgets. A Widget can be zarked. A Widget is just like a Wodget but it can be be both zarked and binked. He is how we would declare the classes in C++:
       	class Widget{ ..... void zark()..... };
       	class Wodget : public Widget{ ..... bink().....};

      Words

      We say that Student is derived from Person. Student inherits properties of a Person. We can also say the Student extends Person, or Person generalizes Student. We use an open headed arrow pointing from Student to Person [ Generalizations in uml1b ] in UML to indicate inheritance. We have all these different words because object-oriented languages are recent developments and their inventors all chose their own words for their ideas.
      Table
      UMLC++SmallTalkOther
      Specialderivedsubclasschild
      Generalbasesuperclassparent
      Attributedata memberattributedata field
      Operationfunctionmethod-
      Signatureheadermessage-

      (Close Table)

      For more on the the different words used by different groups of people see [ objects.glossary.html ] and for some informal definitions see [ Informal Definitions of Terms in objects.glossary ]

      Diagrams

      The Unified modelling Language (UML) [ Generalizations in uml1 ] is designed to make inheritance clearer. For example the diagram below shows that classes D1 and D2 both inherit operations from BB.

      [D1---|>BB<|---D2]

      Notice that BB, D1, and D2 have operation f(). In this case an object of class D1 executes D1's version of f(). We say that the D1 f() overrides the f() in BB. Also note that h() is owned by BB and so is inherited by both D1 and D2.

      Exercise: What operations belong to which class? Fill in the blanks in this table with the words: Has, No, Inherits BB, or overrides BB:
      Table
      Classf()g()h()
      BBHasNo_____
      D1Overrides BBHas_____
      D2_________Inherits BB

      (Close Table)
      [ Answer to first exercise ] below to see if you were correct.

      Similar diagrams are not difficult to do in code and makes complex derivations much easier to see. For example see: [ inheritance.cpp ] , and figure out what this program does? The [ Answer to second exercise ] is below.

      The above code is not quite correct. Functions are virtual in the UML and so this [ inhex.cpp ] is some C++ that encodes the above diagram better.

      Some Rules of Inheritance

      A derived class inherits all public data and functions from its base class, with the exception of its parent's constructors and destructors. Typically you have to rethink construction and destruction for the new class. Further they have the wrong names! However the base constructors can be called from inside the derived class and destructors are called automatically.

      A derived class does not get access to its base class's private data and functions. This is a breach of encapsulation. However a base class can declare certain data and functions to be protected. Protected data and functions can be accessed by objects and functions in derived classes - but there are some rather finicky rules about this.

    1. protected::=member of a class that is private to everybody except its children.

      Protected data and functions are declared exactly like private and public data and functions. The lexeme "protected" and colon(":") are placed before a list of declarations in the class.

      A derived class can add new functions and data to its base class.

      A derived class can also over-load (over-ride or redefine) functions in the base class. The over-ridden functions must be listed in the header and also defined later.

      It is not easy for a derived class to remove a function that it's base class defines. All you can do is overload the base function with a function that (1) does nothing, or (2) gives an error message. Wanting to do this may signal a need to rethink whether you have the right base class.

      A single base class can give rise to any number of derived classes. Each can add its own functionality and data to the common base class.

      A class can be both a parent and a child:

       		Person
       		   |
       		Student
       		   |
       		Student_assistant
      So you can describe a whole hierarchy of inter-related components. Object-oriented languages like Java [ java.class.tree.html ] [ java.html ] and Smalltalk [ smalltalk.classes.html ] [ smalltalk.html ] come with large ready made hierarchies of useful classes.

      People sell ready-made hierarchies of classes. The commonest of these describe the attributes and behavior of objects on a graphic display: Window, Button, Menu, Icon, and so on. For example when you buy Visual C++ you are getting C++ with such a hierarchy (MSFC) and tools for constructing new classes graphically from old ones. These are not free and only work on one kind of computer.

      Syntax

      1. derived_class_declaration::= class derived_class_name : public base_class_name { added_data_and_functions};

        Notice the new use of the reserved word: "public" and the position of the colon before the "public".

        Syntax Example

         class Student_intern: public Student { ... };

        Syntax Exercise

        Which of the following correctly derives class Lion from class Animal
        Net
        1. class Lion { public Animal animal; ... };
        2. class Lion public : Animal { ... };
        3. class Lion : public Animal { ... }
        4. class Lion::public Animal { ... };
        5. class Animal : public Lion { ... };

        (End of Net)

        The [ Answer to exercise ] is below.

      . . . . . . . . . ( end of section Syntax) <<Contents | End>>

      When to use inheritance

      Mathematically inheritance is rather like the subset relationship from set theory. Students are a subset of Human, and so Student behavior is based on Human behavior.

      Before you derive a new class D from a base class B ask yourself the following questions:
      Net

      1. Is each D a special kind of B?
      2. Is every D automatically a B?
      3. Is it impossible to have a D without also having a B?
      4. Is there exactly one B associated with each D and vice-versa?
      5. Are sure that the B is not really a part of D?
      6. Does each D behave rather like a B?
      7. Are they created and destroyed simultaneously?
      8. D isn't just a temporary role that a B plays for part of its life?
      9. D isn't just a temporary role that a B plays for part of its life?
      10. Are there always more (or the same number) of B's than D's?
      11. D isn't a particular instance of a template B<...>, is it?
      12. D and B don't share a common base, do they?

      (End of Net)

      If you answer: "yes, because...." to all of these you can be sure that the Ds should be derived from the Bs.

      Designing Class Hierarchies

      There has been a lot written about this. There have been several projects that have had problems later on because they skimped on the thinking involved. There is lots of reading and practice needed before you can claim to be good at this kind of design. [ Object-Oriented in methods ]

      Luckily human beings seem to be habitual makers of classification hierarchies In a complex project you must however make time early on to plan a stable hierarchy. This takes some thought, experimentation, and discussion. A well thought-out hierarchy can make a set of programs easy to develop. This called the architecture of the code. A badly thought out hierarchy can make modifying a program harder.

      Multiple Inheritance

      In C++ we can derive a new class from any number of parents. For example, if Student is the kind of Person who studies and Teacher is the kind of Person who teaches a class, and Employee is the kind of Person who is paid, then we might derive Student_assistant from Student, Teacher, and Employee. A student Intern might be derived from Student and Employee.
      	class Student_assistant : public Student, public Teacher, public Employee {
       		//constructors and destructors
       		//etc
       	}//class Student_assistant
      Faculty might be derived from Employee and Teacher, but not from Student.

      This is called multiple inheritance. It is a controversial idea. There are some odd difficulties with it. For example, If you derive a class D from two base classes: B1 and B2

       		class B1 {...};
       		class B2 {...};
       		class D: public B1, public B2 {...};
      and both B1 and B2 have a public function f, but D does not, then you can not tell if d.f() is really
       		 d.B1::f()
      or
       		 d.B2::f()
      This may be spotted by the compiler... but even if it is not, it is something to be avoided.

      Worse, if B1 and B2 are derived from a common third base class A:

       		class A                     {...};
       		class B1 : public A {...};
       		class B2 : public A {...};
       		class D: public B1, public B2 {...};
      then it is not clear how many As are in a D. Does each B have an A that is hidden in a D? Or is only one A hidden in D? In C++ the default is for D to have an A associated with B1 and another distinct A associated with B2. However, it is possible for B1 and B2 to be defined so that they will share a single A whenever they are both base classes for a derived class like D:
       		class A                     {...};
       		class B1 : virtual public A {...};
       		class B2 : virtual public A {...};
       		class D: public B1, public B2 {...};

      For the moment assume that multiple inheritance is to be avoided unless you are sure these problem do not occur.

      Joke

      It said that if you shoot your foot in C++ then the other foot also gets shot because its part of a virtual leg.

    . . . . . . . . . ( end of section Inheritance) <<Contents | End>>

    Next

    See Polymorphism [ polymorphism.html ] and Abstraction [ abstraction.html ]

    Answer to exercise

    They are all wrong! Here is the correct syntax for deriving class Lion from class Animal:
     	class Lion : public Animal { ... };
    (Don't forget the ';' at the end of the class!)

    Answer to second exercise

     		BBh BBf
     		BBh D1f D1g
     		BBh D2f D2g

    Answer to first exercise


    Table
    Classf()g()h()
    BBHasNoHas
    D1Overrides BBHasInherits BB
    D2Overrides BBHasInherits BB

    (Close Table)

    Glossary

  1. accessor::=`A Function that accesses information in an object with out changing the object in any visible way". In C++ this is called a "const function". In the UML it is called a query.
  2. Algorithm::=A precise description of a series of steps to attain a goal, [ Algorithm ] (Wikipedia).
  3. class::="A description of a set of similar objects that have similar data plus the functions needed to manipulate the data".
  4. constructor::="A Function in a class that creates new objects in the class".
  5. Data_Structure::=A small data base.
  6. destructor::=`A Function that is called when an object is destroyed".
  7. Function::programming=A selfcontained and named piece of program that knows how to do something.
  8. Gnu::="Gnu's Not Unix", a long running open source project that supplies a very popular and free C++ compiler.
  9. mutator::="A Function that changes an object".
  10. object::="A little bit of knowledge -- some data and some know how". An object is instance of a class.
  11. objects::=plural of object.
  12. OOP::="Object-Oriented Programming", Current paradigm for programming.
  13. Semantics::=Rules determining the meaning of correct statements in a language.
  14. SP::="Structured Programming", a previous paradigm for programming.
  15. STL::="The standard C++ library of classes and functions" -- also called the "Standard Template Library" because many of the classes and functions will work with any kind of data.
  16. Syntax::=The rules determining the correctness and structure of statements in a language, grammar.
  17. Q::software="A program I wrote to make software easier to develop",
  18. TBA::="To Be Announced", something I should do.
  19. TBD::="To Be Done", something you have to do.
  20. UML::="Unified Modeling Language".
  21. void::C++Keyword="Indicates a function that has no return".

End