Example 1: Method Overloading vs. Method Overriding
public class BaseClass
{
public virtual string Display()
{
return "BaseClass Display";
}
public string Display(int number)
{
return "BaseClass Display with number: " + number;
}
}
public class DerivedClass : BaseClass
{
public override string Display()
{
return "DerivedClass Display";
}
}
class Program
{
static void Main()
{
BaseClass obj = new DerivedClass();
Console.WriteLine(obj.Display()); // Output: "DerivedClass Display"
Console.WriteLine(obj.Display(10)); // Output: "BaseClass Display with number: 10"
}
}
- Concepts:
- Method Overloading: The
Display(int number)
method inBaseClass
shows overloading (same method name but different parameters). - Method Overriding:
DerivedClass
overridesDisplay()
to change the implementation.
- Method Overloading: The
Example 2: Interface vs. Abstract Class
public interface IShape
{
double Area();
}
public abstract class Shape
{
public abstract double Area();
public void Display()
{
Console.WriteLine("Shape Display");
}
}
public class Circle : Shape, IShape
{
private double radius;
public Circle(double r)
{
radius = r;
}
public override double Area()
{
return Math.PI * radius * radius;
}
}
class Program
{
static void Main()
{
Circle c = new Circle(5);
Console.WriteLine("Area: " + c.Area()); // Output: Area: 78.5398163397448
c.Display(); // Output: Shape Display
}
}
- Concepts:
- Abstract Class:
Shape
provides a common implementation (e.g.,Display()
), while forcing subclasses to implementArea()
. - Interface:
IShape
only declaresArea()
without any implementation, allowing multiple inheritance.
- Abstract Class:
Example 3: Method Hiding with new
Keyword
public class Animal
{
public void Speak()
{
Console.WriteLine("Animal speaks");
}
}
public class Dog : Animal
{
public new void Speak()
{
Console.WriteLine("Dog barks");
}
}
class Program
{
static void Main()
{
Animal myAnimal = new Dog();
myAnimal.Speak(); // Output: "Animal speaks"
}
}
- Concepts:
- Method Hiding:
Dog
hidesAnimal
'sSpeak()
method using thenew
keyword. - The method invoked depends on the reference type (
Animal
in this case), not the actual object type (Dog
).
- Method Hiding:
Example 4: Polymorphism with Interfaces
public interface IVehicle
{
void Drive();
}
public class Car : IVehicle
{
public void Drive()
{
Console.WriteLine("Car is driving");
}
}
public class Truck : IVehicle
{
public void Drive()
{
Console.WriteLine("Truck is driving");
}
}
class Program
{
static void Main()
{
IVehicle myVehicle = new Car();
myVehicle.Drive(); // Output: "Car is driving"
myVehicle = new Truck();
myVehicle.Drive(); // Output: "Truck is driving"
}
}
- Concepts:
- Polymorphism: The same interface (
IVehicle
) is used to refer to different types of vehicles (Car
,Truck
), but theDrive()
method behaves according to the actual object type.
- Polymorphism: The same interface (
Example 5: Abstract Class and Method Overriding
public abstract class Employee
{
public abstract void Work();
public void GetDetails()
{
Console.WriteLine("Employee details");
}
}
public class Manager : Employee
{
public override void Work()
{
Console.WriteLine("Manager works");
}
}
public class Developer : Employee
{
public override void Work()
{
Console.WriteLine("Developer works");
}
}
class Program
{
static void Main()
{
Employee emp = new Manager();
emp.Work(); // Output: "Manager works"
emp.GetDetails(); // Output: "Employee details"
emp = new Developer();
emp.Work(); // Output: "Developer works"
}
}
- Concepts:
- Abstract Class:
Employee
forces derived classes (Manager
,Developer
) to implement theWork()
method. - Method Overriding: Different implementations of
Work()
inManager
andDeveloper
.
- Abstract Class:
Example 6: Multiple Interfaces
public interface IPrintable
{
void Print();
}
public interface IScannable
{
void Scan();
}
public class MultiFunctionPrinter : IPrintable, IScannable
{
public void Print()
{
Console.WriteLine("Printing document");
}
public void Scan()
{
Console.WriteLine("Scanning document");
}
}
class Program
{
static void Main()
{
MultiFunctionPrinter mfp = new MultiFunctionPrinter();
mfp.Print(); // Output: "Printing document"
mfp.Scan(); // Output: "Scanning document"
}
}
- Concepts:
- Multiple Interface Implementation:
MultiFunctionPrinter
implements bothIPrintable
andIScannable
, demonstrating the ability to fulfill multiple contracts.
- Multiple Interface Implementation:
Name Hiding
public class A
{
public int Add(int a, int b)
{
return a + b;
}
}
public class B : A
{
public float Add(int a, int b) // name hiding
{
return a + b;
}
}
Class Definitions
- classA
public class classA
{
public virtual string Print() { return "classA"; }
}
classA
declares a virtual method Print()
that returns "classA". The virtual
keyword allows this method to be overridden in derived classes.
classB : classA
public class classB : classA
{
public override string Print() { return "classB"; }
}
classB
inherits from classA
. It overrides the Print()
method with its own implementation that returns "classB". The override
keyword indicates that it is overriding the base class (classA
) method.
classC : classB
public class classC : classB
{
public new string Print() { return "ClassC"; }
}
classC
inherits from classB
. It introduces a new method Print()
using the new
keyword. This means classC
has its own implementation of Print()
that hides (but does not override) the Print()
method from classB
.
Usage Example
classA a = new classC();
Console.WriteLine(a.Print()); // Output: "classB"
- Here, an instance of
classC
is created and assigned to a variable of type classA
. - Despite the variable
a
being declared as classA
, it actually points to an instance of classC
. - When
a.Print()
is called, the method that is invoked depends on the actual type of the object (classC
in this case), not the declared type of the variable (classA
). - Therefore,
a.Print()
calls the overridden method Print()
in classB
(since classC
inherits from classB
), which returns "classB".
Explanation
- Inheritance:
classC
inherits from classB
, which in turn inherits from classA
. This forms a hierarchy (classA
-> classB
-> classC
). - Method Overriding:
classB
overrides the Print()
method from classA
. classC
does not override Print()
; instead, it introduces a new method with the same name (Print()
) using new
. - Method Hiding: The
new
keyword in classC
's Print()
method indicates that it hides the Print()
method of classB
and does not participate in polymorphism. Hence, when a.Print()
is called, the method from classB
("classB"
) is invoked, not the one from classC
.
This behavior is why the output of Console.WriteLine(a.Print());
is "classB"
instead of "ClassC"
.
Class and Interface Definitions
- Interface IA
public interface IA
{
string Print();
}
IA
is an interface with a single method Print()
. Any class that implements this interface must provide an implementation for this method.
Class classA
public class classA : IA
{
public virtual string Print() { return "classA"; }
}
classA
implements the IA
interface by providing a Print()
method.The Print()
method is marked as virtual
, meaning it can be overridden in derived classes.
Class classB
public class classB : classA
{
public override string Print() { return "classB"; }
}
classB
inherits from classA
and overrides the Print()
method, changing the return value to "classB"
.
Class classC
public class classC : classB
{
public new string Print() { return "ClassC"; }
}
classC
inherits from classB
and introduces a new Print()
method using the new
keyword. This new method hides the overridden Print()
method in classB
but does not override it.
Class TakeAction
public class TakeAction
{
public void PrintName(IA obj)
{
Console.WriteLine(obj.Print());
}
}
- The
TakeAction
class has a method PrintName
that accepts an object implementing the IA
interface. - Inside the
PrintName
method, it calls obj.Print()
and prints the result to the console.
Main Code Execution
var obj = new TakeAction();
classA a = new classC();
obj.PrintName(a);
- An instance of
TakeAction
is created. - A variable
a
of type classA
is assigned an instance of classC
. - When
obj.PrintName(a)
is called:- Since
a
is of type classA
but references an instance of classC
, the actual method that gets called depends on the inheritance chain and method overrides. PrintName(a)
expects an object of type IA
, which classA
implements.- The
Print()
method in classB
is the one that gets called because classC
only hides the Print()
method with new
, but it doesn't override it. - The
Print()
method in classB
is an override of classA
's Print()
method, so it returns "classB"
.
Output
- The output of
Console.WriteLine(obj.PrintName(a));
will be "classB"
.
Key Concepts
- Inheritance:
classC
inherits from classB
, which inherits from classA
. - Method Overriding:
classB
overrides Print()
from classA
. - Method Hiding:
classC
introduces a new Print()
method that hides classB
's Print()
method but does not override it. - Interface Implementation:
classA
implements the IA
interface, which ensures that Print()
is a valid method for IA
type.
When PrintName(a)
is called, the runtime checks the actual type of a
(which is classC
) and walks up the inheritance chain to find the appropriate Print()
method to call. Since classC
hides but does not override the Print()
method, the overridden method in classB
is invoked, resulting in the output "classB"
.