Object-Oriented Thinking in C++: Instance and Static Members

A static variable is shared by all objects of the class. A static function cannot access instance members of the class.

The data fields used in the classes so far are known as instance data fields, or instance variables. An instance variable is tied to a specific instance of the class; it is not shared among objects of the same class. For example, suppose that you create the following objects using the Circle class in Listing 9.9, CircleWithPrivateDataFields.h:

Circle circle1;
Circle circle2(
5);

The radius in circlel is independent of the radius in circle2 and is stored in a different memory location. Changes made to circle1’s radius do not affect circle2’s radius, and vice versa.

If you want all the instances of a class to share data, use static variables, also known as class variables. Static variables store values for the variables in a common memory location. Accordingly, all objects of the same class are affected if one object changes the value of a static variable. C++ supports static functions as well as static variables. Static functions can be called without creating an instance of the class. Recall that instance functions can only be called from a specific instance.

Let us modify the Circle class by adding a static variable numberOfObjects to count the number of circle objects created. When the first object of this class is created, numberOfObjects is 1. When the second object is created, numberOfObjects becomes 2. The UML of the new circle class is shown in Figure 10.10. The Circle class defines the instance variable radius and the static variable numberOfObjects, the instance functions getRadius, setRadius, and getArea, and the static function getNumberOfObjects. (Note that static variables and functions are underlined in the UML diagram.)

To declare a static variable or a static function, put the modifier static in the variable or function declaration. So the static variable numberOfObjects and the static function getNumberOfObjects() can be declared as follows:

static int numberOfObjects;     

static int getNumberOfObjects(); 

The new circle class is defined in Listing 10.6

Listing 10.6 CircleWithStaticDataFields.h

1 #ifndef CIRCLE_H
2
#define CIRCLE_H
3
4
class Circle
5 {
6     
public:
7    Circle();
8    Circle(
double);
9   
double getArea();
10   
double getRadius();
11   
void setRadius(double);
12   
static int getNumberOfObjects();
13
14   
private:
15   
double radius;
16   
static int numberOfObjects;
17 };
18
19
#endif

A static function getNumberOfObjects is declared in line 12 and a static variable numberOfObjects is declared in line 16 as a private data field in the class.

Listing 10.7 gives the implementation of the Circle class:

Listing 10.7 CircleWithStaticDataFields.cpp

1 #include “CircleWithStaticDataFields.h”
2
3
int Circle::numberOfObjects = 0;
4
5
// Construct a circle object
6 Circle::Circle()
7 {
8     radius =
1;
9     numberOfObjects++;
10 }
11
12
// Construct a circle object
13 Circle::Circle(double newRadius)
14 {
15    radius = newRadius;
16    numberOfObjects++;
17 }
18
19
// Return the area of this circle
20 double Circle::getArea()
21 {
22   
return radius * radius * 3.14159;
23 }

24
25
// Return the radius of this circle
26 double Circle::getRadius()
27 {
28   
return radius;
29 }
30
31
// Set a new radius
32 void Circle::setRadius(double newRadius)
33 {
34    radius = (newRadius >=
0) ? newRadius : 0;
35 }
36
37
// Return the number of circle objects
38 int Circle::getNumberOfObjects()
39 {

40    return numberOfObjects;

41 }

The static data field numberOfObjects is initialized in line 3. When a Circle object is created, numberOfObjects is incremented (lines 9, 16).

Instance functions (e.g., getArea()) and instance data fields (e.g., radius) belong to instances and can be used only after the instances are created. They are accessed from a specific instance. Static functions (e.g., getNumberOfObjects()) and static data fields (e.g., numberOfObjects) can be accessed from any instance of the class, as well as from their class name.

The program in Listing 10.8 demonstrates how to use instance and static variables and functions and illustrates the effects of using them.

LisTing 10.8 TestCircleWithStaticDataFields.cpp

1 #include <iostream>

2 #include “CircleWithStaticDataFields.h”

3 using namespace std;
4
5
int main()
6 {
7    cout <<
“Number of circle objects created: ”
8    << Circle::getNumberOfObjects() << endl;
9
10    Circle circle1;
11    cout <<
“The area of the circle of radius ”
12       << circle1.getRadius() << ” is ” << circle1.getArea() << endl;
13    cout <<
“Number of circle objects created: ”
14       << Circle::getNumberOfObjects() << endl;
15
16    Circle circle2(
5.0);
17    cout <<
“The area of the circle of radius ”
18       << circle2.getRadius() << ” is ” << circle2.getArea() << endl;
19    cout <<
“Number of circle objects created: ”
20        << Circle::getNumberOfObjects() << endl;
21
22    circle1.setRadius(
3.3);
23    cout <<
“The area of the circle of radius ”
24       << circle1.getRadius() << ” is ” << circle1.getArea() << endl;
25
26    cout <<
“circle1.getNumberOfObjects() returns ”
27       << circle1.getNumberOfObjects() << endl;

28    cout << “circle2.getNumberOfObjects() returns ”
29       << circle2.getNumberOfObjects() << endl;
30
31   
return 0;
32 }

Static variables and functions can be accessed without creating objects. Line 8 displays the number of objects, which is 0, since no objects have been created.

The main function creates two circles, circlel and circle2 (lines 10, 16). The instance variable radius in circle1 is modified to become 3.3 (line 22). This change does not affect the instance variable radius in circle2, since these two instance variables are independent. The static variable numberOfObjects becomes 1 after circle1 is created (line 10), and it becomes 2 after circle2 is created (line 16).

You can access static data fields and functions from the instances of the class—e.g., circle1.getNumberOfObjects()in line 27 and circle2.getNumberOfObjects()in line 29. But it is better to access them from the class name—e.g., Circle::. Note that in lines 27 and 29 circle1.getNumberOfObjects() and circle2.getNumberOfObjects() could be replaced by Circle::getNumberOfObjects(). This improves readability, because the reader can easily recognize the static function getNumberOfObjects().

Source: Liang Y. Daniel (2013), Introduction to programming with C++, Pearson; 3rd edition.

Leave a Reply

Your email address will not be published. Required fields are marked *