C++: Classes and Objects (Part 2) --- A deeper understanding of classes and objects

Constructor?

initialization list

The constructor has been introduced before, but it is not completely over. There are many ways to write the constructor, some with default parameters, some with default parameters, and some without default parameters... But using the previous method, it is all for the inside An assignment of member variables, that is, an initial value for each member variable in the class

But this is not initialization. Here we need to distinguish what is initialization and what is initial value assignment.
Simply put, one of the differences between them is that initialization can only be initialized once, but assignment can be assigned multiple times.

Therefore, the concept of initialization list is introduced in the constructor. The initialization list can initialize the member functions in the class. Write a specific example below to show

#include <iostream>
using namespace std;

class Date
{
    
    
public:
	Date(int year = 1900, int month = 1, int day = 1)
		: _year(year)
		, _month(month)
		, _day(day){
    
    }
	void Print()
	{
    
    
		cout << _year << "/" << _month << "/" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};

The above is an overview of the initialization list, through which the parameters can be initialized

Here is the difference between initialization and assignment:

  1. If initialization is used, each member variable can only be initialized once in the initialization list
  2. If there are reference member functions, const member variables and custom members in the class and there is no default constructor, they must be written in the initialization list
  3. Try to use the initialization list for initialization. Regardless of whether the initialization list is used or not, the member variables of the custom type will be initialized with the initialization list first.
  4. The order in which member variables are declared in the class is the order in which they are initialized in the initialization list, regardless of their order in the initialization list

Let's interpret the second article, and at the same time, we can better understand the above principles

  1. There are const member variables
#include <iostream>
using namespace std;

class Date
{
    
    
public:
	//Date(int year = 1900, int month = 1, int day = 1)
	//	: _year(year)
	//	, _month(month)
	//	, _day(day){}
	Date(int year = 1900, int month = 1, int day = 1, int tmp = 1)
	{
    
    
		_year = year;
		_month = month;
		_day = day;
		_tmp = tmp;
	}
	void Print()
	{
    
    
		cout << _year << "/" << _month << "/" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
	const int _tmp;
};

Is the constructor right here? Obviously, it cannot be compiled, and the reason is very simple. The _tmp here is a variable modified by const. How can it be assigned a value? There are two solutions. The first one is to give it a value when it is declared. This is possible, but using the initialization list can perfectly solve this problem.

#include <iostream>
using namespace std;

class Date
{
    
    
public:
	Date(int year = 1900, int month = 1, int day = 1, int tmp = 1)
		: _year(year)
		, _month(month)
		, _day(day)
		, _tmp(tmp) {
    
    }
	//Date(int year = 1900, int month = 1, int day = 1, int tmp = 1)
	//{
    
    
	//	_year = year;
	//	_month = month;
	//	_day = day;
	//	//_tmp = tmp;
	//}
	void Print()
	{
    
    
		cout << _year << "/" << _month << "/" << _day << endl;
		cout << "const tmp  " << _tmp << endl;;
	}
private:
	int _year;
	int _month;
	int _day;
	const int _tmp = 1;
};

Here you can better understand the difference between assignment and initialization, which can be well reflected from const

  1. quote

There is another big usage scenario that can be reflected in the reference, so I won’t write wrong demonstrations here

class Date
{
    
    
public:
	Date(int year = 1900, int month = 1, int day = 1, int tmp = 1)
		: _year(year)
		, _month(month)
		, _day(day)
		, _tmp(tmp) {
    
    }

	//Date(int year = 1900, int month = 1, int day = 1, int tmp = 1)
	//{
    
    
	//	_year = year;
	//	_month = month;
	//	_day = day;
	//	//_tmp = tmp;
	//}
	void Print()
	{
    
    
		cout << _year << "/" << _month << "/" << _day << endl;
		cout << "const tmp  " << _tmp << endl;;
	}
private:
	int _year;
	int _month;
	int _day;
	int& _tmp;
};

explicit keyword

C++ provides the keyword explicit, which can prevent the occurrence of implicit conversions that should not be allowed through conversion constructors, and constructors declared as explicit cannot be used in implicit conversions

Before understanding explicit, you must first know what implicit conversion is. Explicit conversion
must be familiar, it is forced conversion, so implicit conversion is automatic conversion by the compiler.
For example, the following example:

int main()
{
    
    
	int i = 0;
	double d = 1.2;
	int& p = d;
	return 0;
}

The compilation here cannot pass. The reason is that the compilation fails because d is of double type? actually not

insert image description here
In the processing of the compiler, Mr. d will be converted into a temporary variable and then assigned, and we all know that temporary variables are constant, so here we cannot hand over a constant attribute number to the reference for processing

Therefore, you only need to add const here to reduce the permissions, and you can use constant references to accept constant variables

const int& p = d;

In fact, converting the variable d from double type to int type in the above process is an implicit type conversion. We did not perform the conversion, but the compiler still converted it by itself, and generated a temporary variable that failed to guide the assignment.

The existence of explicit means that implicit conversion cannot exist, so we can't limit the type to int and double types, and we need to add the type of class

class A
{
    
    
public:
	A(int a = 10) :_a(a) {
    
    }
private:
	int _a;
};

int main()
{
    
    
	A a;
	a = 2;
	return 0;
}

See what happened to the code above? Assigned 2 to a class? If you know the implicit type conversion, it is not difficult to understand this code, which is to convert 2 into class A, the value of the member variable _a is 2, and then perform one assignment

Then explicit can come on stage, add explicit in front of the initialization list:

class A
{
    
    
public:
	explicit A(int a = 10) :_a(a) {
    
    }
private:
	int _a;
};

int main()
{
    
    
	A a;
	a = 2;
	return 0;
}

At this point, the implicit conversion does not exist, so the assignment here no longer exists, because 2 is really a number 2 here

anonymous object

The concept of anonymous objects is introduced in C++, which is simply an object without a name.

class A
{
    
    
public:
	explicit A(int a = 10) :_a(a) {
    
    }
private:
	int _a;
};

int main()
{
    
    
	A(2);
	return 0;
}

It seems strange here, but it can be passed. C++ allows this internally. The difference between it and the named object is that the life
cycle of the anonymous object is only in this line, and it will be destructed after the end, while the normally generated The object needs to be destructed after the main function ends, and the life cycle of the ordinary generated object is its local domain

What is the use of anonymous objects?

Suppose there is such a scenario

class A
{
    
    
public:
	explicit A(int a = 10) :_a(a) {
    
    }
	void Print()
	{
    
    
		cout << "Print" << endl;
	}
private:
	int _a;
};

int main()
{
    
    
	A a1;
	a1.Print();
	A().Print(); // 匿名对象
	return 0;
}

If here I only need to call the member function print in the class, but normally I need to create an object, and then use the object to refer to the member function in this class, which is very cumbersome. If I use an anonymous object, I don’t Pay attention to who this object is and how much this object is. I only care about whether I can refer to member functions in the class, so I can use it like this. Compared with the method of defining objects, the life cycle of such methods is shorter

Guess you like

Origin blog.csdn.net/qq_73899585/article/details/131987909