Classes and objects in C++ 2-constructor, destructor, copy constructor, assignment operator overloaded function

Class 1 constructor

1.1 The concept of constructor

For the following date classes


class Date{
    
     
public:
 void SetDate(int year, int month, int day)
 {
    
    
 _year = year;
 _month = month;
 _day = day;
 }
 
 void Display()
 {
    
    
 cout <<_year<< "-" <<_month << "-"<< _day <<endl;
 }
private:
 int _year;
 int _month;
 int _day;
 }
 int main()
{
    
    
 Date d1,d2;
 d1.SetDate(2018,5,1);
 d1.Display();
 
 Date d2;
 d2.SetDate(2018,7,1);
 d2.Display();
 return 0;
 }
 

1 For the Date class above, you can set the content of the object through the SetDate public method, but if you call this method to set the information every time you create an object, it would be a bit troublesome. Can you set the object information automatically when the object is created? What?
2 The constructor solves this problem. The constructor is a special member function with the same name as the class name. It is automatically called by the compiler when creating a class type object, ensuring that each private data member has a suitable Initial value, and only called once in the life cycle of the object.

1.2 Features of the constructor

The constructor is a special member function. It is worth noting that although the name of the constructor is called the constructor, the main task of the constructor
is not to open the space to create the object, but to initialize the object .
Its characteristics are as follows:
1. The function name is the same as the class name
2. No return value
3. The editor automatically calls the corresponding constructor when the object is instantiated.
4. The constructor can be overloaded

#include <iostream>
#include <windows.h>
using namespace std;

class Date{
    
    
public:
	//1.无参构造函数
	Date(){
    
    

	}
	// 2.带参构造函数
	Date(int year, int month, int day){
    
    
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
    
    

	Date d1; //调用无参构造函数   注意不要带括号:Date d1();否则就成了函数声明
	Date d2(2021, 8, 11);//调用带参构造函数

	system("pause");
	return 0;
}

5. If the constructor is not explicitly defined in the class, the C++ compiler will automatically generate a default constructor with no parameters. Once the user explicitly defines the constructor, the compiler will not generate it again.
6. Both the parameterless constructor and the full default constructor are the default constructors, and there can only be one default constructor. Note: The no-argument constructor, the full default constructor, and the constructor generated by the compiler by default without writing can all be considered as the default constructor.
Such as the following code will compile error

#include <iostream>
#include <windows.h>
using namespace std;

class Date{
    
    
public:
	//1.无参构造函数
	Date(){
    
    

	}
	// 2.带参构造函数
	Date(int year = 1000, int month = 23, int day = 12){
    
    
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
    
    

	Date d1; //调用无参构造函数   注意不要带括号:Date d1();否则就成了函数声明
	//Date d2(2021, 8, 11);//调用带参构造函数

	system("pause");
	return 0;
}

Insert picture description here

7. Let’s look at a strange phenomenon below

#include <iostream>
#include <windows.h>
using namespace std;
class Date{
    
    
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
    
    
	Date d1; //调用无参构造函数   注意不要带括号:Date d1();否则就成了函数声明
	system("pause");
	return 0;
}

The above code calls the default no-argument constructor, but the result is this.
Insert picture description here
There are many students who have questions about the default member function generated by the compiler: in the case that we do not implement the constructor, the default member function generated by the compiler does not appear. What is the effect? ​​The data is still a random value. The default member function generated by the compiler is not useful?
In fact, it is like this: C++ divides types into built-in types (basic types) and custom types. The built-in type is the type that has been defined by the grammar: such as
int/char..., the custom type is the type defined by us using class/struct/union. If you look at the following program, you will find that the
compiler generates the default constructor. The custom type member _t calls its default member function to initialize the object t (if it is also the default of the compiler itself, it will not do anything)

#include <iostream>
#include <windows.h>
using namespace std;
class Time{
    
    
public:
	Time()
	{
    
    
		cout << "Time()" << endl;
		_hour = 12;
		_minute = 12;
		_second = 12;
	}
private:
	int _hour;
	int _minute;
	int _second;
};
class Date{
    
    
private:
	int _year;
	int _month;
	int _day;
	Time t;
};
int main()
{
    
    
	Date d1; //调用无参构造函数   注意不要带括号:Date d1();否则就成了函数声明
	system("pause");
	return 0;
}

Insert picture description here

Search it!

2 types of destructors

2.1 The concept of destructor

Through the study of the constructor, we know how an object comes from, and how does that object disappear?
Destructor: Contrary to the function of the constructor, the destructor does not complete the destruction of the object. The local object destruction is done by the compiler. When the object is destroyed, it will automatically call the destructor to clean up some resources of the class .

2.2 The characteristics of the destructor

The destructor is a special member function, its characteristics are as follows:

  1. The destructor name is prefixed with the character ~ in the class name.
  2. No parameters and no return value
  3. A class has exactly one destructor. If it is not explicitly defined, the system will automatically generate a default destructor.
  4. When the object life cycle ends, the C++ compilation system automatically calls the destructor. For example, the following sequence table class
#include <iostream>
#include <assert.h>
#include <string.h>
#pragma warning(disable:4996)
using namespace std;
class SeqList{
    
    
public:
	SeqList(int capacity){
    
    
		_arr = (int*)(malloc(sizeof(int)*capacity));
		assert(_arr);
		_capacity = capacity;
		_size = 0;
	}
	~SeqList(){
    
    
		if (_arr){
    
    
			cout << "~SeqList()" << endl;
			free(_arr);
			_arr = nullptr;
			_size = _capacity = 0;
		}
		
	}
private:
	int* _arr;
	int _size;
	int _capacity;
};
class MyString{
    
    
public:
	MyString(const char* str = "chenzhihao"){
    
    
		_str = (char*)malloc(strlen(str) + 1);
		strcpy(_str, str);
	}
	~MyString(){
    
    
		cout << "~MyString()" << endl;
		free(_str);
		_str = nullptr;
	}
private:
	char* _str;
};
class Person{
    
    
private:
	MyString _name;
	int _age;
};
int main()
{
    
    
	SeqList sl(12);
	Person p;
	return 0;
}

Insert picture description here

  1. Regarding the destructor automatically generated by the compiler, will something be done: From the program source code above, it can be seen that the default destructor generated by the compiler will call its destructor for members of the custom type.

3 types of copy/copy constructor

3.1 The concept of copy/copy constructor

Insert picture description here

When creating an object, can you create a new object that is exactly the same as an object?
Copy constructor: There is only one formal parameter, which is a reference to this type of object (usually a constant reference), which is automatically called by the compiler when creating a new object with an existing type of object.

3.2 Features of Copy/Copy Constructor

The copy constructor is also a special member function, and its characteristics are as follows:
1. The copy constructor is an overloaded form of the
constructor 2. The copy constructor has only one parameter and must be passed by reference. The use of pass by value will cause endless Recursive call.

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; 
 }

Insert picture description here

  1. If not explicitly defined, the compiler will generate a default copy constructor. The default copy constructor object is copied in byte order according to the memory storage, this kind of copy is called shallow copy or value copy.
  2. Then the default copy constructor generated by the compiler can already complete the endian value copy, do we still need to implement it ourselves? Of course, a class like the date class is not necessary, what if it is the following class? Will the compiled code pass? Will there be an error in operation?
#include <iostream>
#include <assert.h>
#include <string.h>
#pragma warning(disable:4996)
using namespace std;
class MyString{
    
    
public:
	MyString(const char* str = "Tom"){
    
    
		_str = (char*)malloc(strlen(str) + 1);
		strcpy(_str, str);
	}
	~MyString(){
    
    
		cout << "~MyString()" << endl;
		free(_str);
		_str = nullptr;
	}
private:
	char* _str;
};
int main()
{
    
    
	MyString s1("czh");
	MyString s2(s1);
	return 0;
}

The answer is: compilation is ok, but running the program will crash, because the default copy constructor is just a value (shallow) copy, _str is the same, that is, it points to a memory space, and the destructor is called in s2 At that time, the space pointed to by _str will be released, and then s1 will call the destructor to release this space. At this time, this space has been reclaimed by the operating system. This space does not belong to s1, that is, it releases what it does not belong to Space, causing the program to crash.

4 types of assignment operator overloaded functions

4.1 Operator overloading

C++ introduces operator overloading in order to enhance the readability of the code. Operator overloading is a function with a special function name, and also has its return value type, function name, and parameter list. The return value type is similar to the parameter list and ordinary functions.
The name of the function is: keyword operator + operator symbol that needs to be overloaded.
Function prototype: return value type operator operator (parameter list)
Note: You
cannot create a new operator by connecting other operators: for example, operator@
overload operator must have an operand of a class type or an enumeration type.
The meaning of operators used for built-in types cannot be changed, for example: built-in integer +, cannot change its meaning. When
used as an overloaded function of a class member, the first parameter of the formal parameter list is: the type this pointer. *
. :: szieof ?:. These 5 operators cannot be overloaded *.

class Date
{
    
     
public:
 Date(int year = 1900, int month = 1, int day = 1)
 {
    
    
 _year = year;
 _month = month;
 _day = day;
 }
 
 // bool operator==(Date* this, const Date& d2)
 // 这里需要注意的是,左操作数是this指向的调用函数的对象
 bool operator==(const Date& d2)
 {
    
    
 return _year == d2._year;
 && _month == d2._month
 && _day == d2._day;
 }
 private:
 int _year;
 int _month;
 int _day;
}
void Test ()
{
    
    
 Date d1(2018, 9, 26);
 Date d2(2018, 9, 27);
 cout<<(d1 == d2)<<endl; 
 } 

4.2 Assignment operator overloading

The assignment operator mainly has the following points to note:

  1. Parameter Type
  2. return value
  3. Check whether you assign yourself a value
  4. Return *this
  5. If a class does not explicitly define the assignment operation overload, the compiler will also generate one to complete the endian value (shallow) copy of the object.

Then the default assignment overload function generated by the compiler can complete the endian value copy, do we still need to implement it ourselves? Of course
, classes like date are not necessary. What about the following classes? Try to verify it?

// 这里会发现下面的程序会崩溃掉?这里就需要我们以后讲的深拷贝去解决。
class String
{
    
    
public:
 String(const char* str = "")
 {
    
    
 _str = (char*)malloc(strlen(str) + 1);
 strcpy(_str, str);
 }
 ~String()
 {
    
    
 cout << "~String()" << endl;
 free(_str);
 }
 private:
 char* _str;
};
int main()
{
    
    
 String s1("hello");
 String s2("world");
 
 s1 = s2; 
 }

Here will happen the same situation as the above copy constructor, the program will crash, the reason is also the problem caused by repeated destruction, need deep copy to solve, I will write about it later.

Guess you like

Origin blog.csdn.net/CZHLNN/article/details/113736980