Object-oriented programming
In this part of the C# tutorial, we will talk about object oriented programming in C#.There are three widely used programming paradigms there. Procedural programming, functional programming and object-oriented programming. C# supports both procedural and object-oriented programming.
Object-oriented programming (OOP) is a programming paradigm that uses objects and their interactions to design applications and computer programs. (Wikipedia)
There are some basic programming concepts in OOP:
- Abstraction
- Polymorphism
- Encapsulation
- Inheritance
Objects
Objects are basic building blocks of a C# OOP program. An object is a combination of data and methods. In a OOP program, we create objects. These objects communicate together through methods. Each object can receive messages, send messages and process data.There are two steps in creating an object. First, we define a class. A class is a template for an object. It is a blueprint, which describes the state and behavior that the objects of the class all share. A class can be used to create many objects. Objects created at runtime from a class are called instances of that particular class.
using System;In our first example, we create a simple object.
public class Being {}
public class CSharpApp
{
static void Main()
{
Being b = new Being();
Console.WriteLine(b);
}
}
public class Being {}This is a simple class definition. The body of the template is empty. It does not have any data or methods.
Being b = new Being();We create a new instance of the Being class. For this we have the
new
keyword. The b
variable is the handle to the created object. Console.WriteLine(b);We print the object to the console to get some basic description of the object. What does it mean, to print an object? When we print an object, we in fact call its
ToString()
method. But we have not defined any method yet. It is because every object created inherits from the base object
. It has some elementary functionality, which is shared among all objects created. One of this is the ToString()
method. $ ./simpleobject.exeWe get the object class name.
Being
Object attributes
Object attributes is the data bundled in an instance of a class. The object attributes are called instance variables or member fields. An instance variable is a variable defined in a class, for which each object in the class has a separate copy.using System;In the above C# code, we have a Person class with one member field.
public class Person
{
public string name;
}
public class CSharpApp
{
static void Main()
{
Person p1 = new Person();
p1.name = "Jane";
Person p2 = new Person();
p2.name = "Beky";
Console.WriteLine(p1.name);
Console.WriteLine(p2.name);
}
}
public class PersonWe declare a name member field. The
{
public string name;
}
public
keyword specifies, that the member field will be accessible outside the class block. Person p1 = new Person();We create an instance of the Person class. And set the name variable to "Jane". We use the dot operator to access the attributes of objects.
p1.name = "Jane";
Person p2 = new Person();We create another instance of the Person class. Here we set the variable to "Beky".
p2.name = "Beky";
Console.WriteLine(p1.name);We print the contents of the variables to the console.
Console.WriteLine(p2.name);
$ ./person.exeWe see the output of the program. Each instance of the Person class has a separate copy of the name member field.
Jane
Beky
Methods
Methods are functions defined inside the body of a class. They are used to perform operations with the attributes of our objects. Methods are essential in encapsulation concept of the OOP paradigm. For example, we might have a Connect() method in our AccessDatabase class. We need not to be informed, how exactly the method Connect() connects to the database. We only have to know, that it is used to connect to a database. This is essential in dividing responsibilities in programming. Especially in large applications.using System;In the code example, we have a Circle class. We define two methods.
public class Circle
{
private int radius;
public void SetRadius(int radius)
{
this.radius = radius;
}
public double Area()
{
return this.radius * this.radius * Math.PI;
}
}
public class CSharpApp
{
static void Main()
{
Circle c = new Circle();
c.SetRadius(5);
Console.WriteLine(c.Area());
}
}
private int radius;We have one member field. It is the radius of the circle. The
private
keyword is an access specifier. It tells that the variable is restricted to the outside world. If we want to modify this variable from the outside, we must use the publicly available SetRadius()
method. This way we protect our data. public void SetRadius(int radius)This is the
{
this.radius = radius;
}
SetRadius()
method. The this
variable is a special variable, which we use to access the member fields from methods. The this.radius is the instance variable, the radius is the local variable, valid only inside the SetRadius()
method. Circle c = new Circle();We create an instance of the Circle class. And set its radius by calling the
c.SetRadius(5);
SetRadius()
method on the object of the circle. We use the dot operator to call the method. public double Area()The
{
return this.radius * this.radius * Math.PI;
}
Area()
method returns the area of a circle. The Math.PI
is a built-in constant. $ ./circle.exeRunning the example.
78.5398163397448
Access modifiers
Access modifiers set the visibility of methods and member fields. C# has four access modifiers.public
, protected
, private
and internal
. public
members can be accessed from anywhere. protected
members can be accessed only within the class itself and by inherited and parent classes. private
members are limited to the containing type, e.g only within its class or interface. internal
members may be accessed from within the same assembly (exe or dll). Access modifiers protect data against accidental modifications. They make the programs more robust.
using System;In the above program, we have two member fields. One is declared public, the other private.
public class Person
{
public string name;
private int age;
public int GetAge()
{
return this.age;
}
public void SetAge(int age)
{
this.age = age;
}
}
public class CSharpApp
{
static void Main()
{
Person p = new Person();
p.name = "Jane";
p.SetAge(17);
Console.WriteLine("{0} is {1} years old",
p.name, p.GetAge());
}
}
public int GetAge()If a member field is
{
return this.age;
}
private
, the only way to access it is via methods. If we want to modify an attribute outside the class, the method must be declared public
. This is an important aspect of data protection. public void SetAge(int age)The
{
this.age = age;
}
SetAge()
method enables us to change the private
age variable from outside of the class definition. Person p = new Person();We create a new instance of the
p.name = "Jane";
Person
class. Because the name attribute is public
, we can access it directly. However, this is not recommended. p.SetAge(17);The
SetAge()
method modifies the age member field. It cannot be accessed or modified directly, because it is declared private
. Console.WriteLine("{0} is {1} years old",Finally, we access both members to build a string.
p.name, p.GetAge());
$ ./modifiers.exeRunning the example.
Jane is 17 years old
using System;In the preceding program, we have a
public class Base
{
public string name = "Base";
protected int id = 5323;
private bool isDefined = true;
}
public class Derived : Base
{
public void info()
{
Console.WriteLine("This is Derived class");
Console.WriteLine("Members inherited");
Console.WriteLine(this.name);
Console.WriteLine(this.id);
// Console.WriteLine(this.isDefined);
}
}
public class CSharpApp
{
static void Main()
{
Derived drv = new Derived();
drv.info();
}
}
Derived
class, which inherits from the Base
class. The Base
class has three member fields. All with different access modifiers. The isDefined member is not inherited. The private
modifier prevents this. public class Derived : BaseThe class
Derived
inherits from the Base
class. To inherit from another class, we use the colon (:) operator. Console.WriteLine(this.name);The
Console.WriteLine(this.id);
// Console.WriteLine(this.isDefined);
public
and the protected
members are inherited by the Derived class. They can be accessed. The private
member is not inherited. The line accessing the member field is commented. If we uncommented the line, the code would not compile. $ ./protected.exeRunning the program, we receive this output.
This is Derived class
Members inherited
Base
5323
The constructor
A constructor is a special kind of a method. It is automatically called, when the object is created. Constructors do not return values. The purpose of the constructor is to initiate the state of an object. Constructors have the same name as the class. The constructors are methods, so they can be overloaded too. Constructors cannot return any value.Constructors Constructors cannot be inherited. They are called in the order of inheritance. If we don't write any constructor for a class, C# provides an implicit default constructor. If we provide any kind of a constructor than a default is not supplied.
using System;We have a Being class. This class has two constructors. The first one does not take parameters, the second one takes one parameter.
public class Being
{
public Being()
{
Console.WriteLine("Being is created");
}
public Being(string being)
{
Console.WriteLine("Being {0} is created", being);
}
}
public class CSharpApp
{
static void Main()
{
new Being();
new Being("Tom");
}
}
public Being(string being)This constructor takes one string parameter.
{
Console.WriteLine("Being {0} is created", being);
}
new Being();An instance of the Being class is created. This time the constructor without a parameter is called upon object creation.
$ ./constructor.exeThis is the output of the program.
Being is created
Being Tom is created
Member initiation In the next example, we initiate data members of the class. Initiation of variables is a typical job for constructors.
using System;We have a MyFriend class with data members and methods.
public class MyFriend
{
private DateTime born;
private string name;
public MyFriend(string name, DateTime born)
{
this.name = name;
this.born = born;
}
public void Info()
{
Console.WriteLine("{0} was born on {1}",
this.name, this.born.ToShortDateString());
}
}
public class CSharpApp
{
static void Main()
{
string name = "Lenka";
DateTime born = new DateTime(1990, 3, 5);
MyFriend fr = new MyFriend(name, born);
fr.Info();
}
}
private DateTime born;We have two private variables in the class definition.
private string name;
public MyFriend(string name, DateTime born)In the constructor, we initiate the two data members. The
{
this.name = name;
this.born = born;
}
this
variable is a handler used to reference the object variables. MyFriend fr = new MyFriend(name, born);We create a MyFriend object with two arguments. Then we call the
fr.Info();
Info()
method of the object. $ ./constructor2.exe
Lenka was born on 3/5/1990
Constructor chaining Constructor chaining is the ability of a class to call another constructor from another constructor. To call another constructor from the same class, we use the
this
keyword. using System;We have a Circle class. The class has two constructors. One that takes one parameter and one that does not take any parameters.
public class Circle
{
public Circle(int radius)
{
Console.WriteLine("Circle, r={0} is created", radius);
}
public Circle() : this(1)
{
}
}
public class CSharpApp
{
static void Main()
{
new Circle(5);
new Circle();
}
}
public Circle(int radius)This constructor takes one parameter, the radius.
{
Console.WriteLine("Circle, r={0} is created", radius);
}
public Circle() : this(1)This is the constructor without a parameter. It simply calls the other constructor and gives it a default radius of 1.
{
}
$ ./constructorchaining.exeOutput of the example.
Circle, r=5 is created
Circle, r=1 is created
Class constants
C# enables to create class constants. These constants do not belong to a concrete object. They belong to the class. By convention, constants are written in uppercase letters.using System;We have a Math class with a PI constant.
public class Math
{
public const double PI = 3.14159265359;
}
public class CSharpApp
{
static void Main()
{
Console.WriteLine(Math.PI);
}
}
public const double PI = 3.14159265359;The
const
keyword is used to define a constant. $ ./classconstant.exeRunning the example.
3.14159265359
The ToString() method
Each object has aToString()
method. It returns a human-readable representation of the object. The default implementation returns the fully qualified name of the type of the Object. Note that when we call the Console.WriteLine()
method with an object as a parameter, the ToString()
is being called. using System;We have a Being class in which we override the default implementation of the
public class Being
{
public override string ToString()
{
return "This is Being class";
}
}
public class CSharpApp
{
static void Main()
{
Being b = new Being();
object o = new Object();
Console.WriteLine(o.ToString());
Console.WriteLine(b.ToString());
Console.WriteLine(b);
}
}
ToString()
method. public override string ToString()Each class created inherits from the base
{
return "This is Being class";
}
object
. The ToString()
method belongs to this object class. We use the override
keyword to inform, that we are overriding a method. Being b = new Being();We create two objects. One custom defined and one built-in.
object o = new Object();
Console.WriteLine(o.ToString());We call the
Console.WriteLine(b.ToString());
ToString()
method on these two objects. Console.WriteLine(b);As we have specified earlier, calling the
Console.WriteLine()
on the object will call its ToString()
method. $ ./override.exeThis is what we get, when we run the example.
System.Object
This is Being Class
This is Being Class
Inheritance
The inheritance is a way to form new classes using classes that have already been defined. The newly formed classes are called derived classes, the classes that we derive from are called base classes. Important benefits of inheritance are code reuse and reduction of complexity of a program. The derived classes (descendants) override or extend the functionality of base classes (ancestors).using System;In this program, we have two classes. A base Being class and a derived Human class. The derived class inherits from the base class.
public class Being
{
public Being()
{
Console.WriteLine("Being is created");
}
}
public class Human : Being
{
public Human()
{
Console.WriteLine("Human is created");
}
}
public class CSharpApp
{
static void Main()
{
new Human();
}
}
public class Human : BeingIn C#, we use the colon (:) operator to create inheritance relations.
new Human();We instantiate the derived Human class.
$ ./inheritance.exeWe can see, that both constructors were called. First, the constructor of the base class is called, then the constructor of the derived class.
Being is created
Human is created
A more complex example follows.
using System;We have four classes. The inheritance hierarchy is more complicated. The Human and the Animal classes inherit from the Being class. And the Dog class inherits directly from the Animal class and indirectly from the Being class. We also introduce a concept of a
public class Being
{
static int count = 0;
public Being()
{
count++;
Console.WriteLine("Being is created");
}
public void GetCount()
{
Console.WriteLine("There are {0} Beings", count);
}
}
public class Human : Being
{
public Human()
{
Console.WriteLine("Human is created");
}
}
public class Animal : Being
{
public Animal()
{
Console.WriteLine("Animal is created");
}
}
public class Dog : Animal
{
public Dog()
{
Console.WriteLine("Dog is created");
}
}
public class CSharpApp
{
static void Main()
{
new Human();
Dog dog = new Dog();
dog.GetCount();
}
}
static
variable. static int count = 0;We define a
static
variable. Static members are members, that are shared by all instances of a class. public Being()Each time the Being class is instantiated, we increase the count variable by one. This way we keep track of the number of instances created.
{
count++;
Console.WriteLine("Being is created");
}
public class Animal : BeingThe Animal inherits from the Being and the Dog inherits from the Animal. Indirectly, the Dog inherits from the Being as well.
...
public class Dog : Animal
...
new Human();We create instances from the Human and from the Dog classes. We call the
Dog dog = new Dog();
dog.GetCount();
GetCount()
method of the Dog object. $ ./inheritance2.exeThe Human object calls two constructors. The Dog object calls three constructors. There are two Beings instantiated.
Being is created
Human is created
Being is created
Animal is created
Dog is created
There are 2 Beings
Calling the parent's constructor We use the
base
keyword to call the parent's constructor explicitly. using System;We have two classes. The Shape class and the Circle class. The Shape class is a base class for geometrical shapes. We can put into this class some commonalities of the common shapes. Like the x, y coordinates.
public class Shape
{
protected int x;
protected int y;
public Shape()
{
Console.WriteLine("Shape is created");
}
public Shape(int x, int y)
{
this.x = x;
this.y = y;
}
}
public class Circle : Shape
{
private int r;
public Circle(int r, int x, int y) : base(x, y)
{
this.r = r;
}
public override string ToString()
{
return String.Format("Circle, r:{0}, x:{1}, y:{2}", r, x, y);
}
}
public class CSharpApp
{
static void Main()
{
Circle c = new Circle(2, 5, 6);
Console.WriteLine(c);
}
}
public Shape()The Shape class has two constructors. The first one is the default constructor. The second one takes two parameters, the x, y coordinates.
{
Console.WriteLine("Shape is created");
}
public Shape(int x, int y)
{
this.x = x;
this.y = y;
}
public Circle(int r, int x, int y) : base(x, y)This is the constructor for the Circle class. This constructor initiates the r member and calls the parent's second constructor, to which it passes the x, y coordinates. Have we not called the constructor explicitly with the
{
this.r = r;
}
base
keyword, the default constructor of the Shape class would be called. $ ./shapes.exeOutput of the example.
Circle, r:2, x:5, y:6
Abstract classes and methods
Abstract classes cannot be instantiated. If a class contains at least one abstract method, it must be declared abstract too. Abstract methods cannot be implemented, they merely declare the methods' signatures. When we inherit from an abstract class, all abstract methods must be implemented by the derived class. Furthermore, these methods must be declared with the same of less restricted visibility.Unlike Interfaces, abstract classes may have methods with full implementation and may also have defined member fields. So abstract classes may provide a partial implementation. Programmers often put some common functionality into abstract classes. And these abstract classes are later subclassed to provide more specific implementation. For example, the Qt graphics library has a QAbstractButton, which is the abstract base class of button widgets, providing functionality common to buttons. Buttons Q3Button, QCheckBox, QPushButton, QRadioButton, and QToolButton inherit from this base abstract class.
Formally put, abstract classes are used to enforce a protocol. A protocol is a set of operations, which all implementing objects must support.
using System;We have an abstract base Drawing class. The class defines two member fields, defines one method and declares one method. One of the methods is abstract, the other one is fully implemented. The Drawing class is abstract, because we cannot draw it. We can draw a circle, a dot or a square. The Drawing class has some common functionality to the objects, that we can draw.
public abstract class Drawing
{
protected int x = 0;
protected int y = 0;
public abstract double Area();
public string GetCoordinates()
{
return string.Format("x: {0}, y: {1}", this.x, this.y);
}
}
public class Circle : Drawing
{
private int r;
public Circle(int x, int y, int r)
{
this.x = x;
this.y = y;
this.r = r;
}
public override double Area()
{
return this.r * this.r * Math.PI;
}
public override string ToString()
{
return string.Format("Circle at x: {0}, y: {1}, radius: {2}",
this.x, this.y, this.r);
}
}
public class CSharpApp
{
static void Main()
{
Circle c = new Circle(12, 45, 22);
Console.WriteLine(c);
Console.WriteLine("Area of circle: {0}", c.Area());
Console.WriteLine(c.GetCoordinates());
}
}
public abstract class DrawingWe use the
abstract
keyword to define an abstract class. public abstract double Area();An abstract method is also preceded with a
abstract
keyword. public class Circle : DrawingA Circle is a subclass of the Drawing class. It must implement the abstract
Area()
method. public override double Area()When we implement the
{
return this.r * this.r * Math.PI;
}
Area()
method, we must use the override
keyword. This way we inform the compiler, that we override an existing (inherited) method. $ ./abstractclass.exeOutput of the program.
Circle at x: 12, y: 45, radius: 22
Area of circle: 1520.53084433746
x: 12, y: 45
This was the first part of the description of OOP in C#.
0 comments:
Post a Comment