Information and Computer Science Department, Yeditepe University

~ Inheritance ~

by Sadi Evren SEKER

ses@sadievrenseker.com


Below the topic inheritance we have to ignite the debate by abstract data types (you can see ADT as a shortcut).

1. ADT:

As you all know primitive data types, ADT is a new user defined type, that can be built on primitive data types.

In the structured programming languages (Such as C, Pascal, FORTRAN) it is not possible to create ADT by nature. They can be coded as special subprogram libraries in language. However in most of the Object Oriented (OO) Languages (Such as Java, Ada, C++) there are data abstraction features.

In C for example, “typedef” is a concrete example.


typedef{definition}student;

student NewStudent;


but here in C there is a problem for data encapsulation. (e.g. you can not use the key word private).

So how can we make an encapsulation?

There are two basic encapsulation methods: 1. Indirect encapsulation, 2. Direct encapsulation.

1.1. Indirect encapsulation:

In this kind of encapsulation, the compiler needs to know the signature of the procedure if it is called from another class, and only the class specification defines the types for each of the formal parameters (in and out parameters). So we need a pointer to keep track of the remote elements in current class.



Figure 1 (Indirect encapsulation)


In the figure 1, you can see Class B uses some elements (methods or variables) of Class A and because of indirect encapsulation there is a pointer P in class B.

This kind of encapsulation gives the advantage of short time recompilation. Think about the systems with thousands of modules, you do not recompile all the element P in each class. This is a compile-time advantage but it has a run-time penalty. Each access (especially repeated access) to element P requires an indirect pointer access to get the actual storage of element P.


1.2. Direct Encapsulation:

In this case the actual for element P is maintained within the activation record for Class B (in Java for example, Object B).




Figure 2 (Direct Encapsulation)


In figure 2, you can see, all the element P is in activation record of class B.


Both direct and indirect encapsulation can be used in any programing language that supports encapsulation.


2. Generic Abstract Data Types (GADT):


The second important subject that should be discussed just before inheritance is the generic abstract data types. Let's start with a Java example.


Class Vect {int [] X = new int[10]}


here X is an array of 10 components of type integer and Vect is a generic abstract data type.




2.1. Instantiation of a GADT definition:

Let's continue with the same Java example.


Vect ali= new Vect();


here you will endue with an instance (object) called “ali” of the class “Vect”. Another case may be the C++ class definition with “template” keyword.


template <class type_name> class classname class_definition


In the above C++ example, a new class is created by using the “template” keyword. So in the instantiation, the primitive type of a GADT is not essential, you can use any primitive type by using templates. In the structured programming languages (like C, Pascal, FORTRAN) macros can be used as GADT. For example in C you can use “#define” keyword.


3. INHERITANCE

Let's start with a simple C example.


{int i,j;

{float j,k;

k=i+j;

}


In the expression “k=i+j” both j and k are local variables, but i is a variable from outside of the block. So like the above example, we can implement classes and make the elements of one class available to other classes, since other classes has their own and individual elements. This operation is called inheritance.

Let's look at a more concrete example:

Figure 3 (Inheriting Bikes)
In object-oriented terminology, mountain bikes, racing bikes, and tandems (bikes with two or more riders) are all subclasses of the bicycle class. Some of the books call them as “Derived Classes”. Similarly, the bicycle class is the superclass (again in some text books it is called as “Base Class”) of mountain bikes, racing bikes, and tandems.
Each subclass inherits state (in the form of variable declarations) from the superclass. Mountain bikes, racing bikes, and tandems share some states: cadence, speed, and the like. Also, each subclass inherits methods from the superclass. Mountain bikes, racing bikes, and tandems share some behaviors: braking and changing pedaling speed, for example.
However, subclasses are not limited to the state and behaviors provided to them by their superclass. Subclasses can add variables and methods to the ones they inherit from the superclass. Tandem bicycles have two seats and two sets of handle bars; some mountain bikes have an extra set of gears with a lower gear ratio.
Subclasses can also override inherited methods and provide specialized implementations for those methods. For example, if you had a mountain bike with an extra set of gears, you would override the "change gears" method so that the rider could use those new gears.
You are not limited to just one layer of inheritance. The inheritance tree, or class hierarchy, can be as deep as needed. Methods and variables are inherited down through the levels. In general, the farther down in the hierarchy a class appears, the more specialized its behavior.
Inheritance offers the following benefits:
3.1. Single vs. Multiple Inheritance

If a programming language enables you to use inheritance it is the single inheritance by default. Some of the programming languages (such as C++) permit you to use multiple inheritance. You can see the differences better in the following figure.


Figure 4 (Single vs. Multiple Inheritance)

In figure 4, class A has two subclasses and class B has only one subclass. But in the left hand side of the figure all classes has only one superclass(obviously root A has no superclass). But in the right hand side of the figure class U has two superclasses(X and Y) which makes the inheritance structure multiple inheritance. Multiple inheritance is not possible in Java since it is possible in C++. C++ syntax of multiple inheritance is as following:


class U:X,Y {...}


3.2. Methods in Inheritance

Since inheritance is done in object oriented approaches and methods have some special circumstances, we should look closer to methods and their redefinition styles in inheritance. Let's continue to follow the empirical philosophy and start with a problem.


class ali{

public void subfunction(){printf(“I am subfunction of ali”);}

...

}


class veli:ali{

...

}


here in this example, as we have previously discussed class veli is a derived class and class ali is the base class. So by the definition of inheritance we can use the method “subfunction” inside of class veli, since it is the method of class ali. What will be the result of such an usage? It will obviously print out the string “I am subfunction of ali”. This is true for C++ but infact it is not true in real life. So we have 2 possible ways to solve this problem:

1. Overloading: We can redefine method subfunction() in class veli and the active method becomes the new defined subfunction for only class veli (and the classes inherited from class veli) by the following piece of code in class veli.


public void subfunction(){printf(“I am subfunction of veli”);}


2. Virtual Class: First approach is well for static bounding languages (like C, Pascal, Ada, Fortran). They are bounded at the definition of the method. But some languages (like Java, C++) gives a chance to bound dynamically. They are bounded at the time of the call of the subprogram. In C++ keyword “virtual” is used for this job. OK, lets see the dynamic version of above program.


In the class ali:

virtual void subsubfunction(){printf(“ali”);};

void subfunction(){printf(“I am subfunction of”,subsubfunction());}

In the class veli:

virtual void subsubfunction(){printf(“veli”);}

Main difference between two types is the binding time. It may be important for the classes where subfunction() is extremely long and complex. Rather than duplicating this method, with modifications, in each derived class, only a small virtual function of changes to the method need be redefined in each derived class.


3.3. Abstract Classes:

Abstract classes are only implements the definition of the class. They are used when a template is needed for classes. There are 2 applications:


1. Abstract Superclass: Think about the previous example, we have a method called subsubfunction() and this function is virtual. Now some a way we may want to force coder to implement subsubfunction() for all the derived classes. Else, there may be errors in the usage of subfunction() as we have already discusses. Solution is in C++:


virtual void subsubfunction()=0;


this piece of code makes the class ali abstract, and forces all derived classes to redefine this virtual function.


2. Mixin inheritance: This is an alternative approach to the abstract superclass, below line explains it very well.


class veli = class ali + deltaclass aradakifarklar;


This implementation is not possible in C++. This gives an advantage above superclass if you are using large classes.



Homework:

Subject: Inheritance

Duration: 1 week

Mission: Write two classes that there is an inheritance relation between them in below programming languages, discuss the similarities, differences, advantages and disadvantages between them.

C

Pascal

FORTRAN

C++

JAVA

Smalltalk (optional)

Ada (optional)






QUIZ (Inheritance)


1. What is Abstract Data Type? Give a simple example.





2. What is Inheritance? (Give a short and brief explanation).





3. Give the name of 3 languages that accept inheritance and 3 that does not.





4. In the case given below, which classes has multiple inheritance and which classes do not have?





5. What is a Virtual class, What is an Abstract class and what are the differences?






6. In the given code below,  what is the output on the screen?

class A {
  String name = "class A";
  public void print() {
    System.out.println("class A");
  }
}


class B extends A {
  String name = "class B";
  public void print() {
    System.out.println("class B");
  }
}
class test { 
   public static void main (String args[]) {
    B b = new B();
    A a = b;
    System.out.println(a.name); 
    System.out.println(b.name); 
    a.print();
    b.print();
}
}
7. In the given code below,  what is the output on the screen?

class Mammal {
  public:
    void speak() { cout << "can't speak" << endl; }
};
class Dog : public Mammal {
  public:
    void speak() { cout << "speaking dog" ;}
    void bark()  { cout << "barking dog" << endl;}
};
Mammal f1;
Dog    d;
Mammal* f2=new Dog;

f1.speak();
d.speak();
f2->speak();
f2->bark();
}