Loading...

OBJECT ORIENTED PROGRAMMING  

>

LEARNING OUTCOME 2

APPLY OBJECT-ORIENTED PROGRAMMING PRINCIPLES TO SOLVE PROGRAMMING PROBLEMS AND WRITE EFFICIENT CODE

CLASS VS. OBJECT

In C#, classes and objects are fundamental concepts for building applications. Here's a breakdown to clarify the distinction:

CLASS:

OBJECT:

Here's a table summarizing the key differences:

Feature Class Object
Represents Blueprint or template Concrete instance
Reusability Reusable Not reusable (multiple objects can be created from a class)
Properties Defines properties (data) Holds values for those properties
Methods Defines methods (functions) Can execute those methods

Example:

C#
		public class Car // Class definition (blueprint)
		{
			public string Model { get; set; } // Property (data)
			public int Year { get; set; } // Property (data)
			public void StartEngine() // Method (function)
			{
				Console.WriteLine("Engine started!");
			}
		}
		Car myCar = new Car(); // Creating an object of the Car class
		myCar.Model = "Tesla Model S"; // Assigning values to object properties
		myCar.Year = 2024;
		myCar.StartEngine(); // Calling a method on the object
		

In this example, the Car class defines the blueprint for car objects. We can then create objects (instances) like myCar from this class. Each Car object will have its own Model and Year properties, along with the ability to call the StartEngine() method.

CONSTRUCTORS AND DESTRUCTORS IN C#

CONSTRUCTOR:

Example:

C#
		public class Car
		{
			public string Model { get; set; }
			public int Year { get; set; }
			public Car(string model, int year) // Constructor with parameters
			{
				Model = model;
				Year = year;
			}
		}
		Car myCar = new Car("Ford Mustang", 2020); // Constructor is called here
		

In this example, the Car class now has a constructor that takes two arguments (model and year). When we create a new Car object (myCar), the constructor is automatically called and assigns the provided values to the object's properties.

DESTRUCTOR:

Important Note: C# has automatic garbage collection, so in most cases, you don't need to worry about explicitly calling destructors. However, understanding their purpose can be beneficial in specific scenarios where manual resource management is required.

ACCESS SPECIFIERS

In C#, access specifiers are keywords used to define the accessibility (visibility) of classes, members (properties, methods), and other elements within your code. They control who can access and use these elements from different parts of your program. Here's a breakdown of the commonly used access specifiers:

  1. Public:

    Members declared as public are accessible from anywhere in your program, regardless of the namespace or assembly they are defined in. This is the most permissive access level.

    Example:

    C#
    		public class MyClass
    		{
    			public string PublicProperty { get; set; }
    			public void PublicMethod()
    			{
    				Console.WriteLine("This is a public method!");
    			}
    		}
    		// Accessing public members from another class
    		AnotherClass obj = new MyClass();
    		obj.PublicProperty = "Hello";
    		obj.PublicMethod();
    		
  2. Private:

    Members declared as private are only accessible within the class they are defined in. They are hidden from other classes and parts of your program. This promotes encapsulation and data protection.

    Example:

    C#
    		public class MyClass
    		{
    			private string privateField = "This is private!";
    			public string GetPrivateField()
    			{
    				return privateField; // Private field can be accessed within the class
    			}
    		}
    		// Accessing a private member from another class (compile-time error)
    		AnotherClass obj = new MyClass();
    		// Console.WriteLine(obj.privateField); // This line will cause an error
    		
  3. Protected:

    Members declared as protected are accessible from the class they are defined in, as well as from derived classes (classes that inherit from the base class). This allows for controlled inheritance and data sharing within a class hierarchy.

    Example:

    C#
    		public class BaseClass
    		{
    			protected int protectedValue = 10;
    			public void PrintProtectedValue()
    			{
    				Console.WriteLine("Protected value: {0}", protectedValue);
    			}
    		}
    		public class DerivedClass : BaseClass
    		{
    			public void AccessProtectedMember()
    			{
    				Console.WriteLine("Accessing protected value from derived class: {0}", protectedValue);
    			}
    		}
    		
  4. Internal:

    Members declared as internal are accessible from within the same assembly (compiled unit of code). This is useful for restricting access to members within a specific project or library.

    Example (Imagine two C# files in the same project):

    C#
    		// File1.cs
    		internal class InternalClass
    		{
    			internal void InternalMethod()
    			{
    				Console.WriteLine("This is an internal method!");
    			}
    		}
    		// File2.cs (same project)
    		class MyClass
    		{
    			public void UseInternalClass()
    			{
    				InternalClass obj = new InternalClass();
    				obj.InternalMethod();
    			}
    		}
    		
  5. Protected Internal (C# 6.0 and above):

    Members declared as protected internal combine the accessibility of protected and internal. They are accessible from derived classes (like protected) and also from within the same assembly (like internal).

  6. Private Protected (C# 6.0 and above):

    Members declared as private protected are a niche access specifier. They are only accessible from derived classes within the same assembly.

ENCAPSULATION, INHERITANCE, AND POLYMORPHISM

ENCAPSULATION:

BENEFITS OF ENCAPSULATION:

INHERITANCE:

TYPES OF INHERITANCE:

POLYMORPHISM:

TYPES OF POLYMORPHISM:

Example of Inheritance and Polymorphism:

C#
public class Animal // Base class
{
    public virtual void MakeSound() // Virtual method for sound
    {
        Console.WriteLine("Generic animal sound");
    }
}
public class Dog : Animal // Derived class
{
    public override void MakeSound() // Overridden method for dog sound
    {
        Console.WriteLine("Woof!");
    }
}
public class Cat : Animal // Derived class
{
    public override void MakeSound() // Overridden method for cat sound
    {
        Console.WriteLine("Meow!");
    }
}
static void Main(string[] args)
{
    Animal animal1 = new Dog(); // Polymorphism - actual object type is Dog
    animal1.MakeSound(); // Output: Woof! (dynamic binding)
    Animal animal2 = new Cat(); // Polymorphism - actual object type is Cat
    animal2.MakeSound(); // Output: Meow! (dynamic binding)
}

By effectively using encapsulation, inheritance, and polymorphism, you can write cleaner, more maintainable, and reusable code in C#.

C# program that demonstrates inheritance, encapsulation, and polymorphism

Scenario: We'll build a simple program to manage different shapes (square and circle) and calculate their areas.

C#
public class Shape // Base class (encapsulation)
{
    private double _width; // Encapsulated property (data protection)
    public double Width
    {
        get { return _width; }
        set { _width = value; }
    }
    public virtual double GetArea() // Virtual method for area calculation (polymorphism)
    {
        return 0; // Placeholder, will be overridden in derived classes
    }
}
public class Square : Shape // Derived class (inheritance)
{
    public override double GetArea() // Overridden method for square area (polymorphism)
    {
        return Width * Width;
    }
}
public class Circle : Shape // Derived class (inheritance)
{
    public const double PI = 3.14159; // Constant for pi (encapsulation)
    public override double GetArea() // Overridden method for circle area (polymorphism)
    {
        return PI * Width * Width / 2; // Width represents radius here
    }
}
public class Program
{
    static void Main(string[] args)
    {
        // Polymorphism - actual object type determined at runtime
        Shape[] shapes = { new Square { Width = 5 }, new Circle { Width = 3 } };
        foreach (Shape shape in shapes)
        {
            Console.WriteLine("Area: {0}", shape.GetArea());
        }
    }
}

Explanation:

  1. Encapsulation:
    • The Shape class encapsulates the _width property using a private field and public getter/setter methods. This controls access to the data and ensures it's modified appropriately.
    • The Circle class defines a constant PI for encapsulation, making it a read-only value accessible throughout the class.
  2. Inheritance:
    • The Square and Circle classes inherit from the Shape class, gaining access to its properties and methods (including Width and the virtual GetArea() method).
  3. Polymorphism:
    • The GetArea() method is declared as virtual in the Shape class. This allows derived classes (Square and Circle) to override it with their specific area calculation logic.
    • In the Main() method, we create an array of Shape objects. However, at runtime, the objects are actually instances of Square or Circle. When we call shape.GetArea() in the loop, polymorphism ensures the correct overridden method is executed based on the object's actual type (square or circle), calculating the area appropriately.

This program demonstrates how these OOP concepts work together. Encapsulation protects data, inheritance promotes code reuse, and polymorphism allows for flexible behavior based on object types. You can extend this example to add more shapes and functionalities, showcasing the power of these principles in building well-structured and maintainable C# applications.

End of Outcome Quiz

1 of 20

    Quiz Score

    Percentage: 0%

    Answered Questions: 0

    Correct Answers: 0

    Faults: