c++ initialization list and static members


1. Initialization list

There are two ways for a class to assign values ​​​​to member variables

  • Assignment in function body
  • Initialization list
    The assignment in the function body is to assign a value directly in the constructor, and the initialization list is a special way! The initialization list
    starts after the constructor () :, followed by the variable to be initialized, and then followed by (), the value or expression in the brackets is the initialization of this variable! Then use ,as a split, and then you can assign values ​​​​to member variables or not, if not, you don’t need to use commas to split!
    As follows:
    insert image description here
    Why come out the initialization list? Isn't assignment in the body of a function bad?

Because there are cases where only initialization lists can be done!
Such as: reference, const modified, custom type (no default constructor)

Both references and const must be initialized and assigned when they are defined!
insert image description here
And the const modified is not initialized when it is defined, then it cannot be changed, it is just a random value!
The class object member variable is not defined in the class. The class only declares it. The real definition is after the object is defined. The object calls its constructor to define it in its initialization list, and these are not in the constructor. The definition in the function body, the assignment in the function hall is just to assign a value to it again! For example: when there is a custom type in the member variable, it is said that it will automatically call the constructor of the custom type, but this is based on the premise that its constructor is the default construction, otherwise it will not work! The call of the custom type member is done in the initialization list!
Members are references, const modifications, custom types

class stack
{
    
    
public:
	stack(int capacity)
	{
    
    
		_a = (int*)malloc(sizeof(int) * capacity);
		if (_a == nullptr)
		{
    
    
			perror("malloc fail\n");
			exit(-1);
		}

		_top = 0;
		_capacity = capacity;
	}

private:
	int* _a;
	int _top;
	int _capacity;
};

class B
{
    
    
public:
	B(int& a,int b = 2)
		:_a(a)
		,_b(b)
		,_st(10)
	{
    
    
	}

private:
	int& _a;
	const int _b;
	stack _st;

};

insert image description here
And it cannot be written in the function body, only in the initialization list!
insert image description here
The definition of class member variables is defined in the initialization list, he is only declared in the class, all these three types can only be written in the initialization list!
And when it is not written out in the initialization list, it is actually defined! I didn't assign a value to it in the function body, so every time I assign a value to it, its value is a random value!
insert image description here
When the initialization list is not written, in fact, they still have to go through the initialization list to complete the definition!
Since initialization is so magical, why not just use the initialization list in the first place?
Because the initialization list cannot complete all the work, sometimes it needs to be checked after the assignment is completed, or the space is
initialized by assignment!
like:

class BB
{
    
    
public:
	BB(int capacity=4)
		:_a((int*)malloc(sizeof(int)* capacity))
		,_top(0)
		,_capacity(capacity)
	{
    
    
		if (_a == nullptr)
		{
    
    
			perror("malloc fail\n");
			exit(-1);
		}

		memset(_a, 0, sizeof(int) * _capacity);
	}

private:
	int* _a;
	int _top;
	int _capacity;
};

In this code, it is not enough to complete the initialization in the initialization list. It is also necessary to check whether the space opened by _a is successful. At this time, it cannot be completed in the initialization list and needs to be completed in the function body!

Another thing is to dynamically open up a two-dimensional array, but the initialization list cannot be completed, and it needs to be completed in the function body!

class AA
{
    
    
public:
	AA(int row=10,int col = 5)
	{
    
    
		_a = (int**)malloc(sizeof(int*) * row);
		if (_a == nullptr)
		{
    
    
			perror("malloc fail\n");
			exit(-1);
		}
		for (int i = 0; i < row; i++)
		{
    
    
			_a[i] = (int*)malloc(sizeof(int) * col);
			if (_a[i] == nullptr)
			{
    
    
				perror("malloc fail\n");
				exit(-1);
			}
		}
	}

private:
	int** _a;
};

To dynamically open up a two-dimensional array is to open up the rows first, and then open up the number of columns in each row. This cannot be done in the initialization list! It needs to be done in the function body! Let's put it this way, the initialization list can do 95% of the things but the remaining 5% needs to be done in the function body!
The initialization order of the initialization list should be consistent with the declaration.
When the initialization list initializes the declared member variables, it is initialized in the order of declaration! All in the initialization list, it is recommended that the initialization order is consistent with the declaration order!

class C
{
    
    
public:
	C(int a)
		:_a(a)
		,_b(_a)
	{
    
    }

	void Print()
	{
    
    
		cout << _a << " " << _b << endl;
	}

private:
	int _b;
	int  _a;
	
};

int main()
{
    
    
	C c(1);
	c.Print();
	return 0;
}

This program is not consistent, and the results of its operation are as follows:
insert image description here

2. Static members

Let’s look at a scenario first. The requirement of the scenario is to count how many objects are created by a class. In fact, how many objects are created. After the object is created, the rescue calls the construction once, so you can define a global variable cnt to count, and then ++ in the constructor, ++ is also required in copy construction, because sometimes an object that already exists is initialized with another object that does not exist!
How many objects are created by the global variable statistics class

int cnt = 0;
class Count
{
    
    
public:
	Count()
	{
    
    
		cnt++;
	}

	~Count()
	{
    
    
		cnt--;
	}
	
};

Count c1;

void fun()
{
    
    
	Count c2;
	cout << __LINE__ << " " << cnt << endl;
	
}

int main()
{
    
    
	cout << __LINE__ << " "<<cnt << endl;

	Count c;
	cout << __LINE__ << " " << cnt << endl;
	fun();
	cout << __LINE__ << " " << cnt << endl;
	
	return 0;
}

insert image description here
Among them, __LINE__ is to display the file line
, but this global variable is defined, and it can be modified anywhere! This is not safe. In order not to modify it, encapsulate it into a class and make it a class member variable!
But it should be different from ordinary member variables, make it a static member variable! Add static in front
, so what is the difference between ordinary member variables and static member variables?

Ordinary member variable: belongs to each class object and is stored in the class object
Static member variable: belongs to the class, belongs to each class share, and is stored in the static area! It is not defined in the initialization list, because it is stored in the static area, define it outside the class!

But in this way it is a private member variable and cannot be accessed. To access it, you can make it a public member variable or write a public function to get it! This member function can also be set as a static member function! A static member function has no this pointer, it cannot access non-static member variables or non-static member functions!
How many objects are created by the static member statistics class

class Count
{
    
    
public:
	Count()
	{
    
    
		cnt++;
	}

	~Count()
	{
    
    
		cnt--;
	}
	static int Getcnt()
	{
    
    
		return cnt;
	}
private:
	static int cnt;
};

int Count::cnt = 0;
Count c1;

void fun()
{
    
    
	Count c2;
	cout << __LINE__ <<" "<< Count::Getcnt() << endl;
}

int main()
{
    
    
	cout << __LINE__ << " " << Count::Getcnt() << endl;

	Count c;
	cout << __LINE__ << " " << Count::Getcnt() << endl;

	fun();
	cout << __LINE__ << " " << Count::Getcnt() << endl;
	return 0;
}

It's just that after making it a static member function, the non-static member function in the class cannot be called in this function body, and the non-static member variable in the class cannot be accessed! Because there is no this pointer! But non-static member functions can call static member functions and access static member variables!
Everything defined by static modification is stored in the static area, and its definition is defined outside the class!

Guess you like

Origin blog.csdn.net/m0_67768006/article/details/131403089