Polymorphism & Inheritance in C#
Polymorphism & Inheritance in C#
Polymorphism & Inheritance in C#
Overview
Deriving Classes Implementing Methods Using Sealed Classes Using Interfaces Using Abstract Classes
Implementing Constructors
A constructor is a special type of method that is invoked when you create a new instance of a class. A constructor is used to initialize the members of the class. The name of a constructor is the same as the name of the class that contains it.
Types of Constructors
The two types of constructors are:
Instance constructors: They are called whenever an instance of a class is created. These constructors are used to initialize the data members of the class. Static constructors: They are used to initialize the static variables of a class. These variables are created using static keyword and they store values that can be shared by all the instances of a class.
Implementing Destructors
Destructors are special methods that are used to release the instance of a class from memory. A class can have only one destructor. The purpose of the destructor is to perform the required memory cleanup action. The .NET Framework automatically runs the destructor to destroy objects in the memory.
Declaration of Destructors
A destructor has the same name as its class but is prefixed with a ~ , which is the symbol of tilde. Destructors cannot be inherited or overloaded. Garbage collection is a process that automatically frees the memory of objects that are no more in use. The decision to invoke the destructor is made by a special program of C# known as the garbage collector. The process of garbage collection happens automatically. It ensures that:
Objects get destroyed Only unused objects are destroyed
Declaration of Destructors
C# provides the following methods to release the instance of a class from memory:
Finalize(): It is a special method that is called from the class to which it belongs or from the derived classes. The Finalize() destructor is called after the last reference to an object is released from the memory. Dispose(): This method is called to release a resource, such as a database connection, as soon as the object using such a resource is no longer in use. The IDisposable interface contains the Dispose() method. Therefore, to call the Dispose() method, the class must implement the IDisposable interface.
The destructor of all the object is invoked when the garbage collector is invoked. The Calc1 object has function scope. Therefore, its constructor is executed after the execution of Main() begins.
The Calc2 object has block scope. Therefore, its constructor is executed after the inner block begins.
} } }
Introducing Polymorphism
In Object-Oriented Programming (OOPs), polymorphism allows one interface to be used for multiple functions. Polymorphism reduces the complexity within the functions of a class of a program. Polymorphism can either be static or dynamic.
Static Polymorphism
Static polymorphism refers to an entity, which exists in various forms simultaneously. C# uses two approaches to implement static polymorphism. These are:
Function overloading: This approach allows using the same name for two or more functions. Each redefinition of a function must use different types of parameters, sequence of parameters, or a number of parameters. Operator overloading: This approach allows user-defined types such as structures and classes, to use overloaded operators for easy manipulation of their objects.
Dynamic Polymorphism
In dynamic polymorphism, the decision about function execution is made at run time. Dynamic polymorphism is more useful than static polymorphism as it provides much more flexibility for manipulating the objects. C# uses two approaches to implement dynamic polymorphism:
Abstract classes: Are the special type of base classes that consist of abstract class members. Virtual functions: Are the functions that do not really exist, however, appear to be present in some parts of the program.
Function Signature
The signature of a function is defined by:
The number of parameters The data types of parameters The sequence of the parameters
Constructor Overloading
Constructors can also be parameterized, and therefore, they can be overloaded. Overloaded constructors are commonly used in C# to provide flexibility while creating an object.
Operator Overloading
Operator overloading provides additional capabilities to C# operators when they are applied to user-defined data types. Only the predefined set of C# operators can be overloaded.
Operators +, -, ! , ~, ++ , --
Description These unary operators take one operand and can be overloaded.
+, -, * , /, %
The comparison operators can be overloaded. The conditional logical operators cannot be overloaded directly, but they are evaluated using & and | which can be overloaded.
+=, -=, *=, /=, %= =, ., ?:, ->, new, is, sizeof, typeof
Deriving Classes
Extending Base Classes Accessing Base Class Members Calling Base Class Constructors
class A derived class cannot be more accessible than its base class
class Token { ... class Outside protected string name; { } void Fails(Token t) class CommentToken: Token { { ... ... public string Name( ) t.name { ... Inherited protected members are implicitly protected in the derived class return name; } Methods of a derived class can access only their inherited protected }members } } Protected access modifiers cannot be used in a struct
class Token { protected Token(string name) { ... } ... } class CommentToken: Token { A private base class constructor cannot be accessed by a derived class public CommentToken(string name) : base(name) { } Use the base keyword to qualify identifier scope ... }
Implementing Methods
Defining Virtual Methods Working with Virtual Methods Overriding Methods Working with Override Methods Using new to Hide Methods Working with the new Keyword Practice: Implementing Methods Quiz: Spot the Bugs
Overriding Methods
Syntax: class Token Use the override keyword { ... public virtual string Name( ) { ... } } class CommentToken: Token { ... public override string Name( ) { ... } }
Working with Override inherited Methods You can only override identical
virtual methods
class Token { ... public int LineNumber( ) { ... } public virtual string Name( ) { ... } } class CommentToken: Token { ... public override int LineNumber( ) { ... } public override string Name( ) { ... } }
You must match an override method with its associated virtual method
You can override an override method You cannot explicitly declare an override method as virtual You cannot declare an override method as static or private
class Token { ... public int LineNumber( ) { ... } } class CommentToken: Token { ... new public int LineNumber( ) { ... } }
Resolve name clashes in code Hide methods that have identical signatures
class A { public virtual void M() { Console.Write("A"); } } class B: A { public override void M() { Console.Write("B"); } } class C: B { new public virtual void M() { Console.Write("C"); } } class D: C { public override void M() { Console.Write("D"); } static void Main() { D d = new D(); C c = d; B b = c; A a = b; d.M(); c.M(); b.M(); a.M(); } }
You can use sealed classes for optimizing operations at run time Many .NET Framework classes are sealed: String, StringBuilder, and so on Syntax: Use the sealed keyword
namespace System { public sealed class String { ... } } namespace Mine { class FancyString: String { ... } }
Using Interfaces
Declaring Interfaces Implementing Multiple Interfaces Implementing Interface Methods Implementing Interface Methods Explicitly Quiz: Spot the Bugs
Declaring Interfaces
Syntax: Use the interface keyword to declare methods
Interface names should begin with a capital I
type
Same parameters
class Token: IToken, IVisitable { string IToken.Name( ) { ... } void IVisitable.Accept(IVisitor v) Restrictions of explicit interface method implementation { ... You can only access methods through the interface } You cannot declare methods as virtual } You cannot specify an access modifier
Implementing Interface Methods Use the fully qualified interface method name Explicitly
class Token { string IToken.Name( ) { ... } static void Main( ) { IToken t = new IToken( ); } }
Declaring Abstract Classes Using Abstract Classes in a Class Hierarchy Comparing Abstract Classes to Interfaces Implementing Abstract Methods Working with Abstract Methods Quiz: Spot the Bugs
Token { abstract }
An abstract class cannot be instantiated
interface IToken { string Name( ); } abstract class Token: IToken { string IToken.Name( ) { ... } ... } class CommentToken: Token { ... } class KeywordToken: Token { ... }
IToken interface
Token { abstract }
interface IToken { string Name( ); } abstract class Token { public virtual string Name( ) { ... } ... }
IToken interface
Token { abstract }
Keyword class CommentToken: Token, IToken Comment { ... Token Token } class KeywordToken: Token, IToken concrete concrete { ... }
Differences
Interfaces cannot contain any implementation Interfaces cannot declare non-public members Interfaces cannot extend non-interfaces
abstract class Second { public abstract void Method( ) { } } interface IThird { void Method( ); } abstract class Third: IThird { }
Summary
Deriving Classes Implementing Methods Using Sealed Classes Using Interfaces Using Abstract Classes