C# Classes, Inheritance, and Polymorphism Guide
C# Classes, Inheritance, and Polymorphism Guide
Creating the 'Car' and 'Program' classes demonstrates basic object-oriented programming principles such as encapsulation and class instantiation. The 'Car' class encapsulates data in the form of fields (make, model, color, yearBuilt) and behaviors in methods (Start, Stop). The 'Program' class illustrates how to instantiate and interact with 'Car' objects, setting field values and invoking methods. This encapsulation allows for modular code organization and reuse of objects throughout the application .
The 'override' keyword in the 'ListBox' and 'Button' classes is used to indicate that these classes are providing a new implementation of the 'DrawWindow' method originally defined in the 'Window' class. This keyword is crucial for polymorphic behavior, as it allows the derived classes to offer specialized functionality while maintaining a common interface defined by the base class. It enhances class functionality by enabling dynamic dispatch, meaning that the version of the method that gets executed is based on the actual object type at runtime rather than the reference type .
The 'Car' class follows a two-step process for object creation: first, a reference variable 'myCar' of type 'Car' is declared but not yet initialized. Then, a new 'Car' object is created using the 'new' keyword, and its memory address is assigned to 'myCar'. This illustrates object references in C#, where 'myCar' refers to the object's memory location, allowing access to the object's fields and methods. Modifications to 'myCar' directly affect the referenced object, showcasing how references point to and modify underlying objects .
Benefits of using a base class reference to an array containing derived class objects include enhanced flexibility and simplified code management, as it allows treating different types of objects through a uniform interface, which is essential for polymorphic behavior. This facilitates extending system capabilities without modifying existing code structure, thereby supporting maintainability. However, limitations include potential performance overhead due to dynamic method invocation at runtime, and the inability to directly access derived class-specific members without explicit type casting or additional methods, restricting some operations purely to those defined in the base class .
Polymorphism in C# is demonstrated through the use of virtual and override keywords. The base class 'Window' declares a virtual method 'DrawWindow', which can be overridden by any derived class. The 'ListBox' and 'Button' classes inherit from 'Window' and override 'DrawWindow' to customize its behavior. This allows objects of these derived classes to be treated as objects of the base class 'Window', enabling dynamic method invocation based on the object's actual type at runtime. When the 'DrawWindow' method is invoked on an array of 'Window' objects containing 'Window', 'ListBox', and 'Button' objects, the overridden methods in 'ListBox' and 'Button' are called, showcasing polymorphism .
The 'Employee' class demonstrates encapsulation by encapsulating employee-related data as private instance variables (firstName, lastName, address, sin, salary). It provides a constructor to initialize these variables, ensuring controlled and consistent object state upon creation. The override of the 'ToString' method presents employee information, showing the importance of customizing behavior for better data representation. Additionally, a method to calculate bonuses encapsulates logic pertinent to employee salary, adhering to the principle of keeping related data and behavior together .
Inheritance enhances code reusability by allowing derived classes like 'ListBox' and 'Button' to inherit common functionality from the base 'Window' class, such as managing the 'top' and 'left' fields and the base implementation of 'DrawWindow'. This eliminates code duplication and leverages existing implementations. It also adds scalability, as new derived classes can be added without altering existing functionality in the base class, facilitating extension and maintenance of the codebase as system requirements grow or change .
Method overriding in derived classes allows polymorphic arrays of the base class to dynamically invoke the overridden methods according to the object's actual runtime type. In the provided example, an array of 'Window' objects contains instances of 'Window', 'ListBox', and 'Button'. When iterating over this array, the 'DrawWindow' method is called for each object. Due to method overriding, the specific version of 'DrawWindow' corresponding to the actual type of each object ('Window', 'ListBox', or 'Button') is executed, demonstrating polymorphism .
The fields 'top' and 'left' in the 'Window' class serve as coordinates for positioning window elements in the console. They are protected fields, meaning they are accessible within derived classes. The derived classes 'ListBox' and 'Button' inherit these fields and utilize them in their overridden 'DrawWindow' methods to customize the output display by printing the top-left coordinates where the elements are drawn .
The 'Polymorphism' class tests polymorphism by creating an array of 'Window' objects that includes 'Window', 'ListBox', and 'Button' objects. It then iterates over this array, calling the 'DrawWindow' method on each element. Due to method overriding, the call to 'DrawWindow' is resolved at runtime based on each object's actual type, demonstrating polymorphic behavior. This setup illustrates how polymorphism enables writing code that is generic and flexible, allowing interaction with objects of different types interchangeably through a common base class interface .