This article will covers the use of Classes in Programming languages.
In the 1990’s, we saw the rapid rise of Object oriented programming languages like Java and C++. These object oriented programming languages used the concept that everything is made out of Objects and Classes. These objects contain data and functions, and can interact with each other. Classes is just another part of the Object Oriented model that so many languages follow today.
A “Class” is commonly known as a Blueprint or template for an object. This template is then used to create and define an object, which we use in our program. There is no limit to the number of objects that can be created from a single template.
That was all the technical mumbo-jumbo that needs to be said when introducing classes to a beginner. Let’s get into the actual explanation now. Just remember to take another look at the text above once you’re done with this article. It will probably make alot more sense then.
A simple summed up definition of a Class is the following:
“A collection of functions and attributes under a common name”.
Classes Terminology
A bunch of useful terminology which we will be using later on. This will serve as a good reference for later.
1. An Instance is the class object that is created at run time. It can be called the physical manifestation of a class. An instance is created when a class is assigned to a variable.
The terms object and instance are very interchangeable here, so expect to hear both. The best way to describe is that an object is the actual thing made using the blueprint (class) and the instance is a virtual copy of that object.
2. Methods are another important term. A method is a function that belongs to an object. A Method defined in a Class is available to all objects created using that class. This will be more clear later on as we define methods for our classes.
3. A Constructor is a special kind of method that called when creating an object. The Constructor is used to perform tasks such as initializing any variables that the object will need when it starts. Unlike a regular function, the Constructor does not have a return type.
4. Similar to the Constructor, we also have the Destructor which is a method that executes when the object is destroyed. We often use it to deallocate resources that we may have explicitly declared. (Commonly used in languages where dynamic memory allocation is allowed, such as C++)
5. A Data class refers to a type of class with no methods, only variables. These variables are merely used to hold data. If you’ve done structs in other languages, these two concepts are very similar.
How to Classify Classes
This is an issue that comes up when you’re creating multiple classes. People often tend to miss the point of a class.
A class is meant to hold information regarding a certain topic or field. For instance, one might create a class called student
. You can expect it to have student related variables and methods, like RollNo
, Grade
, School
etc. Including variables like, rainfall
, Stockprice
or Salary
would ruin the point of having a student class.
Similarly, don’t create a massive class filled with all kinds of different fields and functions. For instance, if you’re creating a database for all the people in a school. Naturally, you will want to create Class Objects, which will represent each person. Don’t make just one Class however, instead make a total of three classes, one for the students, one for the teachers and one for the staff.
This allows for greater organization, readability and of course, better structure. More importantly, it creates some distinction between the various type of people found in the School. Because obviously they aren’t all students right? They are unique entities, with their own unique features, but also some common ones.
Classes (Examples)
Before we proceed any further, allow me to show you some examples of classes. I’ll also give a brief explanation of the code (and add some helpful comments) to help you understand the concepts I just explained.
What we are gonna do here, is create a Class of “Student”, give it some variables and then create a function which uses those variables.
First up we have the code for this example Class in C++.
class Student {
public: // Allows these members to be accessed by non-members
// Creating variables
string name;
int rollno;
Student(string str, int n) { // The Constructor
name = str;
rollno = n;
}
void print() {
cout << "Student: " << name << "\n";
cout << "RollNo: " << rollno << "\n";
}
};
int main() {
Student student1("Bob", 124); // Creating Objects: Method#1
Student student2 = Student("John", 191); // Creating Objects: Method#2
student1.print(); // Functions and Variables are accessed
student2.print(); // using the '.' (dot) operator
}
It’s fairly simple, with just two Class variables which we initialized in the Constructor by passing in values as parameters. Don’t forget that the Constructor is a function too. It does however require, that the Constructor have the same name as the Class. Hence, calling Student("John", 191)
, returns an object of type Student, which we store in student2
.
In C++, where we have to mention the type of the return value, you can notice here that
Here’s the same thing, but in Python.
class Student:
def __init__(self, string, number):
self.name = string
self.rollno = number
def display(self):
print("Student: ", self.name)
print("RollNo: ", self.rollno)
student1 = Student("Bob", 124)
student2 = Student("John", 192)
student1.display()
student2.display()
Notice how each Class’s functions and variables match up with the name of the Class (meaning, they are directly related to each other). Also notice how similar the two codes are, despite being in different languages. There is a syntax difference, but the logic and concept remains the same.
Further Examples of Classes
Let’s take a look at a more proper class, complete with a Constructor, Destructor, Function overloading etc. We will be using C++ for most code examples as it’s an ideal language to showcase the best of OOP. As usual we will explain the example, as well as leave helpful comments for you to understand it better.
#include <iostream>
using namespace std;
class MyClass {
public:
MyClass(int n, int i) {
cout << "Constructor was called..." << endl;
_id = i;
_mem = new int[n]; // allocate dynamic memory
}
~MyClass() {
delete[] _mem; // free up dynamic memory
cout << "Destructor was called..." << endl;
}
void print() {
cout << "Empty print function" << endl;
}
void print(string str) {
cout << "print function with parameter: " << str << endl;
}
private:
int _id;
int* _mem;
};
The above Class has several components. First there is a Constructor that initializes the two member variables, and allocates dynamic memory for _mem
. The Destructor frees up this memory using the delete keyword when the object goes out of scope.
We have also overloaded the print()
function to give different output, based on whether we passed a parameter to it or not.
Inheritance in Classes
Inheritance is another feature introduced in Object Oriented Programming Languages that further empathizes reusability and structure in Classes. It basically adds a new layer of complexity by bringing in the concept of Parent and Child classes, where the child inherits attributes and methods from the Parent class.
Before we continue with inheritance, we need to take a break and discuss Access levels first.
Access Levels
Access Levels are basically protection levels, which define who is allowed to access a variable or function. We use the public
and private
(and sometimes protected
) keywords to decide the “scope” of the methods and attributes.
Those methods that have been marked as private
, are only accessible in the Class they were declared. Methods marked as protected
are available both in the class they were declared in, as well as any Child classes that inherit it. Both of these are not available globally, which is what the public
keyword stands for (methods or attributes can be accessed from anywhere).
Let’s take a look at some examples.
class Student {
public: // Allows these members to be accessed by non-members
Student(string str, int n) { // The Constructor
name = str;
rollno = n;
}
void print() {
cout << "Student: " << name << "\n";
cout << "RollNo: " << rollno << "\n";
}
private:
string name;
int rollno;
};
int main() {
Student student1("Bob", 124); // Creating Objects
Student student2 = Student("John", 191); // Creating Objects
}
In the above example, both “name” and “rollno” have been declared as private. This doesn’t change anything for the functions inside the class, as they can still access the variables normally.
Trying to do something like this however, will cause an error:
student1.name = "Sam";
You can expect to receive an error message telling you that you are trying to access an inaccessible member of the class. This of course, would have worked if it was public.
Inheritance in Classes – continued
Now let’s go back to inheritance for a bit. We won’t get into the details, leaving those for a separate tutorial altogether, but we will atleast give you the introduction to the concept of Inheritance of Classes in Programming languages.
If you are making a large application such as a game, you might end up with dozens of similar classes. It’s not uncommon for a large game to have over 10 – 20 types of enemies for example. Now while each enemy here is going to be unique in some way from the others, it’s usually the case that 80% of the code matches the rest of the other enemies.
For example, it’s possible for all enemies to share the same “walk”, “run”, “die”, “drop loot” functions, while functions like “attack” might be different. So are you going copy paste the same functions across 10+ classes? Well, if you don’t know about Inheritance that would be your only choice.
In the below example, we have created 4 Classes. We have one Base Class called “Enemy
” with an attack function and a variable with the attack value. We then created 3 Child Classes which inherited from “Enemy
“.
class Enemy {
public:
int attack;
void Attack() {
cout << "Attack Player" << endl;
}
};
class Dragon : public Enemy {
public:
Dragon() {
attack = 10; // Initialize attack power of Dragon to 10
}
};
class Troll : public Enemy {
public:
Troll() {
attack = 5; // Initialize attack power of Troll to 5
}
};
class Goblin : public Enemy {
public:
Goblin() {
attack = 1; // Initialize attack power of goblin to 1
}
};
Notice how we didn’t have to redefine the Attack function in the Child Classes. However, you may want to redefine it in certain Child Classes which require a unique definition for Attack.
A more practical implementation of this would involve creating unique functions and assigning unique values to the member variables for each child class. For example, a function called “fly” for the Dragon
, which is unique to it, or different attack values for the various types of enemies based on their strength.
We could even further add more levels of inheritance, by creating sub-Types of enemies such “Flying Enemies
” which would inherit from Enemy
. All Flying-based enemies would then inherit from Flying Enemy
. Don’t forget that Flying Enemy
and Enemy
are just abstract Classes, and we will not be using them to create Objects.
Tip: Good Practices
If you remember the code from the very first examples, we put everything under public access, which isn’t normally supposed to be done. It’s good practice to always have things separated in the proper order, even if you are the only person who is ever going to use that Class.
Pretend as if you are going to make the Class available to the public, and want to make sure no-one is able to mess around with the variables/functions that they have no business accessing. If a user is able to ruin an object’s working by illegally modifying it’s value, then that’s a problem you need to address.
Some techniques we use:
Using getters and setters: The reason we keep variables private is to prevent unwanted access. So what if we had a way to limit and control how the Users can change the value of those variables? For those we have getters and setter function. (These are just regular functions btw, we can just call them that).
#include <iostream>
using namespace std;
class Car {
private:
string CarModel;
int HorsePower;
float Speed;
public:
void ChangeGears() {
cout << "Change Gears" << endl;
}
void SetSpeed(float spd) {
if (spd > 0) {
this->Speed = spd;
}
}
float GetSpeed() {
cout << "Speed: " << Speed << endl;
return Speed;
}
};
int main() {
Car car1 = Car();
car1.ChangeGears();
car1.SetSpeed(10);
car1.GetSpeed();
}
The above ensures that you cannot enter a negative value into speed variable of the Car object. We have effectively created a limitation for the user with this function, that only positive values are allowed.
Putting utility functions as private (or protected if needed by children):
Often there will be many functions that are only to be used by other functions inside the Class. These functions are sometimes referred to as Utility functions. As they are not needed to be accessed by the user, they should be kept private/protected.
Take a look at the following code for Bubble Sort in C++. There are two functions inside the Bubble Sort Class. The first one is the Sort
function, into which we will be passing the array of integers to be sorted. This is the function we will be interacting with, and calling externally, hence we have set it to public.
class BubbleSort {
public:
void Sort(int array[], int size) {
for (int i = 0; i < size; i++) {
for (int j = 0; j < size - i; j++) {
if (array[j] > array[j + 1]) {
swap(array[j], array[j + 1]);
}
}
}
}
private:
void swap(int &n1, int &n2) {
int temp = n1;
n1 = n2;
n2 = temp;
}
};
The swap()
function is a utility function used by the Sort()
function. It is not meant to be called by the User, hence it is set to private.
Further Reading
That was quite a length article, and you may think you have learnt alot about OOP and Classes. Well guess what, we’ve barely scratched the surface! There’s alot more to Classes and Object Oriented Programming Languages, with this article merely being the Introduction.
Other concepts that you can learn about: (follow the links for more)
- Types of Constructors
- Polymorphism with Virtual Functions
- Inheritance
- Abstract Classes
- Friend Classes
- Function Overloading
- Operator Overloading
This marks the end of the Classes in Programming languages article. Any suggestions or contributions for CodersLegacy are more than welcome. Any questions about the article content can be asked in the comments below.