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 inBaseClassshows overloading (same method name but different parameters). - Method Overriding:
DerivedClassoverridesDisplay()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:
Shapeprovides a common implementation (e.g.,Display()), while forcing subclasses to implementArea(). - Interface:
IShapeonly 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:
DoghidesAnimal'sSpeak()method using thenewkeyword. - The method invoked depends on the reference type (
Animalin 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:
Employeeforces derived classes (Manager,Developer) to implement theWork()method. - Method Overriding: Different implementations of
Work()inManagerandDeveloper.
- 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:
MultiFunctionPrinterimplements bothIPrintableandIScannable, 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".