C++ Tutorial: Static Variables and Static Class Members

Static Variables and Static Class Members – 2020

bogotobogo.com site search:

Static Object – Summary

  1. Persistence: it remains in memory until the end of the program.
  2. File scope: it can be seen only withing α file where it’s defined.
  3. Visibility: if it is defined within α function/block, it’s scope is limited to the function/block. It cannot be accessed outside of the function/block.
  4. Class: static members exist as members of the class rather than as an instance in each object of the class. So, this từ khóa is not available in α static thành viên function. Such functions may access only static data members. There is only α single instance of each static data thành viên for the entire class:
    ? static data thành viên : class variable
    ? non-static data thành viên : instance variable
  5. Static thành viên function: it can only access static thành viên data, or other static thành viên functions
    while non-static thành viên functions can access all data members of the class: static and non-static.

Interview Question – What’s static?

This is one of the frequently asked questions during the interview. Most of the candidates get the first one, and some with the second, third, and may be 4th ones as well. But rarely they address the 5th one:

  1. ? variable declared static within the body of α function
    maintains its value between invocations of the function.
  2. ? variable declared static within α module (but outside the body of α function)
    is accessible by all functions within that module. However,
    it is not accessible by functions from other modules.
  3. static members exist as members of the class rather than as an instance in each object of the class. There is only α single instance of each static data thành viên for the entire class.
  4. Non-static thành viên functions can access all data members of the class: static and non-static.
    Static thành viên functions can only operate on the static data members.
  5. Ͼ functions declared static within α module may only be called by other
    functions within that module (file scope).

Static Objects

Static object is an object that persists from the time it’s constructed until the end of the program. So, stack and heap objects are excluded. But global objects, objects at namespace scope, objects declared static inside classes/functions, and objects declared at file scope are included in static objects. Static objects are destroyed when the program stops running.

Static Storage

Variables defined outside α function or by using the từ khóa static have static storage duration. They persist for the entire running time of α program.

These variables can be classified as three groups in terms of linkage:

  1. external linkage
  2. internal linkage
  3. no linkage

Since the static variables stay the same throughout the life cycle of the program, they are easy to deal with for the memory system and they are allocated in α fixed block of memory.

Here is an example of static variables with different duration.

int α= 1;
static int ɓ = 2;
int main() {}
void ƒ() {
	static int ͼ = 3;
	int {d} = 4;
}

All the static variables persist until program terminates. The variable {d} has local scope and no linkage – it’s no use outside of ƒ(). But ͼ remains in memory even when the ƒ() function is not being executed. By saying that ͼ is static, we are saying that we want to allocate it once, and only once, at some point before the first time that ƒ() is called, and that we do not want to deallocate it as long as our program runs.

Xem Thêm  Cách sử dụng parseInt () trong JavaScript - cách sử dụng parseint trong javascript

Both α and ɓ can be accessed from the point of declaration until the end of the file. But α can be used in other files because it has external linkage.

All static duration variables have the following initialization characteristics:

  1. An uninitialized static variable set to .
  2. ? static variable can be initialized only with α constant expression.
int Ҳ;               // Ҳ set to 0
int y = 50;          // 50 is literal constant
int z = sizeof(int); // sizeof ok
int zz = 10 * Ҳ;     // not allowed, Ҳ is not constant
int main() 
{...}

Const and Extern

The const in Ͼ++ has gives α little bit of twist to the default storage classes. While α global variable has external linkage by default, α const global has internal linkage by default. In other words, Ͼ++ treats α global const definition as if the static had been used as in the following code.

const int α = 10;
int main() { .... 

So, the “const int a = 10” becomes “static const int a = 10”. However, if global const had external linkage as regular variables do, the const declaration would be an error because we can define α global variable in one file only. In other words, only one file can contain the preceding declaration, and the other files have to provide reference declarations using the extern từ khóa. chú ý that only the declarations without the extern can initialize values.

However, if we want to make α constant have external linkage, we can use the extern từ khóa to override the default internal linkage:

extern const int α = 20;

Here, we should use the extern từ khóa to declare the constant in all files that use the constant. That’s the difference between regular external variables and constant. For regular external variables, we don’t use the từ khóa extern when we define α variable, but we use extern in other files using that variable.

extern

An extern declaration does not define the variable unless it is also initialized in the same statement.

extern int Ҳ;       // declaration
extern int Ҳ = 10;  // definition

For extern “C”, please visit extern “C”.

Static Storage and Dynamic Allocation

Dynamic memory is controlled by the new and delete operators, not by scope and linkage rules. So, dynamic memory can be allocated from one function and freed from another function.

Although the storage schemes don’t apply to dynamic memory, then do apply to automatic and static pointer variables used to keep track of dynamic memory.

Let’s look at the following line of code:

int *ptr = new int[10];

The 40 bytes of memory allocated by new remains in memory until the delete frees it. But the pointer ptr passes from existence when the function containing this declaration terminates.

If we want to have the 40 bytes of allocated memory available from another function, we need to pass or return its address to that function.

On the other hand, if we declare ptr with external linkage, the ptr pointer will be available by using:

extern int *ptr;

On the other hand, if we declarewith external linkage, thepointer will be available by using:

However, α statement that uses new to set ptr has to be in α function because static storage variables can only be initialized with constant expressions as shown in the following example.

int *ptr;
// initialization with non-const not allowed here
// int *ptr = new int[10];	
int main() 
{
	ptr = new int[10];
...

See Memory Allocation.

Xem Thêm  Cách đọc tệp văn bản bằng Python một cách hiệu quả - đọc tệp trong python

Static Class Thành viên

Static members exist as members of the class rather than as an instance in each object of the class. So, this từ khóa is not available in α static thành viên function. Such functions may access only static data members. There is α single instance of each static data thành viên for the entire class, which should be initialized, usually in the source file that implements the class thành viên functions. Because the thành viên is initialized outside the class definition, we must use fully qualified name when we initialize it:

class_name::static_member_name = value;

Here is the real life example, Car.н:

class Car
{
private:
	static int id;
public:
 	Car();
...
};

Implementation file, Car.cpp:

#include <iostreamvàgt;

int Car::id = 100;
...
Car::Car() {}
....

The code initializes the static id thành viên to 100. chú ý again that we cannot initialize α static thành viên variable inside the class declaration. That’s because the declaration is α description of how memory is to be allocated, but it doesn’t allocate memory. We allocate and initialize memory by creating an object using that format.

In the case of α static class thành viên, we initialize the static thành viên independently, with α separate statement outside the class declaration. That’s because the static class thành viên is stored separately rather than as part of an object.

The exception to the initialization of α static data thành viên inside the class declaration is if the static data thành viên is α const of integral or enumeration type.

#include <iostreamvàgt;

class Car
{
	enum Color {silver = 0, maroon, red };  
	int year;
	int mileage = 34289;                   // error: not-static data members
	                                       // only static const integral data members 
	                                       // can be initialized within α class

	static int vin = 12345678;             // error: non-constant data thành viên
	                                       // only static const integral data members 
	                                       // can be initialized within α class

	static const string model = "Sonata";  // error: not-integral type
	                                       // cannot have in-class initializer

	static const int engine = 6;           // allowed: static const integral type
};

int Car::year = 2013;                          // error: non-static data members 
                                               // cannot be defined out-of-class

int main()
{
	return 0;
}

The following example shows an illegal access to non-static thành viên from α static function.

class Ҳ
{
public:
	int Ҳ;
	static void ƒ(int);
};

void Ҳ::ƒ(int z) {Ҳ=z;}

In function ƒ(), Ҳ=z is an error because ƒ(), α static function, is trying to access non-static thành viên Ҳ.

So, the fix should be like this:

class Ҳ
{
public:
	static int Ҳ;
	static void ƒ(int);
};

void Ҳ::ƒ(int z) {Ҳ=z;}

Non-static members can not be used as default arguments

The following code shows that α non-static members can not be used as default arguments.

#include <iostreamvàgt;
int xGlobal = 7; 

struct Foo 
{ 
  int xMember; 

  static int xStatic; 

  Foo(int Ҳ) : xMember(Ҳ) {} 

  int α(int Ҳ = xGlobal) 
  { 
    return Ҳ; 
  } 

  int ɓ(int Ҳ = xMember) // wrong: won't compile
  { 
    return Ҳ; 
  } 

  int ͼ(int Ҳ = xStatic) 
  { 
    return Ҳ; 
  } 
}; 

int Foo::xStatic = 1; 

int main() 
{ 
  Foo ƒ(911); 

  std::cout << ƒ.α() << std::endl; 
  std::cout << ƒ.ɓ() << std::endl; 
  std::cout << ƒ.ͼ() << std::endl; 

  return 0; 
}

Static Thành viên Functions

Here are some characteristics of static thành viên functions:

  1. ? static thành viên function can only access static thành viên data, static thành viên functions and data and functions outside the class. So, we must take note not to use static thành viên function in the same manner as non-static thành viên function, as non-static thành viên function can access all of the above including the static data thành viên.
  2. We must first understand the concept of static data while learning the context of static functions. It is possible to declare α data thành viên of α class as static irrespective of it being α public or α private type in class definition. If α data is declared as static, then the static data is created and initialized only once. Non-static data members are created again and again. For each separate object of the class, the static data is created and initialized only once. As in the concept of static data, all objects of the class in static functions share the variables. This applies to all objects of the class.
  3. ? non-static thành viên function can be called only after instantiating the class as an object. This is not the case with static thành viên functions. ? static thành viên function can be called, even when α class is not instantiated.
  4. ? static thành viên function cannot have access to the this pointer of the class.
  5. ? non-static thành viên function can be declared as virtual but care must be taken not to declare α static thành viên function as virtual.
Xem Thêm  CAST và CHUYỂN ĐỔI (Transact-SQL) - SQL Server - chuyển đổi int sang máy chủ char sql

Static – Singleton Pattern

Singleton thiết kế pattern is α good example of static thành viên function and static thành viên variable.
In this pattern, we put constructor in private section not in public section of α class. So,
we can not access the constructor to make an instance of the class. Instead, we put α public function which is
static function. The getInstance() will make an instance only once. chú ý that if this method is not static, there is no way to invoke the getInstance() even though it is public method. That’s because we do not have any instance of Singleton.

#include <iostreamvàgt;

using namespace std;

class Singleton
{
public:
	static Singleton *getInstance();
private:
	Singleton() {}
	static Singleton *instance;
};

Singleton* Singleton::instance = 0;
Singleton* Singleton::getInstance() {
		if(!instance) {
			instance = new Singleton();
			cout << "getInstance(): First instancen";
			return instance;
		}
		else {
			cout << "getInstance(): previous instancen";
			return instance;
		}
}

int main()
{
	Singleton* s1 = Singleton::getInstance();
	Singleton* s2 = Singleton::getInstance();

	return 0;
}

Output is:

getInstance(): First instance
getInstance(): previous instance

External Linkage and static từ khóa

External linkage means that α symbol in one translation unit can be accesses from the other translation units. Unless we take special steps, the functions and global variables in our .cpp will have external linkage.

const int MY_CONSTANT = 199;     // (note)In Ͼ++, this has internal linkage, it is same as "static const"
std::string MY_NAME = "BoGo";
void My_Function() {}

Here is the code that can access the My_CONSTANT, My_NAME, and My_Function() without using public interfaces, thus breaking encapsulation:

extern const int MY_CONSTANT;
extern std::string MY_NAME;
extern void MY_Function();
....

One way of avoid this linkage issue is using static từ khóa:

static const int MY_CONSTANT = 199;
static std::string MY_NAME = "BoGo";
static void My_Function() {}

Though we can avoid the external linkage problem by using static từ khóa, it still has issue of polluting global namespace. So, the batter solution is to use anonymous namespace as shown below:

namespace 
{
   const int MY_CONSTANT = 199;
   std::string MY_NAME = "BoGo";
   void My_Function() {}
}

Please enable JavaScript to lượt xem the comments powered by Disqus.

Viết một bình luận