Showing posts with label Class. Show all posts
Showing posts with label Class. Show all posts

Association, Composition and Aggregation in C++

In this tutorial from our C++ course, we will learn how different Classes and Objects relate to each other, and study this relationship further.

Classes and Objects in Real Life

So far, in our course, we have used classes in a very isolated way, creating and using only one class. But in the real world, it rarely happens. We live in a world of objects.

Often, it only makes sense that there is an object, if there are others. For example, we can have the Human class and the Food class. Human-type objects are you, me, our friends, family ... Food-type objects, rice, beans, meat ... does it make sense for Human-class objects to exist without Food-class objects? Of course not.

And even if one object does not depend on another to exist, it can depend on others to 'work'. For example, objects from the Engine, Gear, Brake, etc. classes work together to make a Car type object work.

That is, in the real world, objects are not isolated. In your projects, you will always create several classes, instantiate several objects, make one create another, send information, another receive data from another object, the method of an object using several other objects, and so on.

Association, Composition and Aggregation

When an object uses a method or service from another object, we say that there is an association there. Yes, it is very broad and generic. We will specify more the types of relationship, in composition and aggregation.

In both cases, an object has another object. However, in composition, an object exists only if the other exists.

For example, the object of type Car only exists if it has an object of the Engine class. There is no car without an engine.

A Human type object, only exists if it has objects like Heart, Lung ... there is no person without these organs (at least for now, some program will design and create organs in the future - of course, it would use C++).

In aggregation, an object has another, but it could exist without it. For example, every car has an owner. That is, it has Human-type objects that have Car-type objects. But a human being does not necessarily need a car to exist.

You need a heart, a head ... mandatorily. Not a car. The relationship of a Car-type object and a Human-type object is aggregation.

Association, Composition and Aggregation in C++

In composition, when a parent object is destroyed, the child objects will also be destroyed. One does not exist without the other. In aggregation, no. In other words, association is something very generic, then there is aggregation (one can exist without the other) and finally the composition, the most specific relationship, where an object only exists if another exists.

But let's put these generic conversations aside and see in practice some relationships between objects.

Composition in C++

Let's start with the most specific. To make it easier, we call the Human and Car classes parent classes. The classes Engine, Heart, Gear, Lung etc., are the child classes, members or components. Or we call it All and Parts, or Object and Member.

To be characterized as a composition, a member is part of the whole. Each part belongs to only one object (that is, the heart belongs only to a human, and the car's engine belongs to only one car).

The class that represents the Whole, will manage the parts, the components. These members are unaware of the existence of the 'Whole'.

Let's create the Engine class, in the constructor we warn that we are starting the engine and in the destructor function we warn that we are turning the engine off. Engine.h:

#ifndef ENGINE_H
#define ENGINE_H

class Engine
{
    public:
        Engine();
        ~Engine();
};

#endif // ENGINE_H

Engine.cpp

#include "Engine.h"
#include <iostream>
using namespace std;

Engine::Engine()
{
    cout << "Starting the engine..."<<endl;
}

Engine::~Engine()
{
    cout << "Turning off the engine..."<<endl;
}

Now we are going to create the Car class, which will do almost the same as the Engine, it will say 'starting the car' in the constructor and 'turning the car off' in the destructor. However, it will have a member, a pointer for the Engine type, the variable 'myEng'.

In the class, we just declare this pointer, Engine.h:

#ifndef CAR_H
#define CAR_H
#include "Engine.h"

class Car
{
    public:
        Car();
        ~Car();
        Engine *myEng;
};

#endif // CAR_H

But in the implementation, we instantiate this pointer, causing the constructor method of the 'myEng' object to be invoked. In Car's destructor function, we delete the Engine pointer, automatically invoking the destructor function, Car.pp:

#include "Car.h"
#include <iostream>
using namespace std;

Car::Car()
{
    cout << "Let's start the car."<<endl;
    myEng = new Engine();
}

Car::~Car()
{
    delete myEng;
    cout << "Car off."<<endl;
}

Our main.cpp:

#include <iostream>
#include "Car.h"
using namespace std;

int main()
{
    Car myCar;

    return 0;
}

The result is as follows:

Let's start the car.
Starting the engine...
Turning off the engine...
Car off.

The 'myEng' object EXISTS ONLY because of the 'myCar' object. Without 'myCar', there is not 'myEng'. 'myEng' belongs to 'myCar'. One object belongs to another.

Whoever 'controls' myEng is also myCar. He who creates the object, instantiates ... and the Car class object dies, the Engine class object also dies. The 'myEng' object belongs only to the 'myCar' object, to none other. And he doesn't know about any other object either, and he doesn't know anything about the Car class.

Those things that characterize the composition well.

Aggregation in C++

We are now going to create the Human class, to create people. They will drive the car. To create an object of this class, we need to pass a string with the person's name and an object of type Car, see how Human.h looks:

#ifndef HUMAN_H
#define HUMAN_H
#include <string>
#include "Car.h"

class Human
{
    public:
        std::string name{};
        Car myCar;
        Human(const std::string& str, Car car);
        ~Human();

};

#endif // HUMAN_H

Now the Human.cpp implementation:

#include "Human.h"
#include <iostream>
#include <string>
using namespace std;

Human::Human(const std::string& str, Car car)
{
    name = str;
    myCar = car;
    cout<<name;
    myCar.turnOn();
}

Human::~Human()
{
    cout<<name;
    myCar.turnOff();
}

We made some changes to Car.h:

#ifndef CAR_H
#define CAR_H
#include "Engine.h"

class Car
{
    public:
        void turnOn();
        void turnOff();
        Engine *myEng;
};

#endif // CAR_H

And in the Car.cpp implementation:

#include "Car.h"
#include <iostream>
using namespace std;

void Car::liga()
{
    cout << " will turn on the car."<<endl;
    myEng = new Engine();
}

void Car::desliga()
{
    cout <<" turned off the car."<<endl;
    delete myEng;
}
 

That is, now we have the functions turnOn() and turnOff(), on objects of the Car type (before we used to turn on and off the constructor and destructor).

See how our main.cpp looks like:

#include <iostream>
#include "Car.h"
#include "Human.h"

using namespace std;

int main()
{
    Car car;
    Human *h1 = new Human("Neil Peart", car);
    delete h1;

    cout << endl;

    Human *h2 = new Human("Bruce Dickinson", car);
    delete h2;

    return 0;
}

That is, we created an object of the Car class and two of the Human class.
Let's see some interesting things. The result if we run the code above is:

Neil Peart will start the car.
Engine running.
Neil Peart turned off the car.
Engine off.

Bruce Dickinson will start the car.
Engine running.
Bruce Dickinson turned off the car.
Engine off.

First, the same 'car' object is used for both 'h1' and 'h2' objects.

Second, it is the h1 and h2 objects that trigger the car's turnOn() and turnOff() functions, that is, they handle the 'car' object.

Finally, the 'car' object does not cease to exist when the 'h1' object ceases to exist. It remained there alive, so much so that it was used by the object 'h2' shortly thereafter. That is, although there is a relationship between them (some objects use others), they are somewhat independent, unlike the relationship between Car and Engine, where engines ONLY EXIST as long as there are cars, and only one engine is used for each car .

These are the characteristics of aggregation.
Between Car and Engine, it's composition.
Between Human and Car, it's aggregation.

Association in C++

Let me tell you the biggest secret of the C++ language: a large, complex system, like a space station or Microsoft Excel, is nothing less than several small objects, playing specific roles.

In other words, a complex system is nothing more than several small objects, working together, as an association.

Thus, during your career as a C++ programmer, always try to create specific, well-defined Classes and Objects, with the right functions and as simple and direct as possible.

To repeat: a large project or system is nothing more than a looot of objects working together, in association, whether by composition or aggregation.

Organization is the key to success in working with object-oriented programming!

Accessing members of Classes and Objects: private and public

In the tutorial past our course, we learned how to create classes and objects in C++. Now, let's see how to use this knowledge, accessing the members (variables and functions) of an object / class.

Accessing members of Classes and Objects: .

At the end of our previous tutorial, we had the code that created a Square class and the object 'q'. Do the following, run this code. Obviously, nothing happened. We define a class, instantiate an object, and that's it.

We will now learn how to access these members of objects, using the dot operator: .

See that we have the object 'q'. It has the variable 'side' and the function 'area', which can be accessed:

  • q.side;
  • q.area();

Just put the name of the object, followed by the dot operator and the name of the member, defined in the class, just as we do with structs. Let's create a program that defines a value for the side, and then call the area() function to print the value of the area of that square:

#include <iostream>
using namespace std;

class Square
{
    double side;
    double area();
};

double Square::area()
{
    return side*side;
}

int main()
{
    Square q;
    q.lado = 2;
    cout<<"Area: " << q.area() << endl;

    return 0;
}

Run this code and see the result. The error will appear:
‘Double Square :: side’ is private within this context |

In other words, you're saying that the 'side' variable is private! What is it? And now, Jose?

Access specifiers: public and private

Remember that when we talk about class and objects, we said that it has a special power: to make some things public for all the code and other things private, which can be accessed only by some elements? Yeah, that's it.

As we have not defined how these members will access, C++ has put them by default as private (ie secret).

Since everything is private, only the internal members of the objects can access this data. That is, only one function of the object can access and modify the value of that object's variable.

But, we want to access this variable in the main() function, an outside function, nothing to do with the object / class. So, we need to define these members as public.

To do this, just type "public:" before what we want to define as public, see how our class looks:

class Square
{
    public:
        double side;
        double area();
};

Make that small change to your code, and run it. The result will be:


Now, if I defined the side as having a value of 2, the area will be 2x2 = 4, that's correct!
See how wonderful this object-oriented programming ... I created an object named 'q', and it automatically came with the variable 'side' and the function 'area()'.
Information security in Classes and Objects

Nice ... very beautiful ... but there is a problem there ... this 'side' variable, it is visible and accessible to any part of the program. Imagine if it is part of your company's Treasury code, would you find it interesting that someone from another sector had access to this variable?
It's a security breach, do you agree?

How about if only one function of class Square had access to the variable 'side'. It would make more sense, wouldn't it?

It would also make sense for the 'side' variable to be private, no one could tamper with it outside the object's scope.

We will then create a function called 'define(double)' that receives a variable the arrow that value for the variable 'side'.

Our more secure and professional code will look like this:
#include <iostream>
using namespace std;

class Quadrado
{
    public:
        void define(double);
        double area();
    private:
        double side;
};

void Square::define(double l)
{
    lado = l;
}
double Square::area()
{
    return side*side;
}

int main()
{
    Square q;
    q.define(2);
    cout<<"Area: " << q.area() << endl;

    return 0;
}

That is, we now define the value of the side of the square using the define() function, and no longer having direct access to the 'side' variable. In fact, you can create 1 billion objects now, you will not be allowed to modify or directly access the 'side' variable of any of them!

Do you want to change the side value? Asks the function Square.define()
Want to know the area of that square? Asks the function Square.area()

The communication of objects with the external world is only by functions, and this is very interesting because we can have greater control over some information.

Object Oriented Exercises

1. You need to know the side of an object of type Square, create a function that returns the value of the side of that square, incrementing the previous code.

2. When defining the side of the square, obviously it cannot be 0 or less, make the function define() only accept positive values from the side to the square.

How to create a Class and Objects in C++

Now that we have a good idea of what the Object-Orientada programming paradigm is, as well as the Class and Object concepts (in a more abstract way), let's get our hands dirty and make code! Create such classes and real objects.

How to create a Class in C ++

Initially, the concept of class encoding is very reminiscent of structs. In this case, we will use the keyword class to create a Class, as follows:

#include <iostream>
using namespace std;

class MyClass
{
    //Informations
    //about your
    //Class
};

int main()
{
    return 0;
}

That is, we write class, choose a name for our class, open keys and put all the information about it inside. Don't forget to put a semicolon at the end of the class scope!

Ready, the MyClass class was created! Also note that it is not within the main() function, but at the same level as it.

Defining members of a Class: Variables and Functions

Shall we create a real class? We will create a class that will create squares. Our class is called Square.

What is an important data of a square? Hey, its side. Soon, it will have a variable that stores its side.

What other important 'thing' in a square? Its area. Let's create a function that calculates the area of that square. Our class looks like this:

#include <iostream>
using namespace std;

class Square
{
    double side;
    double area();
};

double Square::area()
{
    return side*side;
}

int main()
{
    return 0;
}

There, there is the declaration of the variable 'side' as well as the header of the area() function. And this function, where are we going to declare? It was declared after the scope of the class.

So far, in our course, if we wanted to declare an area() function in our programs, we would do:

double area()
{
     return side * side;
}

And this function is visible and accessible to our entire program, correct?

What if we want to create a function that is a Class and should be visible and accessible only by that class?
We do:

double Square::area()
{
    return side * side;
}

Understood? Put "ClassName::" before the function name, that says that function is of the ClassName class, and only it has access and can use that function!

How to create and instantiate objects in C++

Ok, our class is cute and done! Now let's create objects from it!
If you want to create information of the entire type, you do:

int num;
int age;
int ID;

If you want to create string information, you do:
string name;
string address;

And so on. If you want to create information like 'MyClass', you do:

MyClass example;

For example, to create an object of class Square, you would do:

Square q1;
Square square;

Let's call our object 'q', we create it like this:

#include <iostream>
using namespace std;

class Square
{
    double side;
    double area();
};

double Square::area()
{
    return side*side;
}

int main()
{
    Square q;

    return 0;
}

Ready. Now there is a real square, called Square, which has 'side' and 'area()' members. Nice, right?

When we create an object, we say that we are instantiating an object q of class Square. It is a new 'instance' of the class.

You can even create another object, or millions, just give them different names: q1, q2, ..., q2112 ... each one will have its characteristics: its 'side' values and its areas. Although they are of the same Square 'type' (that is, they all have side and area() in common), each has its specific values.

It's just like us, people ... everyone has a name, heart, lung capacity, age ... but each has its own specific values (specific name, specific age, specific physical condition). Now you understand better the concept of Class and Object, in C++?

In the next tutorial we will learn how to access, change and use these members of the Square class.

What are Classes and Objects in C++

In this tutorial of our C++ course, we will learn in a very colloquial and simple way, what classes and objects are, the basis of object-oriented programming.

What is a Class

Class is nothing more than a blueprint, a mold, a diagram.
For example, let's imagine a class Car.

This class will describe all the details of this car: its size, number of doors, engine power, whether it is manual or automatic, whether it has a sunroof or not, its utilities, etc.

That's basically it, it's a 'form', which explains what the ... objects are like.
To make a car, we need the details of the Car class to create a car. This car is going to be an object.
Yes, to explain class, we have to talk about object ...

What is an Object

... and to talk about Object, we need to talk about Class. It is not possible to separate or explain one of the two things well, something is 'vague', and I hate these technical and vague explanations.

Everything you know is an object. You are an object, you live in an object, you eat objects, you move around objects, you are accessing this page / booklet through an object, in fact, this course is an object.

Everything is an object.

Understand object as the real, day-to-day things that actually exist. And class, like something abstract.

Class and its Objects

A good way to explain something is through real examples. So come on.

Let's say you completed the Progressive C++ course and became a hell of a C++ programmer, with an excellent salary, and decided to buy a car.

You won't come to the dealership and say, "Hey, man, I want a car".
And the salesman won't say, "Okay, here's a car".
Nor will you answer, "Thanks, I have a car now"

When you go to buy a car, you will want a Civic, a Camry, a Corolla or a BMW (if you are a C++ programmer). That is, you will buy something specific. That specific car is an object. An object of the class Car.

The class Car will say: "These objects have x doors, such a engine, transmission, such power, such color ...", that is, the common characteristics that all cars have. All cars have doors and engines, for example.

A Volkswagen Beetle has two doors and a weak engine. Your Audi has 4 doors and a huge power. But both have a certain number of ports and an exact power value.

In other words, a Beetle, a BMW, a Mercedes ... they are all objects of the Car class.

Got it?

Class and objects in C++


Attributes and Functions of Classes and Objects

Let's go to one more example. You don't know or deal with a 'human'. You deal with your father, your mother, your friends ... that is, 'specific' humans.
Let's create the Human class. What are the characteristics of a human? Hey, he has a name, age, height, weight, heart, lung, etc. etc.

We call these attributes details, their details, their information.

This class will also 'do' some things, such as: breathing, beating the heart, walking, sleeping ... that is, the Human class, in addition to having characteristics (values, numbers), it will also have some actions ... these actions are functions.

Specific functions that only exist in the Human class. After all, it does not have a Breathe() function in the Car class, nor does it have a Shifting() function in the Human class.

That is, each Class has its characteristics (attributes) and specific actions that occur there (functions). This is what defines a class: attributes and functions.

The cool thing about object-oriented programming is that the functions of the Car can only act on objects of the Car type, and the actions of the Human class will only be able to act on objects of the Human class.

Instantiate (create) objects from a Class

When you are going to create something, that something was created from a class. That is, we say that the object was instantiated from a class.

For example, suppose you were hired by a company to work in the HR industry. At first, you will create a class called Employee.

What are the characteristics of an Employee? Hey, he has a name, position, salary, identification number ...

When someone new is hired, you need to create a specific object for that new employee. We say that you will instantiate an object of the Employee class.

This object has a name "Neil Peart", age (32), salary ($ 10,000.00/month- after all, it is a C++ programmer), identification number (2112) ...

That is, objects are real things, based on abstract stuff (classes).

From the next tutorial, we will really learn how to program classes, how to instantiate objects, how to define their characteristics and actions.

Object Oriented in C++: Introduction

 Before going into detail about a new programming paradigm (object oriented), let's understand a little what we were going to do and what we are going to do differently.


Functional Programming

So far, we have only used one programming style: functional, also called procedural. As the name says, it is a method that uses procedures, or as we call it: functions.

Basically, it is a script, a routine of procedures and commands. In other words, we only use variables and functions. Let's take an example.

Suppose you want to calculate the arithmetic average of two numbers, in C++. Necessarily, you will have to have two variables to store the values and an average calculation. There, there is a 'script' of what should be done.

What you can do differently, is to put the average in a function, so that it can be invoked indefinitely:

#include <iostream>
using namespace std;

float average(float num1, float num2)
{
    return (num1+num2)/2;
}

int main()
{
    float num1, num2;

    cout<<"Number 1: ";
    cin >> num1;

    cout<<"Number 2: ";
    cin >> num2;

    cout<<"Average: "<< average(num1,num2) << endl;

    return 0;
}

See how this program is just a procedure, it starts running from the beginning of main() and goes to the end of it. Always. Everything we did was always like this. It has a beginning (usually variable declaration), a middle (calling functions to do various things) and an end (showing results).

The purpose of functional programming is to create functions that do things. It may seem simple and fool right? But incredible things were done using this. The Linux Kernel, for example, does not use C++, only C, that is, it has no object oriented, only procedural programming.

Over the years and decades, software has become more and more and more and more, and a little more, complex. And some problems were emerging.


Oriented Object Programming

So far, in our programs, any function could work on any data. This over time became a security issue. It would be ideal if certain functions could act only on some data.

For example, in functional programming, functions that work with a company's Treasury data could work with any data, such as that of Employees. But it would be better if the treasury had its own functions and to work with employee data, they had their own functions as well. And for the sake of security, none could touch the things of others.

Another problem: you assign a function to receive an integer. Someone accidentally uses this function and sends a float. If you do this test, it will give an error, the wrong answer will come out and it can even simply close the program by running. Can you imagine 'closing' the program of an airplane, in mid-flight? It's not cool, right?

Hence the blessed and beautiful OOP: Object Oriented Programming. It solves these problems, and in an incredibly simple and easy way. Its secret is: it starts working with something called an object.

Each object will have its own variables and only a few functions can see it act on it.

If you have a Sound object in your game, it will have specific variables, characteristics and functions acting on it. Character type objects will have specific variables, characteristics and functions for them. A function that affects Sound cannot act on a Character type object. And, wow, that avoids many bugs and potential problems.

That of each object having its data and procedures, is the so-called encapsulation, the basis of the OOP logic. It is as if there is a specific code for each 'thing'. A function only sees data for that 'thing' and can only act on that 'thing'. You can even hide information, say clearly: 'Hey, this variable here, which stores the password, can only be seen here inside the server, it is inaccessible to users outside'. And that brings incredible security.

If you are developing a game in C++ and use object orientation, you will create data and procedures that will only act and make sense in the Logic part. It will create information and functions that will only be visible and will only act on Graphics, you will create specific things for the Scenario (which are not even visible outside this scope). You encapsulate, you divide, you organize things ... are you getting the idea of OOP?

It is no longer that mess of functions and variables that everyone can see and use. A declared variable should generally only be used by the X() function. But the Y() function can indeed see and act on this variable, this is an error, a problem, and it would be interesting if this were naturally impossible, if the language itself made this separation. And it is this separation that Object Oriented does.

If you make a Web system, you want only a few functions to be available to users, such as the function Display(), which will show the grades of an Distance Education student. But if you used functional programming, the evil student can create code that calls the ChangeGrade() function, to change your grades, to hack the system. Well, he may well "guess" the name of the functions, and he will get it right...

With object-oriented programming, we can make it very clear: "Hey system, only this function and these variables can be accessed by students". When he tries to invade the system, calling other functions that are not part of that 'object' (his grades, for example), he will be summarily blocked.

This object orientation is cool, right? But let's stop talking and go to the next tutorial and start learning how to use this awesome thing for good.

Study resources

Programming Paradigm
Functional Programming