360 likes | 699 Views
Object Oriented Programming with C#. Session: August-December 2009 Subject: C# Programming. Learning Objectives. In this chapter we will understand concept of classes and objects Understand the concept of Method Overloading Reviewing the Pillars of OOP. Encapsulation support
E N D
Object Oriented Programming with C# Session: August-December 2009 Subject: C# Programming
Learning Objectives • In this chapter we will understand concept of classes and objects • Understand the concept of Method Overloading • Reviewing the Pillars of OOP. • Encapsulation support • Inheritance usage • Polymorphic support
Understanding the C# class type • What is a class? • Formally, a class is nothing more than a custom user-defined type (UDT) that is composed of field data (sometimes termed member variables) and functions (often called methods in OO speak) that act on this data. The set of field data collectively represents the “state” of a class instance. • The power of object-oriented languages is that by grouping data and functionality in a single UDT, you are able to model your software types after real-world entities
Understanding the C# class type • C# classes can define any number of constructors. These special class methods provide a simple way for an object user to create an instance of a given class with an initial look and feel. Every C# class is initially provided with a default constructor, which by definition never takes arguments. In addition to the default constructor, you are also free to define as many custom constructors as you feel are necessary.
Understanding the C# class type • // The initial Employee class definition. • namespace Employees • { • public class Employee • { • // Field data. • private string fullName; • private int empID; • private float currPay; • // Constructors. • public Employee(){ } • public Employee(string fullName, int empID, float currPay) • { • this.fullName = fullName; • this.empID = empID; • this.currPay = currPay; • }
Understanding the C# class type • // Bump the pay for this employee. • public void GiveBonus(float amount) • { currPay += amount; } • // Show current state of this object. • public void DisplayStats() • { • Console.WriteLine("Name: {0} ", fullName); • Console.WriteLine("Pay: {0} ", currPay); • Console.WriteLine("ID: {0} ", empID); • } • } • }
Understanding the C# class type • Notice the default constructor in the class • public class Employee • { • ... • public Employee(){ } • ... • } • Like C++ and Java, if you choose to define custom constructors in a class definition, the default constructor is silently removed. Therefore, if you wish to allow the object user to create an instance • of your class as follows: • static void Main(string[] args) • { • // Calls the default constructor. • Employee e = new Employee(); • }
Understanding the C# class type • One must explicitly redefine the default constructor for your class (as we have done here). If you do not, you will receive a compiler error when creating an instance of your class type using the default constructor. In any case, the following Main() method creates a few Employee objects using our custom three-argument constructor: • // Make some Employee objects. • static void Main(string[] args) • { • Employee e = new Employee("Joe", 80, 30000); • Employee e2; • e2 = new Employee("Beth", 81, 50000); • Console.ReadLine(); • }
Understanding the Method Overloading • What is Method overloading? • Like other object-oriented languages, C# allows a type to overload various methods. Simply put, when a class has a set of identically named members that differ by the number (or type) of parameters, the member in question is said to be overloaded. In the Employee class, you have overloaded the class constructor, given that you have provided two definitions that differ only by the parameter set: • public class Employee • { • ... • // Overloaded constructors. • public Employee(){ } • public Employee(string fullName, int empID, float currPay){...} • ... • }
Understanding the Method Overloading • Constructors, however, are not the only members that may be overloaded for a type. By way of example, assume you have a class named Triangle that supports an overloaded Draw() method. By doing so, you allow the object user to render the image using various input parameters: • public class Triangle • { • // The overloaded Draw() method. • public void Draw(int x, int y, int height, int width) {...} • public void Draw(float x, float y, float height, float width) {...} • public void Draw(Point upperLeft, Point bottomRight) {...} • public void Draw(Rect r) {...} • }
Understanding the Method Overloading • Assume that if C# did not support method overloading, you would be forced to create four uniquely named members, which, as you can see, is far from ideal: • public class Triangle • { • public void DrawWithInts(int x, int y, int height, int width) {...} • public void DrawWIthFloats(float x, float y, float height, float width) {...} • public void DrawWithPoints(Point upperLeft, Point bottomRight) {...} • public void DrawWithRect(Rect r) {...} • }
Understanding the Method Overloading • Again, remember that when you are overloading a member, the return type alone is not unique • enough. Thus, the following is illegal: • public class Triangle • { • ... • // Error! Cannot overload methods • // based solely on return values! • public float GetX() {...} • public int GetX() {...} • }
Self-Reference in C# Using this Next, note that the custom constructor of the Employee class makes use of the C# this keyword: // Explicitly use "this" to resolve name-clash. public Employee(string fullName, int empID, float currPay) { // Assign the incoming params to my state data. this.fullName = fullName; this.empID = empID; this.currPay = currPay; } This particular C# keyword is used when you wish to explicitly reference the fields and members of the current object. The reason you made use of this in your custom constructor was to avoid clashes between the parameter names and names of your internal state variables. Of course, another approach would be to change the names for each parameter and avoid the name clash altogether: // When there is no name clash, "this" is assumed. public Employee(string name, int id, float pay) { fullName = name; empID = id; currPay = pay; }
In this case, we have no need to explicitly prefix the this keyword to the Employee’s member variables, because we have removed the name clash. The compiler can resolve the scope of these member variables using what is known as an implict this. Simply put, when your class references its own field data and member variables (in an unambiguous manner), this is assumed. Therefore, the previous constructor logic is functionally identical to the following: public Employee(string name, int id, float pay) { this.fullName = name; this.empID = id; this.currPay = pay; }
Basic Pillars of OOP • The following three are called as basic pillars of OOP. • Encapsulation • Inheritance and • Polymorphishm Encapsulation provides the ability to hide the internal details of an object from its users. The outside user may not be able to change the state of an object directly. However state of object may be altered indirectly using what are known as accessor and mutation methods. The concept of encapsulation is also known as data hiding or information hiding. When properly done we can create software “black boxes” that can be implemented, tested and used.
Basic Pillars of OOP Inheritance is the concept we use to build new classes using the existing class definitions. The concept of inheritance facilitates the reusability of existing code and thus improves the integrity of programs and productivity of programmer. Polymorphism is third concept of OOP. It is the ability to take more than one form. Polymorphism is extensively used while implementing inheritance.
Reviewing Basic Pillars of OOP • Encapsulation: How does this language hide an object’s internal implementation? • Inheritance: How does this language promote code reuse? • Polymorphism: How does this language let you treat related objects in a similar way? Before digging into the syntactic details of each pillar, it is important you understand the basic role of each. Encapsulation The first pillar of OOP is called encapsulation. This trait boils down to the language’s ability to hide unnecessary implementation details from the object user. For example, assume you are using a class named DatabaseReader that has two methods named Open() and Close(): // DatabaseReader encapsulates the details of database manipulation. DatabaseReader dbObj = new DatabaseReader(); dbObj.Open(@"C:\Employees.mdf"); // Do something with database... dbObj.Close();
Reviewing Basic Pillars of OOP The fictitious DatabaseReader class has encapsulated the inner details of locating, loading, manipulating, and closing the data file. Object users love encapsulation, as this pillar of OOP keeps programming tasks simpler. There is no need to worry about the numerous lines of code that are working behind the scenes to carry out the work of the DatabaseReader class. All you do is create an instance and send the appropriate messages (e.g., “open the file named Employees.mdf located on my C drive”). Another aspect of encapsulation is the notion of data protection. Ideally, an object’s state data should be defined as private rather than public (as was the case in previous chapters). In this way, the outside world must “ask politely” in order to change or obtain the underlying value.
Reviewing Basic Pillars of OOP Inheritance The next pillar of OOP, inheritance, boils down to the language’s ability to allow you to build new class definitions based on existing class definitions. In essence, inheritance allows you to extend the behavior of a base (or parent) class by enabling a subclass to inherit core functionality (also called a derived class or child class). Figure illustrates the “is-a” relationship.
Reviewing Basic Pillars of OOP You can read this diagram as “A hexagon is-a shape that is-an object.” When you have classes related by this form of inheritance, you establish “is-a” relationships between types. The “is-a” relationship is often termed classical inheritance. Recall that System.Object is the ultimate base class in any .NET hierarchy. Here, the Shape class extends Object. You can assume that Shape defines some number of properties, fields, methods, and events that are common to all shapes. The Hexagon class extends Shape and inherits the functionality defined by Shape and Object, in addition to defining its own set of members (whatever they may be)
Reviewing Basic Pillars of OOP There is another form of code reuse in the world of OOP: the containment/delegation model (also known as the “has-a” relationship). This form of reuse is not used to establish base/subclass relationships. Rather, a given class can define a member variable of another class and expose part or all of its functionality to the outside world. For example, if you are modeling an automobile, you might wish to express the idea that a car “has-a” radio. It would be illogical to attempt to derive the Car class from a Radio, or vice versa. (A Car “is-a” Radio? I think not!) Rather, you have two independent classes working together, where he containing class creates and exposes the contained class’s functionality:
Reviewing Basic Pillars of OOP • public class Radio • { • public void Power(bool turnOn) • { Console.WriteLine("Radio on: {0}", turnOn);} • } • public class Car • { • // Car "has-a" Radio. • private Radio myRadio = new Radio(); • public void TurnOnRadio(bool onOff) • { • // Delegate to inner object. • myRadio.Power(onOff); • } • }
Reviewing Basic Pillars of OOP The containing type (Car) is responsible for creating the contained object (Radio). If the Car wishes to make the Radio’s behavior accessible from a Car instance, it must extend its own public interface with some set of functions that operate on the contained type. Notice that the object user has no clue that the Car class is making use of an inner Radio object: • static void Main(string[] args) • { • // Call is forward to Radio internally. • Car viper = new Car(); • viper.TurnOnRadio(true); • }