Learning Objectives
After completing this session, you will be able to:: Explain Inheritance
Define Abstract Classes and Interfaces Describe Polymorphism using Interfaces
Inheritance
If you want an object that is very similar to one we already have, but with a few extra
characteristics. You just inherit a new class based on the class of the similar object. Inheritance is the process of creating a new class with the characteristics of an existing class, along with additional characteristics unique to the new class. Inheritance provides a powerful and natural mechanism for organizing and structuring programs.
Members and methods that are stored in classes in the class hierarchy are inherited by
subclasses, so you do not need to re-create them. Objects created from a subclass will contain not only the instances of the variables and methods of the child class, but also its parent class'
members and methods, as well as those of the parent of its parent class, and so on. When a members or method is referenced in an object, it is retrieved in a specific order: compiler first searches for it in the current class, then, if it is not found, it searches the parent class, and so on.
Class inheritance is designed to allow as much flexibility as possible. You can create inheritance trees as deep as necessary to carry out your design. An inheritance tree, or class hierarchy, looks much like a family tree; it shows the relationships between classes. Unlike a family tree, the classes in an inheritance tree get more specific as you move down the tree.
You create a derived class by adding a colon after the name of the derived class, followed by the name of the base class:
public class Honda : Car
Calling Base Class Constructors:
The Honda class constructor invokes the constructor of its parent by placing a colon (:) after the parameter list and then invoking the base class with the keyword base.
If the base class has an accessible default constructor, the derived constructor is not required to invoke the base constructor, as the default constructor is called implicitly. If the base class does not have a default constructor, every derived constructor must explicitly invoke one of the base class constructors using the base keyword.
public void Honda() : base {
this.Model = "Honda"; }
Calling Base Class Methods:
If a class needs to call a method in the base class then this is achieved using the base keyword followed by the method required in the usual manner using dot notation.
base.StartCar ();
Unlike C++, multiple inheritances are not allowed in C# and a similar effect can be achieved using interfaces, which is discussed shortly.
In some cases, a class may want to 'overwrite' a base method. C# supports two different ways of method overwriting - 'hiding' or 'overriding'. Note that the term 'overwrite' is a term we have devised to cover both hiding and overriding.
Method overwriting makes use of the following three method-head keywords: new, virtual,
override. The main difference between hiding and overriding relates to the choice of which method to call where the declared class of a variable is different to the run-time class of the object it references. This point is explained further below.
Abstract Class
The abstract keyword enables to create classes and class members solely for the purpose of inheritance—to define features of derived, non-abstract classes. Classes can be declared as abstract. This is accomplished by putting the keyword abstract before the keyword class in the class definition.
Example:
Public abstract class A {
// Class members here. }
An abstract class cannot be instantiated. The purpose of an abstract class is to provide a common definition of a base class that multiple derived classes can share. For example, a class library may define an abstract class that is used as a parameter to many of its functions, and require
programmers using that library to provide their own implementation of the class by creating a derived class.
Abstract classes may also define abstract methods. This is accomplished by adding the keyword abstract before the return type of the method. For example:
Public abstract class A {
Public abstract void DoWork (int i); }
Abstract methods have no implementation, so the method definition is followed by a semicolon instead of a normal method block. Derived classes of the abstract class must implement all abstract methods. When an abstract class inherits a virtual method from a base class, the abstract class can override the virtual method with an abstract method.
Example:
public class D {
Public virtual void DoWork (int i); {
// Original implementation.
} }
Public abstract class E : D {
Public abstract override void DoWork (int i); }
Public class F; E {
Public override void DoWork(int i); {
// New implementation }
}
If a virtual method is declared abstract, it is still virtual to any class inheriting from the abstract class. A class inheriting an abstract method cannot access the original implementation of the method—in the previous example; DoWork on class F cannot call DoWork on class D. In this way, an abstract class can force derived classes to provide new method implementations for virtual methods.
Interface
There are situations when we don't want to create a new type. Rather, to describe a set of behaviors that any number of types might implement. For example, we want to describe what it means to be storable (that is, capable of being written to disk) or printable.
Such a description is called an interface. An interface is a contract; the designer of the interface says "if you want to provide this capability, you must implement these methods." The implementer of the interface agrees to the contract and implements the required methods. When a class implements an interface, it tells any potential client "it will support the methods, properties, events, and indexers of the named interface." The interface details the return type from each method and the parameters to the methods.
The syntax for defining an interface is very similar to the syntax for defining a class or a struct: [access-modifier ] interface interface-name [: base-list ] {interface- body }
Access modifiers (public, private, and so on.) work just as they do with classes. (Refer Session 13 for more about access modifiers.) The interface keyword is followed by an identifier (the interface name). It is common (but not required) to begin the name of your interface with a capital I
(IStorable, an existing interface to add new methods or members, or to modify how existing members work.
pubic interface IStorable {
void Read();
void Write(object); }
If you are designing a to new class say Document class, that will support this feature, then you implement this interface like this.
public class Document : IStorable
It is the responsibility of the Document class, to provide a meaningful implementation of the IStorable methods. Having designated Document as implementing IStorable, it must implement all the IStorable methods, or it will generate an error when you compile. An interface can define that the implementing class will provide a property (Refer Session 13 for a discussion of properties).
Notice that the IStorable method declarations for Read() and Write() do not include access modifiers (For example, public, protected, internal, private). In fact, providing an access modifier generates a compile error. Interface methods are implicitly public because an interface is a contract meant to be used by other classes. As mentioned earlier, Classes can derive from only one class, but classes can implement any number of interfaces.
public class Document : IStorable, ICompressible
Casting to an Interface:
You cannot instantiate an interface directly; that is, you cannot write: IStorable isDoc = new IStorable();
Instead you instantiate a class that implements the interface. Casting is safe to do because the Document object implements IStorable and thus is safely treated as an IStorable object. You cast by placing the type you are casting to in parentheses. The following line declares a variable of type IStorable and assigns to that variable the Document object, cast to type IStorable:
Document doc = new Document("Test Document"); IStorable isDoc = (IStorable) doc;
There may be instances in which you do not know in advance (at compile time) that an object supports a particular interface. For instance, given a collection of objects, you might not know whether each object in the collection implements IStorable, ICompressible, or both. The is operator lets you query whether an object implements an interface.
if (doc is IStorable) {
IStorable isDoc = (IStorable) doc; isDoc.Read();
}
Summary
Inheritance: Inheritance is the process of creating a new class with the characteristics of an existing class, along with additional characteristics unique to the new class. Abstract Class: The abstract keyword enables to create classes and class members
solely for the purpose of inheritance—to define features of derived, non-abstract classes. Classes can be declared as abstract.
Interfaces: Interfaces, like classes, define a set of properties, methods, and events. But unlike classes, interfaces do not provide implementation. They are implemented by classes, and defined as separate entities from classes.
Test Your Understanding 1. What is inheritance?
2. Does C# support multiple inheritances? 3. What is the advantage of using inheritance? 4. What is an abstract class?
5. How do you achieve multiple inheritances in C#? 6. Differenciate between abstract class and interfaces.