본문 바로가기

Programming/C++ Basic

[Basic C++] 20 - Static members / Const members / Static const members in C++

 From the previous post, the "static" and "const keywords were introduced briefly. Those keywords are complicated to use, as their behaviors are flexible under different situations. On the contrary, when they are brought in C++ class, the behaviors of them are pretty straightforward.

 

In this post, I am going to talk about static members, const members, and static const members in C++ class and how to use them efficiently, but not too deep.


1. Static members

Static members in a class only exist in the class, and not copied to the objects of the class. Consider static members are unique members of the original class. They are created when the class is defined, thus you can access them using the scope resolution operator (::), even before the instantiation of the class. For instance, static member "A" of class X can be accessed using X::A.

 

1.1) Static variables

The static variables of a class are variables shared by all objects of the class. They are treated just like global variables, thus they must be declared outside the class within the global scope. The static variable "id" in the following example in class A is defined as "A::id = 0" using the scope resolution operator.

 

One popular usage of static members is the assign a unique ID for each object using a static variable and a constructor. Class A and its five objects are declared on the heap using a double pointer.

 

Code Example: 1

#include <iostream>

class A {
private:
// Static int variable for a unique object ID
	static int id;
public:
	A() {
		id++;
	}
	void print_id() {
		std::cout << "Object id = " << id << std::endl;
	}
};
// Static variable are defined outside the class.
int A::id = 0;

int main() {
// class double pointers
	A **a = new A *[5];
	for (int i = 0; i < 5; i++) {
    // Assign dynamic objects to dynamic pointers
		a[i] = new A();
		a[i]->print_id();
	}
}

Figure 1 Result of code example 1

 


1.2) Static member functions

Static functions are no different from static variables. They belong to a class itself rather than its objects. A static function inside a class X is called using the same syntax with static variables; eg, "X::static_function". One common way to use a static member function is to access private static variables.

 

Code example 2

#include <iostream>
#include <string>
using String = std::string;

class X {
private:
	static String p_str;
public:
	static String str;
};

String X::p_str = "Private static variable\n";
String X::str = "Public static variable\n";

int main() {
	X::str;
	X::p_str;
}
error C2248: 'X::p_str': cannot access private member declared in class 'X'
message : see declaration of 'X::p_str'
message : see declaration of 'X'

The preceding example shows a class X with two static variables; p_str and str. Both of them are defined outside the class and be called in the main function. But X::p_str is not allowed, as the static variable is declared with the private access specifier.

 

To access private variables inside a class, public member functions are often declared. The problem here is that the class must be instantiated to use the function. To solve this problem, a static function is declared and defined with the public access specifier inside the class without the instantiation of an object.

 

Code example 3

#include <iostream>
#include <string>
using String = std::string;

class X {
private:
	static String p_str;
public:
	static String str;
    // Static member function
    // It can be defined inside or outside the class
	static void access_function() {
		std::cout << p_str;
	}
};

String X::p_str = "Private static variable\n";
String X::str = "Public static variable\n";

int main() {
	std::cout << X::str;
	X::access_function();
}

Figure 2 Result of code example 3

The preceding example shows a static member function declared and defined with the public access specifier to access the private string variable. The program runs perfectly without any error.


 

2. Const members

2.1) const object

Const member functions are C++ member functions with the "const" keyword. Then why do we even need to declare const member functions in a class?. The reason is simple if you understand the main purpose of the "const" keyword. We use the keyword to prevent certain variables from being altered by other entities in a program.

 

In the same way, we can declare const objects so that they are not be altered during compilation or runtime. Once a const object is declared, no class members altering the value of the object are allowed. If they are, the compiler raises an error.

 

Code example 3

#include <iostream>
class X {
private:
	int pri_v = 0;
public:
	int pub_v = 0;
	X (int priv, int pubv) :
		pri_v(priv), pub_v(pubv)
	{}
	void print_v() {
		std::cout << "private variable = " << pri_v << std::endl;
		std::cout << "public variable = " << pub_v << std::endl;
	}
};

int main() {
	const X x1(10, 20);
	x1.pub_v = 50;
}

2.2) const member functions

Const objects are created to keep initial data and prevent them from being altered. The compiler, thus, does not allow to call class members that may modify the data to protect const objects. When it comes to this mechanism, the following example shows a very interesting result.

 

Code example 5

#include <iostream>
class X {
private:
	int pri_v = 0;
public:
	int pub_v = 0;
	X (int priv, int pubv) :
		pri_v(priv), pub_v(pubv)
	{}
	void print_v() {
		std::cout << "private variable = " << pri_v << std::endl;
		std::cout << "public variable = " << pub_v << std::endl;
	}
};

int main() {
	X x1(10, 20);
	x1.print_v();

	const X x2(30, 40);
	x2.print_v();
}

ERROR c2662 occurs as below,

error C2662: 'void X::func_x(void)': cannot convert 'this' pointer from 'const X' to 'X &'

To solve the error, there need to be a const function for the const object as below,

	void print_v2() const {
		std::cout << "private variable = " << pri_v << std::endl;
		std::cout << "public variable = " << pub_v << std::endl;
	}

Figure 3 result of code example 5

The preceding example clearly shows that the non-const object can call both non-const and const member functions; however, the const object is not allowed to call the non-const function. The non-const function we declared in the example does never change the values, nonetheless, we can not call it from the const object.

 

Consider this mechanism as a fail-safe of the compiler. Whether the non-const function modifies the values or not, we have to add the "const" keyword to the function in order to call it from the const object.


3. Static const members

Static const members are members with the "static" and "const" keywords at the same time. As we have studied before, static variables only belong to their original class, thus they are not copied to the objects of the class. const variables must be defined and initialized during the compilation and no modification of their values is allowed.

 

Static const variables, therefore, static and const simultaneously, in which their values are non-changeable and they only exist inside the original class. See the following example.

 

Code example 6

#include <iostream>
class X {
private:
	static const int pri_v = 10;
public:
	static const int pub_v = 20;
	static void print_v() {
		std::cout << "static const private int = " << pri_v << std::endl;
		std::cout << "static const public int = " << pub_v << std::endl;
	}
};

int main() {
	X::print_v();
}

Figure 4 Result of code example 6

Unlike static variables, static const variables can be defined inside a class, as they are constant. This is only allowed to "static const int". Other data types such as string, char, and double have to be defined outside the class.

 

Code example 7

#include <iostream>
#include <string>
class X {
private:
	static const int pri_i = 10;
public:
	static const int pub_i = 10;
	static const double pub_d;
	static const char pub_c[5];
	static const std::string pub_str;

	static void print_v() {
		std::cout << "static const private int = " << pri_i << std::endl;
		std::cout << "static const public int = " << pub_i << std::endl;
		std::cout << "static const public double = " << pub_d << std::endl;
		std::cout << "static const public char array = " << pub_c << std::endl;
		std::cout << "static const public string = " << pub_str << std::endl;
	}
};

const double X::pub_d = 1.5;
const char X::pub_c[5] = "Char";
const std::string X::pub_str = "String";

int main() {
	X::print_v();
}

Figure 5 Result of code example 6

 


4. REFERENCES

[1]https://en.cppreference.com/w/cpp/language/static

[2]https://en.cppreference.com/w/cpp/language/constant_initialization

[3]https://www.ibm.com/support/knowledgecenter/en/SSLTBW_2.2.0/com.ibm.zos.v2r2.cbclx01/cplr038.htm