C++: Class constructor and destructor

Table of contents

I. Introduction

2. Class constructor

1. Basic concepts and grammatical rules of constructors

2. The no-argument constructor and custom constructor generated by the compiler by default 

3. The characteristics of the constructor (overloadable)

4. Notes on constructors

5. Application examples of constructors:

3. The copy constructor of the class

1. Basic concept of copy constructor

2. The copy constructor and custom copy constructor generated by the compiler by default 

3. Applicable situations of the copy constructor generated by the compiler by default and the custom copy constructor

4. Typical scenarios where the copy constructor is called

5. A trap when using constructors

4. Class destructor

1. Basic concepts and grammatical rules of destructors

2. The destructor and custom destructor generated by the compiler by default

3. Application scenario of destructor


Knowledge Architecture:

 

I. Introduction

The class has six default member functions. Even if we don't define these six default member functions , the compiler will add these functions to the class during the compilation phase .

The six default member functions of the class:

This article mainly discusses the class constructor, copy constructor and destructor.

2. Class constructor

1. Basic concepts and grammatical rules of constructors

(1) The constructor is a special member function whose identification name is the same as the class name.

(2) The constructor can be customized (the function name must be a class name), or it can be generated by the compiler by default (the compiler will no longer generate it after user-defined)

(3) The constructor of the class has no return value (and no need to indicate the return value)

(4) The constructor is called by the compiler ( the user cannot call it by itself ). When we use the defined class type to create a class object instance , the compiler will automatically call the constructor of the class.

(5) The constructor is only called once during the entire life cycle of the class object instance .

(6) Class constructors are generally used to initialize class member variables .

2. The no-argument constructor and custom constructor generated by the compiler by default 

The no-argument constructor generated by the compiler by default:

code snippet:

class indate
{
private:
    int i;
    int j;
};


class Date
{
public:

	
private:
	int _day;
	int _month;
	int _year;
    indate _subclass;       类类型成员变量
};

int main()
{
   Date a;                 创建类对象实例时编译器自动调用构造函数(无参构造函数)
   return 0;
}

Notice:

(1) We can think that there is a member function called Date in the Date class, and a member function called indate in the indate class.

(2) Since we did not explicitly customize the Date function in the Date class of the source code , the compiler will automatically add a no-argument constructor (Date()) generated by the compiler to the Date class during the compilation phase (for indate class as well).

(3) The Date a; statement in the main function of the above code segment is executed, and the no-argument constructor generated by the compiler by default will be called.


The following points need to be noted for the parameterless constructor generated by the compiler by default :

(1). The parameterless constructor generated by the compiler by default will not do any processing on the built-in type member variables of the class object instance (such as the above-mentioned _day, _month, _year members)

(2). The no-argument constructor generated by the compiler by default will call the no-argument constructor of its class type member variable (here it is emphasized that the object member of this class must have a no-argument constructor) (such as the constructor of Date a in the above code segment Date() will call the no-argument constructor of its member class indate _subclass)


Custom constructor:

(1) If we have special requirements for the function of the class constructor (generally initialize member variables), we can also customize the constructor (the constructor function name must be the same as the class name)

(2) Once the user defines the constructor, the compiler will no longer generate another constructor (the copy constructor will be discussed separately)

for example:

#include <iostream>
#include <time.h>
#include <string>
#include <map>

using std::cout;
using std::endl;

class Date
{
public:
	Date(int day, int month, int year)     Date就是类的自定义构造函数
	{
		_day = day;
		_month = month;
		_year = year;
		cout << "initclass success" << endl;
	}
	
private:
	int _day;
	int _month;
	int _year;
};


int main()
{ 
	Date a(1, 2, 3);                      编译器自动调用构造函数(带参构造函数)
	return 0;
}

Notice:

(1) If there is only a constructor with parameters in the class , when creating a class object instance, add the actual parameter list to the object creation statement as shown in the figure above .

(2) If there are class object members in the created class object , the compiler will add the call instruction of the constructor of the class object member to the custom constructor of the class

for example:

This can be observed with the assembly instruction:

3. The characteristics of the constructor (overloadable)

Constructors can be overloaded (very important) :

See function overloading: http://t.csdn.cn/KcgeK

for example:

using std::cout;
using std::endl;

class Date
{
public:
    Date()
    {
        ;
    }
	Date(int flag)                      自定义构造函数重载
	{
		cout << "reload one" << endl;
	}

	Date(int day, int month, int year)
	{
		_day = day;
		_month = month;
		_year = year;
		cout << "reload two" << endl;
	}
	
private:
	int _day;
	int _month;
	int _year;
};


int main()
{
	Date a(1,2,3);
	Date b(1);
	return 0;
}

When a class object instance is created, which overload of the constructor is called depends on the way we pass parameters when creating the class object.

4. Notes on constructors

1.  No-argument constructors and all-default constructors. Constructors that can be called without arguments can only have one overload in the class definition .

About default parameters: http://t.csdn.cn/XubVT

for example:

2. When customizing the constructor , it is necessary to define an overloaded function that can be called without parameters , otherwise the following situations may occur: 

The following situations may also occur:

That is to say, when a class object is created as a member of another class, its no-argument constructor must be called 

5. Application examples of constructors:

In the actual scenario of using two stacks to implement a queue, the constructor of the class can play an obvious role

栈对象的类

class stack
{
    stack()                        自定义一个stack的构造函数来初始化维护栈的指针
    {
        _data=nullptr;
        _capacity=0;
        _nums=0;
    }
public:
    void stackinit(int capacity=4); 栈对象方法(函数体省略)   
    void stackpush();
    void stackcheck();
    int& stacktop();
    void stackdestroy();
private:
    int* _data;
    int _capacity;
    int _nums;

};

队列对象的类

class Queen
{
    stack _pushST;                   栈对象成员变量
    stack _popST;

};

int main ()
{
    Queen myqueen;
    return 0;
}



In this example, the constructor can not only simplify the source code, but also avoid the situation of forgetting to initialize the stack object pointer.

3. The copy constructor of the class

1. Basic concept of copy constructor

The copy constructor of a class is essentially a special overloaded function of the class's constructor , and its formal parameter table has only a single formal parameter (the formal parameter table is a sign to distinguish overloading) , and this formal parameter is a reference to the type object of this class (Generally used const modification).

About references: http://t.csdn.cn/oVhTv
(1) The relationship between the copy constructor of a class and the constructor of a class:

(2) When we do not have an explicit copy constructor of a custom class ( even if other overloaded constructors are defined ), the compiler will automatically generate the compiler's default copy constructor during the compilation phase.

(3) The copy constructor can be customized (the function name must be a class name, there is only one parameter in the formal parameter table and must be a reference to an object of this class type ), once the user defines the copy constructor, the compiler will not Automatically generated again .

(4 ) The copy constructor of a class is used when initializing a new class object with an existing class object . Its function is to copy the content of an object to another newly created object

When a class object instance is created, which overload of the constructor is called depends on the way we pass parameters when creating the class object.

for example:

It can be considered that the compiler automatically adds a function declared as Date(const Date& object) to the Date class

2. The copy constructor and custom copy constructor generated by the compiler by default 

The copy constructor generated by the compiler by default:

The function of the copy constructor generated by the compiler by default is: for the built-in type member variable , copy the member variable of the reference object (actual parameter) byte by byte to the newly created object of the same type ; for the class type member variable , call The member's own copy constructor to complete the copy . This type of copying is called shallow copying.

for example:

If there are class type member variables in the class object , such as:

Custom copy constructor:

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

    Date(const Date& d)                  自定义拷贝构造函数
    {
        _year = d._year;
        _month = d._month;
        _day = d._day;
    }
private:
    int _year;
    int _month;
    int _day;
};

int main()
{
    Date d1;
    Date d2(d1);
    return 0;
}

3. Applicable situations of the copy constructor generated by the compiler by default and the custom copy constructor

In some cases, it is convenient to use the copy constructor that the compiler generates by default .

But in some other cases, you cannot use the copy constructor generated by the compiler by default , for example: use a stack object to initialize another stack object.

The copy constructor generated by the compiler by default copies objects in a shallow copy method of copying member variables byte by byte , and the stack object will apply for space on the memory heap area . In the above case, object b and object a will both maintain the same block Heap memory space

It is very dangerous for two stack objects to maintain the same heap memory space, and it is easy to make bugs 

Therefore, the class object calls other memory resources , and the copy constructor generated by the compiler by default is not applicable. At this time, only a custom copy constructor can be considered. (The user designs a deep copy to complete the copy construction of the object)

4. Typical scenarios where the copy constructor is called

(1) When using an existing object to create a new object
(2) When the function parameter type called is a class type object
(3) When the function return value type is a class type object

class Date
{
public:
    Date(int year, int minute, int day)
    {
        cout << "Date(int,int,int):" << this << endl;
    }
    Date(const Date& d)
    {
        cout << "Date(const Date& d):" << this << endl;
    }
    ~Date()
    {
        cout << "~Date():" << this << endl;
    }
private:
    int _year;
    int _month;
    int _day;
};



Date Test(Date d)
{
    Date temp(d);
    return temp;
}
int main()
{
    Date d1(2022,1,13);
    Test(d1);
    return 0;
}

5. A trap when using constructors

When customizing the constructor, the type variable of the class itself cannot be used as the formal parameter of the constructor

for example:

In the above code segment, after creating the d1 object, use d1 to initialize d2, but the constructor parameter of Date is also a Date object. When calling the function, it needs to open up memory space for the function parameter on the stack area , which is equivalent to creating another Date object , at this time, will call the copy constructor of the formal parameter object, and so on, forming dead recursion.

4. Class destructor

1. Basic concepts and grammatical rules of destructors

(1) The destructor is a special member function whose identification name is: ~ + class name .

(2) The destructor can be customized (the function name must be ~ + class name ), or it can be generated by the compiler by default (the compiler will no longer generate it after user-defined)

(3) The destructor of the class has no return value (and there is no need to indicate the return value)

(4) The destructor is called by the compiler at the end of the life cycle of the class object ( users can also call it explicitly )

(5) The destructor of a class is generally used to clean up the memory of class member variables.

Destructors cannot be overloaded! ! ! ! ! ! ! !

2. The destructor and custom destructor generated by the compiler by default

The destructor generated by the compiler by default:

No processing will be done for the built-in type member variables of the class object , and the destructor of the member itself will be called for the class type member variables of the class object .

for example:

 

Custom destructors and reference scenarios for destructors:

You can observe the calling process of the custom destructor through assembly:

 3. Application scenario of destructor

typedef int DataType;
class Stack
{
public:
	Stack(size_t capacity = 3)
	{
		_array = (DataType*)malloc(sizeof(DataType) * capacity);  为栈数据申请堆区空间
		if (NULL == _array)
		{
			perror("malloc申请空间失败!!!");
			return;
		}
		_capacity = capacity;
		_size = 0;
	}
	void Push(DataType data)
	{
		// CheckCapacity();
		_array[_size] = data;
		_size++;
	}

	~Stack()                            自定义析构函数
	{
		if (_array)             
		{
			free(_array);               释放栈对象申请的堆区资源
			_array = NULL;
			_capacity = 0;
			_size = 0;
		}
}
private:
	DataType* _array;
	int _capacity;
	int _size;
};

int main()
{
	Stack a;
	return 0;                           a的生命周期结束,调用析构函数
}

When the object applies for other memory resources , the requested memory resource must be released before the object is destroyed (otherwise it will cause a memory leak). At this time, the role of the destructor can be reflected. We can customize the destructor to release The memory resource applied by the object , the compiler will automatically call the destructor when the object is destroyed, which is very convenient to use. (Note that the destructor generated by the compiler by default cannot release heap memory resources, so the default destructor generated by the compiler cannot be used in this example )

 

Guess you like

Origin blog.csdn.net/weixin_73470348/article/details/128749893