3

Extensibility and Reusability – Inheritance at Work

LEARNING OBJECTIVES

At the end of this chapter, you should be able to understand the concepts of OOP paradigm regarding

  • Extending and deriving of new classes from existing classes.

  • Concepts of containment and inheritances.

  • Overloading and overriding base class functions.

  • Single and multiple inheritances.

  • Virtual functions.

  • Interfaces provided by Java language.

  • Run-time polymorphism and data binding and class as ADT.

  • OOP concepts like RTTI, decoupling and STL.

3.1 Extendibility and Reusability of OOP Paradigm

Classes have relationships amongst them which are responsible for making the OOP languages versatile and powerful. There are several tools and features provided by OOP languages to ensure reusability and extendibility, as follows: composition / containment, generalization / specialization in inheritance, virtual functions and abstract data types (ADTs), and standard template libraries (STL).

3.2 Extending / Deriving New Classes

We can derive a new class based on an existing class. This is possible through the inheritance and containment property afforded by OOP languages. Containment is class within a class, i.e. containment ensures all the member functions and member data of a contained class to the class containing the class.

Inheritance, on the other hand, is a technique to create a new class from an existing class by adding additional and many a times specialized functionality to it. Inheritance provides access to all non-private (public and protected) member data and member functions to the descendant class.

3.2.1 Containment: Class within a Class – Container Class

Container class is one of the techniques provided by OOP languages to achieve reusability of the code. Container class means a class containing another class or more than one class. For example, a computer has a microprocessor in it. In other words, it can also be called composition or aggregation.

In composition, one class (let us say Host) stores an instance of another class (let us call it Guest class) in an instance property. The Host class delegates work to the Guest class by invoking methods on that instance.

As an example, a Student class can have a data member belonging to a string class. Then we would say that the string class is contained in the Student class. The advantage of containment is that we can use a string class within a Student class to store details such as name and address belonging to a string class. Similarly, if we define a class called Date with day, month and year information, we can define the object of Date within a class called Student and define Date-related data such as DOB, DOJ, etc. Composition is a “has” type of relation.

 

Example 3.1:   Composition / Containment of C++

Composition means that the object comprises of several subobjects. For example, BankAccount has CurrentAccount and SavingsAccount. The containment relationship by drawing a line with a black diamond from the containing object to the contained object is shown in Figure 3.1, as per UML specifications.

 

Containment – composition

 

Figure 3.1 Containment – composition

 

Implementation in C++

class BankAccount { … };
class SavingAccount
{private: BankAccount Account;
};

Implementation in Java

Not supported in Java. The lifetime of a composite object depends completely on the garbage collector.

3.2.2 Inheritance and Class Hierarchy

Reusability of code is one of the strong promises made by OOP languages like C++ and Java, and inheritance is the tool selected to fulfill this promise. The concept of inheritance is not new to us. We inherit property, goodwill and name from our parents. Similarly, our descendants will derive these qualities from us. Study the inheritance class hierarchy shown in Figure 3.2. Humans and Animals derive qualities from living beings. Professionals, Students and Athletes are derived from Humans. We say these three categories have inherited from Human. Class Human is called a base class and Student and Athlete are called derived class or subclass. In Java language, base class is referred to as superclass. What can be inherited? Both member functions and member data can be inherited. Note that the direction of the arrow to indicate the inheritance relation is pointed upwards as per modelling language specifications.

 

Inheritance hierarchy

 

Figure 3.2 Inheritance hierarchy

 

Inheritance specifies is type of relation. Observe that a student is a human. Similarly, a mammal is an animal. Human is a base class / superclass and Student is a derived class / subclass. Derivation from base class is the technique to implement is type of relation. A base class can have more than one derived class.

When do we use inheritance? You inherit so that you can derive all the functionality and member data from base class, and derived class can add its own specialized or individualistic functionality. We can therefore say that subclasses are more specialized versions of their base class or superclass. They can derive all the functionality of superclass and also introduce its own specialized behaviour.

For example, Athlete derives all functionality and attributes of Human and in addition adds sports and athletic functionality and attributes on its own. Let us say that base class Human as defined a method called Work() and an attribute like hoursAtWork to indicate the number of hours Human spend at work. All the three subclasses of Human, namely, Person, Student and Athlete, will derive the functionality and attribute defined by the superclass. Thus, the code need not be written three times – writing it once is sufficient. In the example that follows we will show you sample statements for inheritance and other related topics in C++ and Java. However, the user is advised to refer to relevant chapters for detailed treatment of the topics.

 

Example 3.2:   Inheritance and Derivation in C++

class Human
{public:
  protected: // variables declared as protected are public to 
                derived classes
      // protected variables
};
      // Student inherited from Human, inheritance type is public
class Student : public Human
{public:
  private:
};

Note that members declared as private are not available to derived class. If you declare these member data as public then security is compromised. So what is the way out? Declare the member data as protected as shown above. If a public member function has the object, i.e. the object has invoked the member function, then that function can access

  • All the public member functions and public member data.
  • Public functions of a class can access all the private member data and member functions of its own class and protected member data and member functions of their base classes.

So, if you want the member data to be passed to derived class in inheritance, declare them as protected.

 

Example 3.3:   Inheritance and Derivation in Java

In Java, inheritance is achieved by extension. Suppose that we have a base class called Human with attributes and methods. Then the derived class, called subclass, is created by using the key word extends. This is shown in the example below:

Class Human
{// member data & methods}
class Student extends Human {
// new fields and methods defining a Student would go here}

This gives Student all the same fields and methods as Human, yet allows its code to focus exclusively on the features that make it unique.

3.2.3 Generalization vs Specialization

Generalization describes the relationship whereas inheritance is a tool or method of OOPS languages to implement generalization. We can say that generalization is a generic name for inheritance. Figure 3.3 shows an example.

 

Generalization – generic name for inheritance

 

Figure 3.3 Generalization – generic name for inheritance

 

Generalization means that the derived subclass is a subtype of base object. For example, CurrentAccount is a BankAccount. Therefore, we can say that BankAccount generalizes the common behaviour and attributes of CurrentAccount and SavingsAccount.

Common functionality be provided only in base class. That is, base class is generalization and derived class or subclass is specialization.

 

Example 3.4:   Generalization Implementation in C++ and Java

Implementation in C++

class BankAccount { … };
class SavingAccount : public BankAccount { … };

Implementation in Java

public class BankAccount { … }
public class SavingAccount extends BankAccount { … }

Now let us discuss the specifics of inheritance. Consider the base class called Father and derived class called Son, as shown in Figure 3.4. As a descendant you are privileged to inherit all non-private member data and member functions.

 

Inheritance at work

 

Figure 3.4 Inheritance at work

3.3 Overriding Base Class Functions

Suppose your father has a car. You can inherit and use the car for your mobility or you can buy a scooter and use the scooter instead. That is, you have overridden your father's method of Move() with your own functionality. So when you call Move() method, it calls your own move method and you will have to move on a scooter. If you want to use the car, you should call for Move() function defined by Father class explicitly like Father:Move().

Suppose base class (super) defines attributes such as age and weight, you can add additional attributes like height. Let us also suppose that super defines functionality such as Move() and Work(). Suppose you need a functionality to move by air, which your parent did not define, you can define your own function MoveByAir().

3.4 Overloading

A class can declare several variations in a function with the same name but with different implementations. This is termed as overloading. We show below base class overloading its Move() method:

Move() { cout<<”move by car”):
Move(int m) { cout<<” move by Bus”); // m =1
MoveFamily(int m , int n ) { cout<<”move with family”); // n=number

Now if derived class Son decides to override only on of the Move() function with its own implementation like: Move() { cout<<”Move by scooter”).

Then, balance two overloaded functions of base class shown below will be truncated and will not be available to derived class, namely:

Move(int m) { cout<<” move by Bus”); // m =1
MoveFamily(int m , int n ) { cout<<”move with family”); // n=number

However, subclass can call these functions by explicit mention of base class like Father:Move(int m).

3.5 Single and Multiple Inheritances

Inheritance means the ability to derive a new descendant class with additional functionality from base class. Inheritance is a powerful tool in the hand of programmer to define a new class from existing classes. There are different types of inheritances supported by OOPS languages.

In Figure 1.6a, we have shown single inheritance, wherein the derived class Person inherits from base class Human .In Figure 1.6b, multilevel inheritance is depicted, wherein Student inherits properties from Person, which in turn inherits from base class Human. In Figure 1.6c, we have shown hierarchical inheritance involving one base class and three derived classes.

Figure 1.6d depicts multiple inheritance, where base class is called virtual because single base class is being used by two derived classes, namely, derived class 1 (DC1) and derived class 2 (DC2). Further, you can see that derived class 3 (DC3) inherits from both DC1 and DC2. This type of inheritance is also called hybrid inheritance as there is a single derived class DC3 from two base classes DC1 and DC2.

3.6 Virtual Inheritance

Look at Figure 3.5. There is only one base class for both DC1, student, and DC2, athlete. The base class is called virtual base class and inheritance is termed as virtual inheritance. Virtual inheritance ensures that ambiguity that otherwise exists in case of more than one base class, does not exist.

 

Hybrid inheritance and virtual Inheritance

 

Figure 3.5 Hybrid inheritance and virtual Inheritance

 

In some situations, single inheritance is not sufficient and multiple inheritance leads to ambiguity. Consider the example presented in Figure 3.5.

A Student works at college laboratories and an Athlete works out at the gym after college hours. But let us say that recruiting companies need a Professional who works at college laboratories and also takes keen interest in gym and sports. We need a professional who inherits Work() of Students and also Work() of Athletes on requirement. In addition, the Professional must retain all the basic qualities of Human (shown as dotted arrow). Hence the relationship can be termed as hybrid inheritance.

Multiple Inheritance is Deriving a Class from More Than One Base Class

Also notice in Figure 3.5 that both Student and Athlete have the same base class, Human. This type of base class is called virtual base class because, though there is only one base class common to both derived classes, each of the derived class feels it has its own base class. In order to facilitate inheritance of properties, functions and member data selectively from Student and Athlete, we need to declare these two classes as virtual inheritance from the base class. The relationship is called virtual inheritance because, though there are base classes called Student and Athlete for derived class Professional, they act as if they do not exist and they are there only to pass whatever functions are demanded by derived class Professional.

We would declare virtual inheritance as shown below:

  class Student:virtual public Humans
  class Athlet:virtual public Humans

Professional class is declared as shown below

  class Professional : public Student, public Athlet

3.7 Problems with Multiple Inheritance

C++ no doubt provides a powerful feature such as multiple inheritance. However, this feature leads to ambiguity as regards deriving from more than one base class. In the example shown in Figure 3.6, professional inherits both from Student and Athlete. Imagine a case where both Student and Athlete classes define a function called Work(). Which function will professional then inherit? Surely ambiguity exists here.

 

Multiple inheritance – UML diagram

 

Figure 3.6 Multiple inheritance – UML diagram

 

Example 3.5:   Example for Multiple Inheritance in UML/C++

We know multiple inheritance means deriving from more than one base class. For example, refer to Figure 3.7.

 

Java's solution for ambiguity problems of C++ multiple inheritance

 

Figure 3.7 Java's solution for ambiguity problems of C++ multiple inheritance

Implementation in C++

class Student { … };
class Athlete { … };
class Professional : public Student, public Athlete { … };

Implementation in Java: NOT supported

3.8 Interface

As shown above, Java language has solved the problem ambiguity in multiple inheritance by simply not allowing multiple inheritance feature at all. Instead, it solves this problem by allowing only one inheritance, i.e. single base class and multiple interfaces. An interface provides names of the functions it provides service and a class can implement an interface which in turn has functions implemented in one of the derived classes of the interface.

 

Example 3.6:   Example for Interface in Java

Objects need to interact with users and the outside world. Java's interface is used by object to interact with the outside world. An interface simply will have names of all the functions for which the object provides functionality. Only names but no implementation. Therefore, we can say that interface is function names with empty bodies. For example, a Student objects interface is shown below:

  interface Student
  { void GetData();void ComputeResult();void Displayresult();}

Suppose name of our class is UGStudent, then we can use the interface Student, as shown below:

  class UGStudent implements Student
  {  // class definition here}

We can say that interface is a contract between the class and outside world regarding providing certain functionality.

3.9 Access Specifiers in Inheritance

Inheritance allows one data type to acquire the properties of another data type. But this facility largely depends on access specifiers used while inheriting. The access specifiers are public, private and protected.

  • Public Inheritance: Out of the three specifiers, public is most widely used. Indeed, when we say inheritance, we mean public inheritance. In public inheritance, all non-private members, i.e. public and protected members, are available to descendant classes.
  • Private Inheritance: This is less frequently used. Here only functionality is available to descendant classes but not attributes. For example, it is possible to fly like a bird by acquiring function Fly() through private inheritance, but one cannot become a bird by acquiring the attributes like colour, beak, wings, etc.
  • Protected Inheritance: This feature is least used since protected means public to descendant classes and private to others.

When access specifier is omitted, a class inherits privately, since only public accessory functions defined in the class become available to the descendant and not attributes, thus satisfying the definition of private inheritance. User-defined data type struct has no security access specifiers. Therefore, struct inherits publicly by default.

3.10 Run-time-type Information – RTTI

Dynamic_cast operator, which allows the program to safely attempt conversion of an object into an object of a more specific object type. This feature relies on run-time-type information (RTTI).

Static_cast operator: Objects known to be of a certain specific type can also be cast to that type with static_cast, a purely compile-time construct.

When base class function is overridden, exactly which of the base class function to call depends on the type of object. It is NOT possible to determine the type of the object at compile time. Hence, a pointer to base class, depending on the type of object that will be known only at run-time, dispatches the correct method. This feature is called dynamic method dispatch in Java or virtual function methods in C++.

3.11 Virtual Functions

In inheritance relation, the derived class gets access to protected member data through public accessory functions thereby achieving an important objective-oriented programming facility called code reusability.

But what about object to base class using the member functions belonging to derived class? This feature facilitates object to base class to execute any one of the derived class functions, depending on the user's choice at run-time.

This means that object to base class is provided with a bridge to selected derived class function and hence it can execute the function. The bridge is made available when we declare a virtual function in the base class and derived class overrides base class function.

If function is declared as virtual function in base class, we can execute an overriding function with the same name in the derived class with a pointer to base class. Pointer to base class is provided by virtual function. In summary, we can say that from base class we can execute any function with the same name as that of the virtual function in the base class, depending on the user's choice at run-time.

The above feature has been facilitated by C++ by providing variable pointers to a base class. These variable pointers can refer to objects of any derived classes of that type in addition to objects exactly matching the variable type. This allows arrays and other kinds of containers to hold pointers to objects of differing types. Because assignment of values to variables usually occurs at run-time, this is necessarily a run-time phenomenon. This feature facilitates run-time polymorphism and dynamic data binding explained in the next section. As the type of an object at its creation is known at compile time, constructors, and by extension copy constructors, cannot be virtual. If any functions in the class are virtual, the destructor should also be defined as virtual.

3.12 Pure Virtual Functions

C++ supports another variation of virtual functions like pure virtual functions. Virtual function can be converted by writing = 0 at the end of the function declaration:

 

virtual void FindArea() = 0;

 

Note that objects cannot be created for a class with pure virtual functions and such classes are called abstract data type (ADT). A member function can also be made “pure virtual” by appending it with = 0 after the closing parenthesis and before the semicolon. Objects cannot be created of a class with a pure virtual function and are called ADTs. Any derived class inherits the virtual function as pure and must provide a non-pure definition of it (and all other pure virtual functions) before objects of the derived class can be created. An attempt to create an object from a class with a pure virtual function or inherited pure virtual function will be flagged as a compile-time error.

3.13 Run-time Polymorphism and Dynamic Data Binding

Inheritance solves the problem of reusability. That is, derived class can access all the data members and function members of base class that are declared as protected. We have also learnt that derived class can override the functions defined in base class. Further, we have seen while dealing with virtual functions that with a pointer to base class we can call the derived class object. Combining the above two features of OOP language gives us a powerful tool, called run-time polymorphism and dynamic binding.

Refer to Figure 3.8 which shows hierarchical inheritance with virtual functions defined in base class and each of the derived class overriding the base class virtual function with its own implementation.

 

Hierarchical inheritance

 

Figure 3.8 Hierarchical inheritance

 

What this feature means to the programmer is that with a pointer to base class, we can decide at run-time to call particular derived classes overriding function. In other words, we can bind the overriding function from several of the derived classes with a pointer to base class. In the previous section we have seen the working of virtual functions with which we can achieve binding of derived class functions with a pointer to base class.

3.14 Class as Abstract Data Type

A class in object-oriented languages can also be called ADT.

The features of OOP language such as run-time polymorphism and dynamic binding will allow us to define a base class with virtual functions with no implementation (called pure virtual functions) or with dummy functionality just to indicate to the user that implementation is by derived class. These classes are called ADTs because they hide the implementation.

Refer again to Figure 3.8. We will declare a base class (ADT) called Shape. You will appreciate Shape has no definite shape, no definite area or perimeter or specific draw routine. Shape will hence declare virtual functions with only names and no implementation details. We will derive classes like Circle and Square and provide the solid implementation of these virtual functions. Solid means, all virtual functions will be implemented in each of the derived classes.

3.15 Separation of Behaviour and Implementation

ADT or base class with virtual function with no implementations is also called interfaces in some OOP languages. The base class will simply work as interface, informing the user about the functionality available, through definition of virtual functions and depending on the user's choice, the particular implementation from any one of the derived class is executed. The user is hidden from the details of implementation. The code of actual implementing function is linked to calling function only at run-time.

3.16 Decoupling

In inheritance, we have reusable code. Encapsulation means binding data and code. When run-time polymorphism is being used, it is best to polymorphically decouple the encapsulation to prevent discrete code modules from interacting with each other. In practice, you will notice that base class overridden function is automatically hidden and can be called explicitly by referring to the base class function.

3.17 Standard Template Library

One of the true definitions of objective-oriented programming is the ability of the programmer, through language, to use library facility. C++ has much developed Standard library in the form of stream IO library that provides extensive functionality for input and output. Standard template library (STL) is the most significant addition to library provided by C++. Using the module in STL, a programmer can write code using data structures and algorithm implementation for data structures like vectors, lists, queues, maps, etc.

3.18 Summary

  1. Extensibility and reusability of OOP languages have been realized with language features like inheritance, virtual inheritance, standard templates, etc.
  2. Containment represents a has type of relation. Supported by C++ but not supported by Java. A class contains an instance of another class.
  3. Containment is also called composition and aggregation in the literature.
  4. Base class is called superclass in Java. Derived class is termed as subclass. In inheritance, all non-private members are available to descendants. That is, base class is generalization and derived class or subclass is specialization.
  5. In inheritance, subclass functions can override base class overloaded functions. If subclass function overrides only one of the overloaded functions of base class, then balance overloaded functions will be truncated and will not be available to base class.
  6. Inheritance types supported by C++ are

    Single- and Multilevel inheritances

    Hierarchical inheritance

    Multiple and hybrid inheritance (not supported by Java)

  7. Multiple inheritance is deriving a class from more than one base class.
  8. Base class and derived class are called superclass and subclass in Java.
  9. Subclass methods can override base class functions. If such overriding takes place of overloaded base class functions, then balance of overloaded functions are truncated and they are not available to subclasses.
  10. If more than one subclass is derived from the same base class, then the base class is called a virtual base class.
  11. If a subclass derives from more than one base class, then to resolve the ambiguity arising out of the multiple inheritance relation, both the base classes must be declared as virtual. Inheritance is called virtual inheritance.
  12. Java solves the problems of ambiguity due to multiple inheritance type of relations by allowing only single inheritance but several interfaces. The interfaces contain only names of the functions and hide implementation of these functions. Implementation of an interface is also called realization.
  13. Dynamic_cast operator, which allows the program to safely attempt conversion of an object into an object of a more specific object type. This feature relies on RTTI.
  14. Run-time polymorphism means that with a pointer to base class, we can decide at run-time to call particular derived classes overriding function. In other words, we can bind the overriding function from several of the derived classes with a pointer to base class.
  15. Virtual Function: If function is declared as virtual function in base class, then we can execute an overriding function with the same name in the derived class with a pointer to base class. Pointer to base class is provided by virtual function.
  16. Pure Virtual Function in C++: Pure virtual functions are virtual functions with “=0” attached at the end. No object can be created for a class with pure virtual functions defined in it.
  17. Java supports interfaces to implement the concept of pure virtual functions of C++.

Exercise Questions

Objective Questions

  1. A subclass can have access to private data members of superclass – TRUE / FALSE
  2. Generalization means inheritance – TRUE / FALSE
  3. Specialization refers to
    1. Base class
    2. Subclass
    3. Superclass
    4. None
  4. Which of the following refer to containment:
    1. Composition
    2. Aggregation
    3. Has a
    4. Is a
    1. i and ii
    2. i, ii and iii
    3. i, ii and iii
    4. i, ii and iv
  5. Multiple and hybrid inheritance
    1. Supported by C++
    2. Supported by C++ and Java
    3. Supported by Java
    4. Supported by none
  6. If a subclass is derived from more than one base class, then the inheritance type is
    1. Multiple inheritance
    2. Virtual inheritance
    3. Virtual base class
    4. Multilevel inheritance
  7. Realization can be achieved by
    1. Extending a base class
    2. Implementing an interface
    3. Virtual functions
    4. None of these
  8. When a subclass redefines a base class function using the same name and signature, it is called
    1. Base class overloading
    2. Base class function override
    3. Base class function hiding
    4. None of these
  9. Composition is implemented using
    1. Has a
    2. Is a
    3. Interface
    4. Virtual function

    Short-answer Questions

  10. Explain composition / containment features of OOP languages.
  11. Generalization / specialization means inheritance. Do you agree?
  12. Distinguish between composition and inheritance.
  13. Why does Java not support containment?
  14. What are the types of inheritance supported by Java?
  15. What is the alternate provided by Java to multiple inheritance of C++?
  16. What is the difference between a class and an interface in Java?
  17. Can constructors be declared as virtual? Why or why not?
  18. Can destructors be declared as virtual? Why or why not?
  19. Distinguish overloading and overriding in inheritance relationship.
  20. What is an interface in Java?
  21. Explain access specifiers and their relevance in inheritance relation.
  22. Explain RTTI and dynamic cast operator.
  23. What are virtual functions? How are they useful?
  24. What are pure virtual functions? Why can objects not be instantiated to class with pure virtual functions defined inside?

    Long-answer Questions

  25. What are the various types of inheritance supported by OOP language?
  26. What are run-time polymorphism and run-time data binding?
  27. ADT / interface are supporting the concept of separation of behaviour and implementation. Do you agree?
  28. What is a virtual function? Why do we need virtual functions? What are the rules for virtual function implementation?
  29. What is an abstract class? Why do we need abstract classes? What are the rules governing virtual base class?

    Assignment Questions

  30. Write inheritance hierarchy for the animal kingdom.
  31. Explain polymorphism with a suitable example.
  32. Explain generalization and specialization with suitable examples.
  33. Explain the terms aggregation and separation with suitable examples.
  34. Explain various types of inheritances.
  35. When do you use inheritance and on what occasions do you use interface?

Solutions to Objective Questions

  1. False
  2. True
  3. b
  4. c
  5. a
  6. a
  7. b
  8. b
  9. a
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.117.73.127