Tuesday, December 6, 2011

- Inheritance & Polymorphism

Inheritance:
Inheritance facilitates code reuse which help you to build dependency between two or more class types (new class can be created using existing class).
Code reuse comes in two types:
  • Inheritance ("is-a" relationship)
  • Containment / Delegation model ("has-a" relationship)
Classical inheritance ("is-a" relationship)  helps you to build new class definitions that extend the functionality of an existing class. Existing class called base or parent class and the extended class know as derived or child class. In following example Circle class derived from Shape class

//Base or Parent class
class Shape
{
}

//Derived or Child class (Circle "is a" Shape)
class Circle : Shape
{
}

Note that a derived class never inherits the constructor of a parent class. Inheritance preserve encapsulation.
The .Net platform does not support multiple inheritance (MI) for classes, however it is permissible for an interface to directly drive from multiple interfaces.
When you use inheritance you need to keep some rules in mind:
  • Base class read-only properties out to initialize at base class constructor
  • The default constructor of base class is called before logic of the derived class is executed. That's why it is more efficient if you explicitly invoke the appropriate base class constructor by help of base keyword like following example:
//Base or Parent class
public class ProductItem
{
private int itemCode;
       private string itemName;

public ProductItem(int itemCode, string itemName)
       {
           ItemCode = itemCode;
           ItemName = itemName;
}
public int ItemCode
       {
            get{return itemCode;}
            set{itemCode = value;}
       }
public string ItemName
        {
            get{return itemName;}
            set{itemName = value;}
        }
}

//Derived or Child class (ChildProduct "is a" ProductItem)
public class ChildProduct: ProductItem
{
    public ChildProduct(int itemCode, string itemName, int productType)
        :base(itemCode, itemName )//call the appropriate base constructor
    {
        productType = productType;
    }
    private int productType;

    public int ProductType
    {
        get { return productType; }
        set{productType = value;}
    }
}

You may use base key word whenever you want to access a public or protected member of parent class.

sealed keyword:
By mark a class as sealed, the compiler will not allow you to derive from this type. Example:

sealed class SealedClassSample
{}

Nested Type:
C# supports nested type which gives you the possibility of defining a type (enum, class, interface, struct, or delegate) directly within the scope of a class or structure. Nested types provides following extra functionality:
  • Non-nested classes can not be declared as private but Nested types allows to have the complete control over the access level of inner type.
  • Since nested type is a member of the containing class, it can use of private members of containing class.
  • Usually, nested type is working as a helper for the other class and it is not for use by the outside world.
In order to use nested type in the outside world, you need to qualify it by the nested type. Example:

//outer class
public class OuterClass
{
    //inner class
    public class InnerClass
    {
    }
} 

//create the nested type in outside world
OuterClass.InnerClass inner;
inner = new OuterClass.InnerClass();
Nested type class diagram
Polymorphism: 
Subclasses can define their own version of a method defined by their base class using the process termed method overriding, which is know as polymorphism. Base class must mark by virtual keyword and the subclass need to mark by override keyword. Example:

class Shape
{
    //this method can be overridden by any subclasses
    //derived from Shape Class such as Circle class
    public virtual void Draw()
    {
    }
}

class Circle : Shape
{
    //override of Shape Draw method
    public override void  Draw()
    {
          //draw circle
    }
}

you can invoke the Draw method of the base class (Shape) like this:

base.Draw();
 
Sealing Virtual Members:
In order to prevent a derived type to override a particular virtual method we use sealed keyword. For instance in the following example SpecialCircle class can not override the Draw method as in marked sealed in Circle class.

class Circle : Shape
{
    //override of Shape Draw method
    public sealed override void  Draw() { }
}

class SepcialCircle : Circle
{
    //Draw method can not be overridden since it's marked sealed in base class (Circle) 
}

Abstract Classes:
Abstract classes are useful when you need a base class to define common members for all subclasses but direct instance of this class is meaningless since it is too general (not a concrete entity). abstract keyword is used to create abstract base class and there is no way to create an instance of abstract class. When derived class are created abstract based class assembled in memory. Here is an example:

//marked the class as abstract to prevent direct instantiation
abstract class Shape
{
}

Polymorphic Interface:
An abstract class may define any number of abstract members which don't have default implementation, however all subclass must implement the abstract members. By doing so, you enforce the polymorphic interface on all subclasses.

Member Shadowing:
Shadowing is opposite of member overriding; derived class defines member that is identical to a member define in base class. In this case derived class has shadowed the parent's version. For member shadowing compilers in Visual Studio 2010 give below warning:

‘ProjectName.DerivedClassName.MethodName()' hides inherited member ' ProjectName.BaseClassName.MethodName() ()'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword.

There is two methods to get rid of above warning:
  • Add virtual keyword to base method and override to derived method.
  • In case you don't have access to the base class you need to mark derived class with new keyword
By marking a method with new keyword you insure to hide the same method implementation in parent version. new keyword can be applied to any member type inherited from a base class (field, constant, static member, or property). You may invoke the base member or method by explicit casting.

Casting Rules, (as and is Keywords):
We can store a derived type in any valid base type reference (implicit cast). The ultimate base class in the system is System.Object. Therefore everything "is-a" object, so we can store an instance of any type within an object. Example:

//store derived class Circle in base class Shape
Shape myShape = new Circle();

On the other hand explicit cast allows you explicitly downcast using following syntax:

(classYouWantToCastTo) refernceYouHave
Object myShape2 = new Circle();
Shape anotherShape = (Shape)myShape2;

Keep in mind explicit casting is evaluated at runtime, not compile time. Therefore it is a good practice to place the explicit casting in try catch block. Alternatively C# provides as keyword which allow you to determine compatibility by checking against the null return. Consider the following:

Object myShape2 = new Circle();
Square mySquare = myShape2 as Square;
if (mySquare == null)
     Console.WriteLine("This shape is not a Square");

is keyword works just like as keyword is for compatibility detection between two items, however the return type for is keyword is bool (false insted of null if there are not compatibale).

System.Object:
It is final base class for every type in the .NET universe represent by object keyword. If the base class is not specify for a type it have derived from object class implicitly by compiler. Virtual, non-virtual and static members of object class are:

public class Object
{
    //Virtual members:
    public virtual bool Equals(object obj);
    public virtual int GetHashCode();
    public virtual string ToString();
       protected virtual void Finalize();

    //Non_Virtual members:
    public Type GetType();
    protected object MemberwiseClone();

    //Static members
    public static bool Equals(object objA, object objB);
    public static bool ReferenceEquals(object objA, object objB);
}

Let's go through the definition of above methods:
  • Equals(): returns true only if the items being compared refer to the exact same item in memory (default behavior). By default Equals method compare object references, not the state of the object.
  • Finalize(): is called to free any allocated resources before the object is destroyed.
  • GetHashCode(): returns an int that identifies a specific object instance.
  • ToString(): returns a string representation of this object,using <namespace>.<type name> (fully qualified name)
  • GetType(): returns a Type object that fully describes the object you are currently referencing. This is RTTI (Runtime Type Identification) method.
  • MemberwiseClone(): return a member-by-member copy of the current object.
Keep in mind after overriding Equals() you need to override GetHashCode() as well, since these methods used internally by Hashtable types to retrieve subobjects from the container.
ValueType class overrides Equals() method for all structures, so they work with value-based comparisons. Consider the following:

Shape shape1 = new Shape();
Shape shape2 = shape1;
Object object1 = shape2;
Console.WriteLine("shape1.ToString() :{0}", shape1.ToString());
Console.WriteLine("shape1.GetHashCode() : {0}", shape1.GetHashCode());
Console.WriteLine("shape1.GetType(): {0}", shape1.GetType());
Console.WriteLine("shape1.Equals(shape2): {0}", shape1.Equals(shape2));
Console.WriteLine("shape2.Equalas(object1): {0}", shape2.Equals(object1));

object methods example output







C# project "root namespace" of above project is CosoleApplication1 which is project name.

Overriding Equal():
In case you want to override the Equal() methods it is good practice to check the type of the incoming argument to make sure it is the proper type. Consider the following example:

//One way to over ride the Equals method
public override bool Equals(object obj)
{
    Shape myShape = obj as Shape;
    if (myShape != null)
    {
        //if all fields are equal return true otherwise return false
        if (myShape.Area == this.Area &&
            myShape.Color == this.Color)
            return true;
    }
    return false;
}

Another way to override the Equal method is implement a prim and proper ToString() method, that accounts for all field data up the chain of inheritance:

//Another way to over ride the Equals method if ToString() method 
//implementation is prime and proper
public override bool Equals(object obj)
{
    return obj.ToString() == this.ToString();
}

Overriding GetHashCode():
If you override the Equal() method you need to override the GetHashCode() as well, since a hash code is a numerical value that represents an object as particular state. By default GetHashCode() uses your current location in memory to yield the hash value. Since Hashtable internally invoking Equal() and GetHashCode() to retrieve the correct object, you need to override GetHashCode() if you are intending to use Hashtable.
There are many algorithms, in order to create the hash code. Most of the time String GetHashCode() is used to generate the hash code.
If there is a unique field data on your class for all instances (such as ID in following example), you may call GetHashCode for that field

//ID filed is unique for all instances
public override int GetHashCode()
{
    return ID.GetHashCode();
}

If there is no unique filed you may use the ToString() help if you have overridden it.

//ToString() filed is overridden
public override int GetHashCode()
{
    return this.ToString().GetHashCode();
}

System.Object Static Members:
In order to check the equality (value-base and reference base) System.Object defines two static members.

//value-base
Console.WriteLine("object1 == object2 ?: {0}",object.Equals(object1, object2));

//reference-base
Console.WriteLine("object1 == object2 ?: {0}", object.ReferenceEquals(object1, object2));

Reference: Pro C# 2010 and the .NET 4 Platform by Andrew Troelsen.

    2 comments: