Rebirth: I want to learn C++ on the fifth day

The main content of this article is the initialization list of the constructor and the simple application of operator overloading in the sequence table . Operator overloading implements stream insertion and stream extraction of custom types . I hope it will be helpful to everyone, like + bookmark + comment, support it!

Table of contents

Advanced understanding of constructor

 1. Definition of built-in type members in the parameter list

2. Definition of custom type members in the parameter list

3. Three major problems solved by the initialization list

(1) Reference member variables in the class

​edit

(2) const member variable

(3) Problems when custom type members do not have default constructors

Application of operator overloading

(1) Operator overloading in the sequence table

(2) Stream insertion and stream extraction of custom types


Advanced understanding of constructor

In the previous article, we have seen what the constructor does: initialize the object .

Note that the constructor only says to initialize the object, so there must be memory space allocated for the object before initialization, that is, the definition of member variables . When is the definition of member variables completed? That's the initializer list inside the constructor.

The syntax rules for initialization lists are given below :

Initialization list: Starts with a colon , followed by a comma-separated list of data members , each " member variable " followed by an initial value or expression enclosed in parentheses. The initialization list is where member variables are defined (allocated memory space), including custom types and built-in type members.
class A//类A
{
public:
    A()
    {
        cout<<"调用A的默认构造 A()"<<endl;
        _a=i;
    }
    A(int i)
	{
		cout << "调用A的带参构造 A(int)" << endl;
		_a = i;
	}
private:
    int _a;
};
class Date//类Date
{
public:
	Date(int year = 1, int month = 1, int day = 1)//构造函数
		:_year(year),//构造函数的初始化列表(为成员变量分配空间)
		_month(month),
		_day(day),
        a()
	{
		//构造函数函数体
	}
private:
                //成员变量的声明
	int _year;//内置类型成员
	int _month;
	int _day;
    A a;//自定义类型成员
};

The initialization list is indispensable for the constructor, and the compiler will add it by default even if you don't write it manually. Initializer lists added by default allocate space for built-in types, but do not specify values ​​(random values). The default constructor of the custom type is called on the member of the custom type.

public:
	Date(int year = 1, int month = 1, int day = 1)//构造函数
		/*:_year(),    //编译器默认添加,会为成员分配内存空间,是随机值
		_month(),
		_day(),
        a()*/            //对自定义类型会调用自定义类型的默认构造函数
	{
		
	}

 1. Definition of built-in type members in the parameter list

At this time, the constructor above does not manually add the initialization list, and an object is created at this time

Date d1;
d1.Print();

Print the built-in type member variables of d1.

 Is a random value, because the default initialization list only allocates memory space for built-in type member variables, and does not assign values ​​​​to member variables .

At this time, the assignment operation can be completed in the manually added initialization list, or in the function body.

(1). Complete the assignment in the manually added initialization list

Date(int year = 1, int month = 1, int day = 1)//构造函数
		:_year(year),
		_month(month),
		_day(day)
	{
		
	}
Date d1;
d1.Print();

operation result:

 (2). The assignment is completed in the function body

public:
	Date(int year = 1, int month = 1, int day = 1)//构造函数
	/*	:_year(),
		_month(),
		_day()*/  //默认参数列表
	{
		_year = year;
		_month = month;
		_day = day;
	}
Date d1;
d1.Print();

operation result:

Summary : The definition (allocation of memory space) of built-in type member variables can only be completed once in the initialization list. This process will occur regardless of whether it is written or not. Manual writing can be assigned at the time of definition. Not writing the compiler's default parameter list will define the member variable as a random value, and then assign the desired value again in the function body. 

2. Definition of custom type members in the parameter list

When we don't add the initialization list manually, the default initialization list will call the default constructor of the custom type member

For example: when the constructor is like this

Date(int year = 1, int month = 1, int day = 1)//构造函数
		//:_year(),//默认初始化列表
		//_month(),
		//_day(),
		//a()  默认构造函数的调用
	{
		//构造函数函数体
	}
Date d1;

operation result: 

 

 When we manually write the initialization list, we can selectively call the constructor of the custom type, which can be a parameterized or default constructor.

	Date(int year = 1, int month = 1, int day = 1)//构造函数
		:_year(year),//默认初始化列表
		_month(month),
		_day(day),
		a(2) //选择调用带参构造函数

at this time

	Date d1;

operation result 

 

 Summary : The default constructor automatically calls the default constructor of the custom type for the custom type. The essence is that the default initialization list of the default constructor calls the default constructor of the custom type . As long as the constructor uses the default initialization list, the default constructor will be called on the custom type. Conversely, by manually adding the initialization list, you can selectively call the constructor of the custom type.

3. Three major problems solved by the initialization list

(1) Reference member variables in the class

The reference must be initialized when it is defined, otherwise there will be a compilation error. For details, see Rebirth: I want to learn C++ the next day_Promise Taizu's Blog-CSDN Blog

The members in the class are all defined in the initialization list, if the member has a reference type, it must be initialized in the initialization list.

#include<iostream>
using namespace std;
class A
{
public :
	A(int a)
	{
		_a = a;//初始化
	}
private:
	int& _a;
};
int main()
{
	int tmp = 2;
	A a(tmp);
	return 0;
}

At this time, the definition of reference _a has been completed in the default initialization list, and the assignment initialization in the constructor function body will cause a compilation error (uninitialized at the definition).

Solution: Manually add the initialization list in the constructor, and define and initialize together in the initialization list.

A(int a)
:
_a(a)
{
	
}

(2) const member variable

Const member variables are prone to problems and the principle of reference is the same. All definitions must be initialized.

(3) Problems when custom type members do not have default constructors

We know that when the constructor does not write the initialization list, the default initialization list will call the default constructor of the custom type

Default constructor:

 For details, see: I want to learn C++ on the fourth day of rebirth - Programmer Sought

But if this custom type does not have a default constructor at this time, a compilation error will occur .

At this time, you must manually add the parameter list and selectively call the constructor of the custom type.

Application of operator overloading

On the fourth day, we learned about operator overloading. Here are two examples to let readers feel the charm of operator overloading!

(1) Operator overloading in the sequence table

First write a simple sequence table

#include<iostream>
using namespace std;
class Sequence
{
public:
	Sequence()
	{
		//初始化
		_a = (int*)malloc(4 * sizeof(int));
		_size = 0;
		_capcity = 4;
	}
	void Push(int x)
	{
		//检查容量:此处忽略
		
		_a[_size] = x;
		_size++;
	}
	void Print()
	{
		for (int i = 0; i < _size; i++)
		{
			cout << _a[i] << " ";
		}
	}
private:
	int* _a;
	int _size;
	int _capcity;
};
int main()
{
	Sequence s;//创建顺序表
	s.Push(1);//尾插三个数据
	s.Push(2);
	s.Push(3);
	//打印顺序表
	s.Print();
	return 0;
}

We can overload [ ] inside the class

int& operator[](int i)
{
	return _a[i];
}

At this point, the elements in the sequence table can be accessed like an array:

int main()
{
	Sequence s;//创建顺序表
	s.Push(1);//尾插三个数据
	s.Push(2);
	s.Push(3);

	//打印顺序表
	cout << s[0]<<s[1]<<s[2]<<endl;
	return 0;
}

After overloading [ ], the sequence table can be made more vivid, which greatly enhances the readability of the code. 

(2) Stream insertion and stream extraction of custom types

Take the Date class as an example

#include<iostream>
using namespace std;
class Date//类Date
{
public:
	Date(int year=1, 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;
};
int main()
{
	Date d1(1,1,2);
	d1.Print();
	return 0;
}

You can use the Print function to print the date

 But if the date can also be printed in this way, will it be pleasing to the eye?

cout<<d1<<endl;

Below we use operator overloading to realize this idea.

#include<iostream>
using namespace std;

class Date//类Date
{
public:
	friend ostream& operator<<(ostream& out, Date& d);//将此函数声明为类Date的友元函数
	Date(int year=1, 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;
};
ostream& operator<<(ostream& out, Date& d)
{
	out << d._year << "年" << d._month << "月" << d._day << "天";
	return out;
}
int main()
{
	Date d1(1, 1, 2);
	cout << d1;
	
	return 0;
}

 operation result:

 Here cout is an object of the ostream class, and the position of the cout object and the d object can be exchanged by writing the operator overload as a global function. Use friend functions to allow functions outside the class to access private members of the class. The next article will introduce friend functions.

That's all for today's sharing. If it is useful to everyone, I hope that programmers can support it three times and continue to share knowledge! Thanks!

Guess you like

Origin blog.csdn.net/2301_76144863/article/details/131977798