Introduction to Classes in C++

Tuesday, May 4, 2021
Design C++ Object-Oriented

A key idea in Object-Oriented programming is encapsulation - complexity is managed by exposing only those fields and methods that the client code need and hiding everything else. A second idea is to keep the interface of the class separate from the implementation. This is done through the use of Classes that let's us create Objects. These objects encapsulates the data and related functions that are specific to the class. Let's see how these ideas are employed in C++ to achieve encapsulation.

Two ideas to employ encapsulation

Separate interface from implementation

Interface only defines the signature of all fields and methods belonging to a class, i.e. only declaring names and types for the data, parameter names, types, function names and their return types. The interface in C++ is kept in .h file. Implementation refers to the definitions of all the methods that are declared in the .h file. These definitions are kept in a separate (*.cpp) file. With this design, the user of the class does not need to concern with how a particular method is implemented and can easily inspect the interface to see what methods are available to use.

Separate public from private

Not everything needs to be exposed to the client code; some fields and methods can be kept private. The private fields and methods are not available for the client code to use but class methods can access this private data. This allows us to design the class with only the required functionality to be exposed to the user while keeping other data and methods private.

Let's see how these ideas are used. We will create a class called Circle that models a geometrical circle.

#pragma once // instructs the compiler to compile it only once

class Circle {
    public: // methods and variables that client code can directly use/access
        void setRadius(double radius);
        double getPerimeter();
        double getArea();

    private: // methods and variables that cannot be directly accessed by client code
        double radius_;

};

Here, the data associated with the Circle is radius. Note that this data is kept private (by defining it under private section; _ is suffixed to name as a convention to visually indicate that it is a private data). So the client code cannot access it directly. Also, this class exposes three functions - setRadius(double radius), getPerimeter() and getArea() that the client code can use to interact with the object.

Now we look at the implementation of the circle class (in Circle.cpp file):

/*
/* Source code (Circle.cpp) for Circle class
*/

#include "Circle.h"

void Circle::setRadius(double radius) {
    radius_ = radius;
}

double Circle::getPerimeter() {
    return 2 * 3.1415 * radius_;
}

double Circle::getArea() {
    return 3.1415 * radius_ * radius_;
}

We include the header file of the class (and header files of methods belonging to any other class that we might use while defining these functions). The function names are prepended by ClassName::. Let's test it out by defining a circle of unit radius in our main program:

#include <iostream>
#include "Circle.h"
using std::cout;
using std::endl;

int main() {
    Circle c;
    c.setRadius(1);
    cout << "Perimeter: " << c.getPerimeter() << endl;
    cout << "Area: " << c.getArea() << endl;
    
    return 0;
}
(base) param@pop-os:~/lab/cpp/circle$ ./main
Perimeter: 6.283
Area: 3.1415

Nice!