Meta Descripation:Inheritance is a foundational concept in object-oriented programming (OOP) that allows us to create a new class that builds upon an existing class. It helps to organize code efficiently by sharing common functionality and properties across different classes, reducing redundancy and improving maintainability.
In this article, we'll explore inheritance with a practical example, focusing on vehicles, to demonstrate how and why inheritance is useful in building real-world applications. We'll also go in-depth into the use of the protected access modifier, a key aspect of inheritance.
Real-Life Scenario: Vehicles
Imagine you are designing software for a vehicle management system. The company makes different types of vehicles, such as Cars, Bicycles, and Trucks. While each vehicle type has its own unique features, they all share some common properties and behaviors:
- All vehicles have a name, a speed, and a way to start and stop.
- Cars may have air conditioning and different seating capacities.
- Bicycles have bells but do not use fuel.
- Trucks can carry heavy loads and have different load capacities.
Instead of repeating the shared properties and behaviors in each class, we can use inheritance. This way, we can define the common functionality in a base class and inherit from it to add specific features in derived classes.
Step 1: Creating the Base Class
We start by creating a base class named Vehicle
. This class will contain all the properties and methods common to every type of vehicle.
public class Vehicle
{
public string Name { get; set; }
public int Speed { get; set; }
protected int FuelLevel { get; set; } // Protected: Only accessible by Vehicle and its derived classes
public void Start()
{
Console.WriteLine($"{Name} is starting.");
}
public void Stop()
{
Console.WriteLine($"{Name} is stopping.");
}
public void Accelerate(int amount)
{
Speed += amount;
Console.WriteLine($"{Name} is accelerating to {Speed} km/h.");
}
public void Refuel(int amount)
{
FuelLevel += amount;
Console.WriteLine($"{Name} has been refueled by {amount} liters. Current fuel level: {FuelLevel} liters.");
}
}
Here, we defined:
-
Name
andSpeed
aspublic
properties. -
FuelLevel
as aprotected
property, meaning it can be accessed by theVehicle
class and any derived class but not from external classes. - Methods like
Start()
,Stop()
,Accelerate()
, andRefuel()
represent the common actions a vehicle can take.
Step 2: Creating the Derived Classes
Now, we create specific types of vehicles that inherit from the Vehicle
base class. These derived classes will add specific features that are unique to each vehicle type.
Car Class (inherits from Vehicle
)
public class Car : Vehicle
{
public bool HasAirConditioning { get; set; }
public void TurnOnAirConditioning()
{
if (HasAirConditioning)
{
Console.WriteLine($"{Name}'s air conditioning is now on.");
}
else
{
Console.WriteLine($"{Name} doesn't have air conditioning.");
}
}
public void Drive(int distance)
{
if (FuelLevel >= distance / 10)
{
FuelLevel -= distance / 10; // Use protected FuelLevel
Console.WriteLine($"{Name} drove {distance} km. Remaining fuel: {FuelLevel} liters.");
}
else
{
Console.WriteLine($"Not enough fuel for {Name} to drive {distance} km.");
}
}
}
Bicycle Class (inherits from Vehicle
)
public class Bicycle : Vehicle
{
public bool HasBell { get; set; }
public void RingBell()
{
if (HasBell)
{
Console.WriteLine($"{Name} is ringing the bell!");
}
else
{
Console.WriteLine($"{Name} doesn't have a bell.");
}
}
public void Pedal(int distance)
{
Speed += 5;
Console.WriteLine($"{Name} is pedaling {distance} km at speed {Speed} km/h.");
}
}
Truck Class (inherits from Vehicle
)
public class Truck : Vehicle
{
public int LoadCapacity { get; set; } // Load capacity in kg
public void LoadCargo(int weight)
{
if (weight <= LoadCapacity)
{
Console.WriteLine($"{Name} is now loaded with {weight} kg.");
}
else
{
Console.WriteLine($"{Name} cannot carry more than {LoadCapacity} kg.");
}
}
public void DriveWithCargo(int distance)
{
if (FuelLevel >= distance / 5)
{
FuelLevel -= distance / 5; // Use protected FuelLevel
Console.WriteLine($"{Name} drove {distance} km with cargo. Remaining fuel: {FuelLevel} liters.");
}
else
{
Console.WriteLine($"Not enough fuel for {Name} to drive {distance} km with cargo.");
}
}
}
Step 3: Using the Classes
Now that we have defined our classes, let’s see how inheritance works in action.
public static void Main(string[] args)
{
// Create a Car instance
Car car = new Car() { Name = "Sedan", Speed = 0, HasAirConditioning = true };
car.Refuel(50); // Refuel using a public method from Vehicle
car.Start(); // Use Start method from Vehicle
car.Drive(200); // Use Drive method from Car, which utilizes protected FuelLevel
car.TurnOnAirConditioning(); // Use Car-specific method
car.Stop(); // Use Stop method from Vehicle
Console.WriteLine();
// Create a Bicycle instance
Bicycle bicycle = new Bicycle() { Name = "Mountain Bike", Speed = 0, HasBell = true };
bicycle.Start(); // Use Start method from Vehicle
bicycle.Pedal(15); // Use Pedal method from Bicycle
bicycle.RingBell(); // Use Bicycle-specific method
bicycle.Stop(); // Use Stop method from Vehicle
Console.WriteLine();
// Create a Truck instance
Truck truck = new Truck() { Name = "Heavy Loader", Speed = 0, LoadCapacity = 10000 };
truck.Refuel(100); // Refuel using a public method from Vehicle
truck.Start(); // Use Start method from Vehicle
truck.LoadCargo(8000); // Use Truck-specific method
truck.DriveWithCargo(150); // Use Truck-specific method to drive with cargo
truck.Stop(); // Use Stop method from Vehicle
}
Understanding the protected
Access Modifier in Inheritance
The protected
access modifier is crucial in inheritance. It sits between public
and private
in terms of accessibility. Here’s a detailed breakdown:
-
public
: The member is accessible from anywhere. -
private
: The member is only accessible within the class itself. -
protected
: The member is accessible within the class it is defined in and any of its derived classes.
Think of protected
as a way to allow sharing specific details between a class and its "children," but to keep those details hidden from the rest of the world.
When to Use protected
protected
is useful when you have a base class that has members needing to be shared with derived classes, but you want to prevent direct access from outside classes. For example, internal logic, data, or behaviors that are common for derived classes but should not be exposed publicly.
Example: Employees
Consider an Employee base class and specific derived classes like Manager and Intern. All employees have a salary that is managed internally, but each employee type may have different calculations for bonuses or pay increases.
-
Base Class (
Employee
):
public class Employee
{
public string Name { get; set; }
protected decimal BaseSalary { get; set; } // Protected salary
public Employee(string name, decimal baseSalary)
{
Name = name;
BaseSalary = baseSalary;
}
public void ShowSalary()
{
Console.WriteLine($"{Name}'s base salary is {BaseSalary}.");
}
}
-
Derived Class (
Manager
):
public class Manager : Employee
{
public Manager(string name, decimal baseSalary) : base(name, baseSalary) { }
public void ApplyBonus()
{
// Using the protected member BaseSalary
BaseSalary += 2000;
Console.WriteLine($"{Name} received a bonus. New salary: {BaseSalary}.");
}
}
- Usage:
public static void Main(string[] args)
{
Manager manager = new Manager("Alice", 50000);
manager.ShowSalary(); // Public method, can be accessed from anywhere
manager.ApplyBonus(); // Apply bonus
manager.ShowSalary(); // Show updated salary
}
Benefits of protected
Controlled Access for Derived Classes:
protected
allows derived classes to access critical properties and methods without exposing them publicly. This is useful when you want derived classes to extend or alter certain behaviors.Encapsulation: It keeps members safe from outside interference. For example, the
FuelLevel
should only be modified in a controlled manner, either by derived classes or by public methods of the base class.Code Reuse and Flexibility:
protected
allows flexibility in derived classes to utilize or extend behaviors defined in the base class, supporting reuse and reducing redundancy.
Assignments
Easy Level
- Create a new derived class named Motorcycle that inherits from
Vehicle
. Add a propertyHasSideCar
and a methodToggleSideCar()
. - Write code to create an instance of Motorcycle, set its properties, and call its methods.
Medium Level
- Modify the Bicycle class to add a new property called
GearCount
and a method namedChangeGear(int newGear)
to adjust the bicycle's gear. - Create an instance of Bicycle, set the number of gears, and write code to change gears while pedaling.
Difficult Level
- Create a Bus class that inherits from
Vehicle
with a propertyPassengerCapacity
and a methodPickUpPassengers(int passengers)
. - Implement a feature to track the number of passengers on board, and include logic to prevent exceeding the passenger capacity.
- Write code to create a Bus instance, pick up passengers, and simulate driving a certain distance while managing the fuel level.
Conclusion
By understanding and applying inheritance, we can create well-structured, scalable, and maintainable applications. The key is to find the right balance between sharing functionality through the base class and customizing behavior in derived classes, all while ensuring encapsulation through access modifiers like protected.
Top comments (0)