Showing posts with label Static Variable. Show all posts
Showing posts with label Static Variable. Show all posts

Instance Members and Static Members

In this tutorial of our C ++ course, we will clarify a little more about the variables of the objects as well as learn what static members are and how to use them in practice.


Instance members (of objects)

Static members in C++
Recalling our study of functions a little, we saw there that, commonly, the variables declared within a function are said to be local and temporary. Because they only exist within the function and are deleted from memory when the function ends. In classes, something similar occurs.
When we have a 'Car' class and the 'engine' attribute, we do:

  • BMW.engine = 4;
  • corolla.engine = 2;

Although the name of the variable is the same, each object has its own variable, where one does not change the other. That is, 'copies' of these variables are created.

Thus, the variables are specific to each instance, even though they have the same name and the objects originate from the same Class.


Static members of a Class

However, sometimes we do not want each instance to have its own attribute, it may be necessary to have an attribute that is exactly the same (same memory location), for all objects.

And it is possible to do this, for both variables and functions.

For example, suppose you are the programmer who will take care of a large company's system, and each time a person is hired, an Employee type object must be created. And each time an employee is fired, an object is deleted. How do you keep track of how many employees there are?

Simple, just create a static variable, which is incremented every time an object is instantiated and is decremented every time an object is deleted.


Static variable

To create a static variable, just use the static keyword before declaring the variable.

Let's create the class "Car.h":

#ifndef CAR_H
#define CAR_H


class Car
{
    public:
        Car();
        ~Car();
        int getTotal();

    private:
        static int total;
};

#endif // CAR_H

See that we declare the entire variable 'total' as static. Let's see the implementation, 'Car.cpp':

#include "Car.h"

int Car::total = 0;

Car::Car()
{
    total++;
}

Car::~Car()
{
    total--;
}

int Car::getTotal()
{
    return total;
}

The first thing we did was to initialize the total variable with 0, after all, initially, no object was instantiated. The constructor function simply increases the total value, that is, each time we instantiate an object, this variable will be increased.

And in the destructor function, we decrease this variable.

And since it is static, this value will represent the number of objects created from the Car class. See how our main.cpp looks like:

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

int main()
{
    Car *ptr1, *ptr2, *ptr3;
    ptr1 = new Car();
    ptr2 = new Car();
    ptr3 = new Car();

    cout<<"Number of instantiated objects: "<< (*ptr1).getTotal() <<endl;

    delete ptr3;
    cout<<"Number of instantiated objects: "<< (*ptr1).getTotal() <<endl;
return 0; }

First, we created three Car-type objects. Next, we do the dynamic memory allocation.

We print the result after these 3 allocations. We delete the third pointer (this causes the destructor ~ Car() function to be triggered), then print the number of instances again.

And the result is:

"Number of instantiated objects: 3"
"Number of instantiated objects: 2"

Note that we use the function of the first object, '*ptr1', which we created, this proves that the variable 'total' is the same, for all objects.


Static function

Just as static variables exist, we can also create static functions, for a class. However, they have a very specific characteristic: they can only act on static variables.

We will create the zero() function, which will reset the 'total' variable. Our "Car.h" class:

#ifndef CAR_H
#define CAR_H

class Car
{
    public:
        Car();
        ~Car();
        int getTotal();
        static void zero();

    private:
        static int total;
};

#endif // CAR_H

Our implementation "Car.cpp"

#include "Car.h"
int Car::total=0;

Car::Car()
{
    total++;
}

Car::~Car()
{
    total--;
}

int Car::getTotal()
{
    return total;
}

void Car::zero()
{
    total=0;
}

Finally, our main:

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

int main()
{

    Car *ptr1, *ptr2, *ptr3;
    ptr1 = new Car();
    ptr2 = new Car();
    ptr3 = new Car();

    cout<<"Number of instantiated objects: "<< (*ptr1).getTotal() <<endl;
delete ptr3;
    cout<<"Number of instantiated objects: "<< (*ptr1).getTotal() <<endl;
Car::zero();
    cout<<"Number of instantiated objects: "<< (*ptr1).getTotal() <<endl;
return 0; }

And the result is:

"Number of instantiated objects: 3"
"Number of instantiated objects: 2"
"Number of instantiated objects: 0"

An interesting thing about static members is that they exist even before any instance of the class is created. So, without creating any objects, you can already access 'total' and 'zero()'.

For example, you can ask the user for a value and use that value to change a static variable of a class, before even starting to instantiate objects from it, and start working with objects from a value previously determined by the user.

Local, Global, Global Constant, and Static Variable

In this tutorial from our C++ e-book, we will learn a little more about the relationship between functions and variables, knowing the local, global, constant, and static variables types.

Local variable

When we declare a variable within a function, we say that it is local.
This is due to the fact that it 'exists' only for those who are within the function, that is, only inside can see it and its value.

Other commands in other functions cannot access it normally.
To illustrate this, let's declare the variable myVar with value 1, inside main().

Next, let's call the print () function, which will print the value of myVar:
#include <iostream>
using namespace std;

void print()
{
    cout<<myVar;
}

int main()
{
    int myVar=1;
    print();
    return 0;
}
This code is neither compiled, the error appears:
"'myVar’ was not declared in this scope | "

That is, the myVar variable is not within the scope of the print() function, it is as if it did not exist.

The opposite also applies:
#include <iostream>
using namespace std;

void print()
{
    int myVar=1;
}

int main()
{
    cout<<myVar;
    return 0;
}
That is, not even the main() function can see the internal content of the print() function.

Now let's declare myVar both inside print() and inside main(), and let's print both values:
#include <iostream>
using namespace std;

void print()
{
    int myVar=1;
    cout << "In print() = "<<myVar<<endl;
}

int main()
{
    int myVar=2;
    cout << "In main() = "<<myVar<<endl;
    imprime();
    return 0;
}
Results
C++ Progressive e-book

That is, we can declare variables of the same name, but in different functions.
And the functions only 'see' what's inside that function, ok?

Global variable

There is a way to make the same variable seen and accessed by several functions, just make it a global variable.

To do so, simply declare it outside the scope of functions.
For example, let's declare the variable pi, and store the value of pi.

Next, we will ask the radius value from the user, and using two other functions, we calculate the perimeter and the area of the circle:
#include <iostream>
using namespace std;
float pi = 3.14;

float perimeter(float r)
{
    return 2*pi*r;
}

float area(float r)
{
    return pi*r*r;
}

int main()
{
    float rad;

    cout<<"Radius: ";
    cin>>rad;

    cout<<"Perimeter: " << perimeter(rad)<<endl;
    cout<<"Area     : " << area(rad)<<endl;

    return 0;
}
Note that we use the pi variable in functions, without declaring them within their scope.

If we were to use local variables, we would have to declare pi more than once, which would not be very efficient.

Use global variables when they are needed in many different parts of your code.
And you can use the same name for a local and global variable. In this case, the local variable will have priority.

Global constants

Very careful when using global variables. In complex programs, it is easy to 'lose control' of global variables, as they can be changed anywhere in code.

In most cases, give priority to using same arguments.

However, if you want to use global variables that should not be changed, use the const keyword before declaring the variable:
  • const float pi = 3.14;

Let's suppose a hacker broke into your system, and entered a function called change(), which will change the value of pi to 4, sabotaging your project:
#include <iostream>
using namespace std;
const float pi = 3.14;

void change()
{
    pi = 4;
}

int main()
{
    change();

    return 0;
}
As the variable was declared with the const keyword, it will give the error:
"| 7 | error: assignment of read-only variable pi ’|"

That is, the variable is read only, cannot change the 'pi'. And in fact, no program should change pi, so it makes sense that it is global and constant, do you agree?

Let's assume that you will create a system for a large supermarket chain, and you will set the discount price at 10%, do:
  • const float off = 0.1;

Ready. Now thousands of functions can access the discount amount.
What if you want to increase the discount to 20%?
Easy, just do:
  • const float off = 0.2;

See that you changed just one thing, just one variable. But it automatically modified the calculations of the thousands of functions that use this variable directly.

It changes only once, and the change occurs in multiple corners.
If you had done it locally, you would have to go to each function and change variable by variable ... it would take hours or days.

But with constant global variable, no. Changes only once. And everything changes.
Did you get the utility of global and constant variables?

Static local variable

When we declare a variable within a function, it is created and reserved in computer memory at the beginning of the function and is destroyed at the end of the function's execution.

In the code example below, we initialize the myVar variable to 1, print, increment by one, and terminate the function.
#include <iostream>
using namespace std;

void test()
{
    int myVar=1;

    cout<<myVar<<endl;

    myVar++;
}

int main()
{
    test();
    test();

    return 0;
}
We call the test() function twice, and what appears on the screen is always the same: the value 1.

Each time the function runs, the variable is created, initialized and the value 1 is displayed. It is incremented, but then the function ends and the variable simply dies.

We then say that local variables are nonpersistent. That is, they do not 'persist', they are created and destroyed along with the function.

There is a way to make the variable persistent, that is, it is created initially and not destroyed, its address and value in memory still remains. These are the static variables.

To declare a variable to be static, just use the static keyword before the declaration:

  • static int myVar;


Veja:
#include <iostream>
using namespace std;

void test()
{
    static int myVar=1;

    cout<<myVar<<endl;

    myVar++;
}

int main()
{
    test();
    test();
    test();
    test();

    return 0;
}
Ready. No matter how many times you call the test() function, the myVar variable you will use is declared and initialized only once. When the function ends, it will still persist and when calling the function again, it will already take the previous value of the variable, to print and increment.

Like global variables, local static are always initialized to 0 if you do not explicitly initialize. And if you boot, this boot will only occur once, as you saw in the previous code example, ok?