Introduction to Object Oriented Programming for Beginners

An overview of the concept of Object Oriented Programming, a key concept in software design, with examples of classes and inheritance.

3,073 words, estimated reading time 12 minutes.
Introduction to Programming with C#

This article is part of a series of articles. Please use the links below to navigate between the articles.

  1. Learn to Program in C# - Full Introduction to Programming Course
  2. Introdution to Programming - C# Programming Fundamentals
  3. Guide to C# Data Types, Variables and Object Casting
  4. C# Operators: Arithmetic, Comparison, Logical and more
  5. Application Flow Control and Control Structures in C#
  6. Introduction to Object Oriented Programming for Beginners
  7. Introduction to C# Object-Oriented Programming Part 2
  8. C# Collection Types (Array,List,Dictionary,HashTable and More)
  9. Error and Exception Handling in C#
  10. Events, Delegates and Extension Methods
  11. Complete Guide to File Handling in C# - Reading and Writing Files
  12. Introduction to XML and XmlDocument with C#
  13. What is LINQ? The .NET Language Integrated Query
  14. Introduction to Asynchronous Programming in C#
  15. Working with Databases using Entity Framework
  16. All About Reflection in C# To Read Metadata and Find Assemblies
  17. Debugging and Testing in C#
  18. Introduction to ASP.Net MVC Web Applications and C#
  19. Windows Application Development Using .Net and Windows Forms
  20. Assemblies and the Global Assembly Cache in C#
  21. Working with Resources Files, Culture & Regions in .Net
  22. The Ultimate Guide to Regular Expressions: Everything You Need to Know
Introduction to Object Oriented Programming for Beginners

The object-oriented approach to programming tries to represent abstract or concrete things of the real world in a type of computer code called classes. This article is designed to give you an overview of object-oriented programming, classes, inheritance, and abstraction.

What is Object Oriented Programming?

Object Oriented Programming is a branch of computer programming centred around objects rather than actions and data rather than logic. Objects are modelled after things in the real world or creating data models. By modelling data and things, a set of related properties and actions can be created and interacted with.

Object-oriented programming believes the objects we want to manipulate are more important than the logic required.

What is a Class in Object Oriented Programming?

A class can be considered a blueprint for a noun, e.g. a person, place or thing. Nouns have attributes that describe them, such as Size, Mass, Temperature, Speed, etc. These attributes are called fields.

A noun can also have actions or processes associated with it. For example, a car could have an action of Accelerate, which would affect the Speed attribute. These actions are called methods.

A class cannot be used by itself but to instantiate (create) an instance of an object that shares all the same fields and methods. Because it is a blueprint, you can create many instances with the same fields and methods. An instance of a class is called an object. You must keep in mind that each object created from a class is unique; each instance of a class will have its own values for the fields, totally separate from the values of the other objects.

Creating one class that can be reused often is the foundation of object-oriented programming and effective code reuse.

A class should be as specific to the task as possible and only contain nouns dedicated to the task for which the class is to perform.

Why use Classes?

Now, let's look at where object-oriented programming comes into its own. There is a concept known as inheritance: one class can inherit all the methods and fields of a parent or base class and add new functionality or replace existing methods. This allows a new class to focus more on the modelled object.

Every car manufacturer uses the same base class to put that into English with the car example. This class defines a basic car with four wheels, a steering wheel, brakes, headlights, seats, etc... However, if every manufacturer only used this blueprint, every car produced would be the same - what would be the point?

We take functionality from the base class, create another car class and add functionality. We can add central locking, water temperature and paint. A different manufacturer may use trim colour oil, temperature, and ABS brakes. We can override the methods from the base class so that the basic seats are now heated leather seats and the headlights are HID.

Classes can also use other classes. Our base car class can use a base engine class. If we wish, our new car class can override this base engine class to use a super turbo-charged jet-powered engine.

Classes in C#

A C# application is a collection of classes, structures (shortened to struct) and types.

Firstly, classes and structs are essentially the same, apart from two key differences.

  • Classes are a reference type, structs are value types
  • Classes can use inheritance, whereas structs cannot.

Defining a Class

A class is introduced using the class keyword, followed by the class name you are creating. Because a class is a code block, it requires curly brackets (braces).

Let's use the example above and create a Car class. I've called the class baseCarClass because we will use this class as a base for new classes in future tutorials.

In the example, we identified several fields and methods associated with a car class.

We will create a sample application using the baseCarClass, create a new console project, and copy the following code into the window.

C#
class baseCarClass
{
}

We can now add variable declarations for some of the properties of the base car, such as paint colour, number of seats, and direction.

The .Net Framework and the compiler are not affected by the order in which you declare fields or methods; however, it greatly improves readability if you declare properties at the start of a class, followed by its methods.

C#
class baseCarClass
{
  public string Colour { get; set; }
  public int numberOfSeats { get; set; }
  public int direction { get; set; }
  public string modelName { get; set; }
}

So far, all we have done is create a blueprint for a class. We shall now see how to create an actual car object.

A class is a user-defined type, so we use the same syntax as declaring an int (for example), but a class also needs initialising with the new keyword. This will instantiate an instance of the class on the heap.

In the Main method of the console application, create an instance of the baseCarClass like this:

C#
static void Main()
{
  baseCarClass myCar = new baseCarClass();
}

We can now set the various attributes of the car.

In your Main method, create an instance of the baseCarClass:

C#
static void Main()
{
  baseCarClass myCar = new baseCarClass();
  myCar.Colour = "blue";
  myCar.numberOfSeats = 4;
  myCar.modelName = "Demo Car MKI";
}

Using the class as a blueprint means we can create multiple cars with different values for each property.

C#
static void Main()
{
  baseCarClass myCar = new baseCarClass();
  myCar.Colour = "blue";
  myCar.numberOfSeats = 4;
  myCar.modelName = "Demo Car MKI";

  baseCarClass myNewCar = new baseCarClass();
  myNewCar.Colour = "yellow";
  myNewCar.numberOfSeats = 2;
  myNewCar.modelName = "Sports Car MKI";
}

Class Methods

We have just created a class with a few properties. We can add a few methods to our classes that contain certain logic.

C#
class baseCarClass
{
  public bool isEngineRunning { get; set; }
  public decimal speed { get; set; }
  public decimal distanceTraveled { get; set; }
  public decimal fuelLevel { get; set; }
  public Color colour { get; set; }

  public void startEngine()
  {
  }
  
  void accelerate()
  {
  }
  
  void brake()
  {
  }
  
  void stopEngine()
  {
  }
}

The compiler is not affected by the order in which you declare fields or methods; however, it greatly improves readability if you declare fields and properties at the start of a class, followed by its methods.

Classes as a Data Type

Our car does not have an engine at this stage, so it's pretty useless. A car can have many different engine types, and we will model a base engine as we have created a base car. This way, our cars will have a variety of engines.

C#
class baseEngineClass
{
  public string name { get; set; }
  public int numberOfCylinders { get; set; }
  public int MPG { get; set; }
  public int acceleration { get; set; }
}

We can add one class to another in the same way as we add an integer or string. A class is simply another data type.

Let's add the engine to our car class.

C#
class baseCarClass
{
  public string Colour { get; set; }
  public int numberOfSeats { get; set; }
  public int direction { get; set; }
  public string modelName { get; set; }
  public baseEngineClass engine { get; set; }
}

Now, all that is left to do is create an engine and give it to a car.

C#
static void Main()
{
  baseCarClass myCar = new baseCarClass();
  myCar.Colour = "blue";
  myCar.numberOfSeats = 4;
  myCar.modelName = "Demo Car MKI";

  myCar.engine = new baseEngineClass();
  myCar.engine.name = "Slow Engine"
  myCar.engine.numberOfCylinders  = 4;
  myCar.engine.MPG = 50;
  myCar.engine.acceleration = 2;
}

C# Class Inheritance

Class inheritance is one of the key principles in object-oriented programming. It allows one class to pass on properties and methods to child classes so that they can reuse, extend, and modify existing functionality.

In simplistic terms, class inheritance allows one class to inherit methods, properties and fields from a parent class and build upon its functionality. Classes inherit from another class using a colon followed by the class name to inherit from on the class declaration line.

Let's create a sports car class which has a folding roof.

C#
public class SportsCar : baseCarClass
{
}

This basic class definition should be familiar, with the additional inheritance " : baseCarClass" bit added on. This is saying that we want a new class called SportsCar, which contains everything that baseCarClass contains.

Next, we can add the folding roof as a boolean property, using two methods: one to raise the roof and the other to lower it.

C#
public class SportsCar : baseCarClass
{
  private bool isRoofUp;

  public void RaiseRoof()
  {
    isRoofUp = true;
  }

  public void DropRoof()
  {
    isRoofUp = false;
  }
}
C#
SportsCar myCar = new SportsCar();

The SportsCar contains all the properties of the baseCarClass plus those we defined in the SportsCar class.

Using C# Properties

In this example, we saw that we created some properties with a get and set keyword after them. These are called properties.

Properties are the same as fields, however, they can execute code when you access them via getters and setters. This allows for the protection of class information and the enforcement of business rules.

Generally, if you mark a field as public, you should convert it to a property. This is because many actions, such as serialisation and deserialisation (we'll cover these later), only work for properties.

A property can be defined in two ways. For example, we just saw the automatic property, a shorthand version where the compiler automatically generates the backing variable and getter and setter code.

The expanded version also allows you to add logic and security to the get or set methods. Only certain users can update the value while everyone can read it.

C#
private int _month

public int Month
{
  get 
  {
    return _month;
  }

  set
  {
    if ((value >= 1) &amp;&amp; (value <= 12))  
    {
      _month = value;
    }
  }
}

This will ensure that the value of _month will always be between 1 and 12. If the user of your class passes a value outside this range, it will not be applied.

C# Class Constructors and Destructors

Class constructors and destructors are methods automatically called when a class is instantiated or destroyed. They are provided so the class can be initialised with the correct data, open connections, and so on, and connections and files can be finalised and closed before the object is removed from memory.

You do not need to provide a constructor method in your classes, as the compiler will automatically initialise fields to default values using a default constructor which takes no parameters. A constructor should be used when you need non-default values to be initialised. Constructors can also be overloaded to extend the functionality of the method. If you create an overloaded constructor, the compiler will not provide a default, so if you still require a constructor with no parameters, you must provide it yourself.

A constructor is declared as a public method with the same name as the class; in this example, public baseCarClass() is the constructor.

C#
class baseCarClass
{
    public bool isEngineRunning;
    public decimal speed;
    public decimal distanceTraveled;
    public decimal fuelLevel;
    public Color colour;

    // Constructor
    public baseCarClass()
    {
    }

    public void startEngine()
    {
    }

    void accelerate()
    {
    }

    void brake()
    {
    }

    void stopEngine()
    {
    }
}

When you compile your class, the compiler will automatically add a default "hidden" constructor; however, if you want to provide additional functionality, you must do this yourself. You can pass a parameter on to the constructor when instantiating the class with the new keyword.

C#
// Constructor
public baseCarClass(Color carColour)
{
    colour = carColor;
}
C#
baseCarClass car = new baseCarClass(Color.Yellow);
//car.colour == Color.Yellow

baseCarClass car = new baseCarClass(); // Will not compile

When you code a constructor, the compiler will not automatically provide one. Only those coded will be present, so if you create a constructor with a parameter, you cannot create an object with a parameterless constructor unless you write one.

This example constructor will only allow a baseCarClass to be created when a colour is given. The default with no parameters is not available. If you do need it, you will have to create it yourself.

C#
// Default Constructor
public baseCarClass()
{
    // Call the most specific constructor to prevent duplicate code
    baseCarClass(Color.Black);
}

// Custom Constructor
public baseCarClass(Color carColour)
{
    colour = carColour;
}
C#
baseCarClass car = new baseCarClass(Color.Yellow);
//car.colour == Color.Yellow

baseCarClass car = new baseCarClass(); // Now will compile
//car.colour == Color.Black - default colour

Constructors and Inheritance

By default, all inherited classes will use the constructor as the base class unless overridden.

Because the constructor was added to the baseCarClass, any class inheriting from it can also benefit from having the constructor, thus:

C#
SportsCar sporty = new SportsCar(Color.Pink);
//sporty.colour == Color.Pink

To create a constructor specifically for the SportsCar class, we define it in the same way:

C#
// Constructor
public SportsCar(bool roofUp)
{
    isRoofUp = roofUp;
}
C#
SportsCarcar = new SportsCar(true);
//car.isRoofUp == true

What colour is the SportsCar?

Because we have not provided colour in our constructor, the default constructor for the base class has been called making the colour of the car Color.Black. You can call the base class's constructor and give it a parameter. This can be done in one of two ways.

Firstly, to provide a default "static" value:

C#
public SportsCar(bool roofUp):base(Color.PeachPuff)
{
    isRoofUp = roofUp;
}

Or you can add another parameter to the constructor and use this to call the base constructor.

C#
public SportsCar(bool roofUp, Color carColour): base(carColour)
{
    isRoofUp = roofUp;
}

Private Constructors

You can also mark the constructor as private, which will have the effect of not allowing the class to be instantiated. This is useful for abstract classes where you should not create an instance.

C#
class PoliceCar
{
  private PoliceCar()
  {
  }
}

The following code will not compile as the program cannot "see" the private method.

C#
PoliceCarcar = new PoliceCar();

Destructors

Destructors work slightly differently in that the syntax is a shortcut to an override of the Finalize method; however, all you need to know is that they are used to finalise the class and are ready for removal from memory. The Garbage Collector always calls the destructor; you never call it from within your code. Since you cannot call the destructor, you cannot overload the destructor method.

C#
~baseCarClass ()
{
  // Code to scrap the car (realistically, this would be closing files and connections)
}

Method Overloading and Overriding in C#

When inheriting from another class, you may change the default behaviour of a method or create a different method signature. You can do this by overloading the method with your code.

Method signatures are formed from the parameter list, particularly the data types. Methods can share the same name within the class if the signature differs.

C#
static int Add(int a, int b)
{
  return a + b;
}

The signature should be (int, int) in the above example. In the Visual Studio code editor, if you were to call the Add method after you enter the '(' IntelliSense, it will pop up the available parameters. Notice that there is only one option given to you.

Method Overloading

We can add an overloaded method with a different signature, and IntelliSense will now present two options, one for each signature of the overloaded method. The compiler finds two methods of the same name and two calls to that method with different parameters. It can tell the difference by comparing the signatures of the methods.

C#
static int Add(int a, int b, int c)
{
  return a + b + c;
}

The parameter names and the return type do not affect the method signature. Thus, the method below will raise an error because a method already exists for Add(int, int), even though it returns a decimal.

C#
static decimal Add(int a, int b, int c)
{
  return a + b + c;
}

Methods should be overloaded when you have similar methods requiring different parameters or want to add new functionality to existing code. However, you should not overload too often as it causes headaches during debugging and testing and is more effort to maintain.

Optional Parameters in C#

C# does not have an implementation of optional parameters like those found in PHP. However, you can simulate this feature using method overloading.

C#
static int Add(int a, int b)
{
  return Add(a, b, 0, 0);
}

static int Add(int a, int b, int c)
{
  return Add(a, b, c, 0);
}

static int Add(int a, int b, int c, int d)
{
  return (a + b + c + d);
}

In this example, we can call Add with 2, 3 or 4 parameters, and only one functional method is called - the others pass the data around. You can use IntelliSense to see the different overloads and their parameters.

Overloading Example
Overloading Example

Full Code

C#
using System;
using System.Drawing;

class TestBaseCarClass
{
    static void Main()
    {
        Console.WriteLine(Add(1, 1));
    }

    static int Add(int a, int b)
    {
        return Add(a, b, 0, 0);
    }

    static int Add(int a, int b, int c)
    {
        return Add(a, b, c, 0);
    }

    static int Add(int a, int b, int c, int d)
    {
        return a + b + c + d;
    }
}

This code is only shown as an example. If you want to create a function that accepts any number of parameters of the same type, then the params keyword is better suited.

Method Overriding

Methods can be overridden, such as replacing or extending the default behaviour. In this example, we will override the ToString() method for the ArrayList class so that it may return something more meaningful.

C#
using System;
using System.Collections.Generic;

class Program
{
  static void Main()
  {
     ArrayList myList = new ArrayList();

    myList.Add("Hello");
    myList.Add("World");
    myList.Add("123456");

    Console.WriteLine(myList.ToString());
  }
}

You may expect the ToString to return "Hello World 123456", but it returns "System.Collections.ArrayList", which isn't particularly helpful.

We can override this default behaviour by creating a new class inherited from the ArrayList. We can then override the ToString method using the override keyword.

C#
class myArrayList : System.Collections.ArrayList
{
    public override string ToString()
    {
        return base.ToString();
    }
}

The base keyword refers to the object. By default, the override method will return base.ToString(). You can use this base object to call the non-overwritten method. We are going to amend the code to suit our needs, and in this example, we will convert the array list to show the list's contents, one item per line.

C#
using System;
using System.Text;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        myArrayList myList = new myArrayList();

        myList.Add("Hello");
        myList.Add("World");
        myList.Add("123456");

        Console.WriteLine(myList.ToString());
    }
}

class myArrayList : System.Collections.ArrayList
{
    public override string ToString()
    {
        StringBuilder result = new StringBuilder();
        string[] theItems = (string[])base.ToArray(typeof(string));

        foreach (string item in theItems)
        {
            result.AppendLine(item);
        }
        return result.ToString();
    }
}

When we create an instance of our new class and call the ToString method, we are given "Hello World 123456" one item per line.

Object Oriented Programming Summary and Conclusions

In this rather lengthy article, we have looked at object-oriented programming, learned what a class and properties are, and learned how to inherit classes, constructors and destructors, overloading and overriding. In Part 2, we will look at some more object-orientated examples and a few more concepts.

About the Author

Tim Trott is a senior software engineer with over 20 years of experience in designing, building, and maintaining software systems across a range of industries. Passionate about clean code, scalable architecture, and continuous learning, he specialises in creating robust solutions that solve real-world problems. He is currently based in Edinburgh, where he develops innovative software and collaborates with teams around the globe.

Related ArticlesThese articles may also be of interest to you

CommentsShare your thoughts in the comments below

My website and its content are free to use without the clutter of adverts, popups, marketing messages or anything else like that. If you enjoyed reading this article, or it helped you in some way, all I ask in return is you leave a comment below or share this page with your friends. Thank you.

This post has 11 comments. Why not join the discussion!

New comments for this post are currently closed.