C + + foundation -- classes and objects (middle) -- constructor, destructor, copy construction

Posted by amedhussaini on Thu, 20 Jan 2022 19:55:48 +0100

1. The default six member functions of the class

If there is nothing in a class, it is referred to as an empty class. Is there nothing in the empty class? No, if I don't implement any class, the following six default member functions will be generated automatically

Default member functions: they are special member functions. If we don't implement them, the compiler will generate one by itself.

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 type object to ensure that each data member has an appropriate initial value and is called only once in the object declaration cycle

2. Constructor

Constructor is a special member function. It should be noted that although the constructor is called constructor, it often gives us a misunderstanding here, but it does not open up space to create objects, but initialize objects

[constructor features]:

  • The function name is the same as the class name
  • No return value
  • When an object is instantiated, the compiler automatically calls the corresponding constructor
  • Constructors can be overloaded
  • If the defined constructor is not displayed in the class, the C + + compiler will automatically generate a parameterless default constructor. Once it is defined, the compiler will no longer generate it

The constructor with parameters and the above parameterless constructor constitute an overload

class Date
{
public:
	//non-parameter constructor 
	Date()
	{
		_year = 1;
		_month = 1;
		_day = 1;
	}
	//The constructor with parameters and the above parameterless constructor constitute an overload
	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 d2(2022, 1, 17);

	return 0;
}

Hit a breakpoint, debug and find that it can run and display the results.

It should also be noted that syntactically nonparametric and full default parameters can exist at the same time, because it is enough to cause function overloading, but when calling nonparametric, the compiler cannot distinguish which is called, which is ambiguous.

class Date
{
public:
	//non-parameter constructor 
	Date()
	{
		_year = 1;
		_month = 1;
		_day = 1;
	}

    //Full default constructor
	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1;

	return 0;
}

It is recommended to use full default or semi default, which is easier to use

When we don't write a constructor, the compiler will automatically help us implement the constructor. The d object calls the default constructor generated by the compiler, but the d object year/month/_day is still a random value. In other words, the default constructor generated by the compiler is useless here??


Here, C + + divides classes into two categories: built-in types (basic types) and custom types

Built in types: such as int/char/double / pointer / built-in type array, etc

Custom type: type defined by struct/class

When we do not write constructors, the compiler generates them by default and does not initialize member variables of built-in types.

For a custom type member variable, it will call its default constructor for initialization. If there is no default constructor, an error will be reported.

The default constructor of any class is -- it can be called without parameters. There are three default constructors of any class, which are all default, parameterless and generated by the compiler by default.

3. Destructor

3.1 destructor concept

We learned that the constructor is an initialization object, so what does the destructor do?
Destructor: Contrary to the constructor function, the destructor does not complete the destruction of objects, and the destruction of local objects is completed by the compiler. When the object is destroyed, it will automatically call the destructor to clean up some resources of the class
 

3.2 characteristics

  1. The destructor name is preceded by a character in the class~
  2. No parameter return value
  3. A class has only one destructor. If the definition is not displayed, the system will automatically generate the default destructor
  4. At the end of the object life cycle, the C + + compilation system automatically calls the destructor
class Date
{
public:
	Date(int year = 0, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	~Date()
	{
		cout << "~Date()" << endl;
	}

private:
	int _year;
	int _month;
	int _day;
};

The Date class has no resources to be cleaned up, so it is possible that the Date does not implement the destructor. What needs to be cleaned up?
The space opened on the heap needs to be cleaned up. If the resources on the heap are not released actively, they will not be released. You need to write a destructor yourself, as follows:

Implement a stack:

class Stack
{
public:
	Stack(int capacity = 4)
	{
		_a = (int*)malloc(sizeof(int)*capacity);
		if (_a == nullptr)
		{
			cout << "malloc fail\n" << endl;
			exit(-1);
		}

		_top = 0;
		_capacity = capacity;
	}

	void Push(int x)
	{}
	
	~Stack()
	{
		free(_a);
        //Although it is destroyed automatically, it is better to write it
		_top = _capacity = 0;
	}

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

class MyQueue
{
public:
	void push(int x)
	{

	}

private:
	Stack PushST;
	Stack PopST;
};

int main()
{
	Stack st;
	Stack st2(20);

    MyQueue mq;

	return 0;
}

When we write two stacks to implement a queue, we need to instantiate two stacks. The space opened up is on the heap. After we destroy the space opened up by malloc on the heap, the instantiated objects are automatically destroyed

 

[note]:

In addition, the destruction order of destructors is reversed with that of constructors. In the above example, st is constructed first and then st2. The destruction order of destructors is st2, st

5. For the destructor automatically generated by the compiler, call its default destructor for custom type members

class String
{
public:
	String(const char* str = "jack")
	{
		_str = (char*)malloc(strlen(str) + 1);
		strcpy(_str, str);
	}
	~String()
	{
		cout << "~String()" << endl;
		free(_str);
	}
private:
	char* _str;
};

class Person
{
//There is no need to write a destructor, and a custom destructor will be called
private:
	String _name;
	int _age;
};

int main()
{
	Person p;

	return 0;
}

4. Copy constructor

4.1 concept

Constructor: there is only a single formal parameter, which is a reference to an object of this type (usually decorated with const). It is automatically called by the compiler when creating a new object with an existing type object.

4.2 characteristics

The copy constructor is also a special member function with the following characteristics:

  1. The copy constructor is an overloaded form of the constructor
  2. There is only one parameter of the copy constructor, and the parameter must be passed by reference. Using the value passing method will cause infinite recursive calls
class Date
{
public:
	Date(int year = 0, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	//Date(d1);
	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;
}

If the parameter is passed without reference, it becomes this form Date(const Date d). Then calling the copy structure needs to pass the parameter. The passed parameter calls the copy structure, and the copy structure calls the passed parameter

 3. If the definition is not displayed, the system generates the default copy constructor

  • Built in type members, which will complete the copy in byte order. (light copy)
  • A custom type member will call its copy construct

In some places, we can use the copy structure generated by the system by default, such as shallow copy, which directly copies the value of the stack area from d1 to d2, while in some places, such as deep copy, we need to implement the copy constructor ourselves, such as the implementation of the stack. When copying, we also copy the address of st1 to st2. When destroying the function, we destroy st2 first. After destroying the address, the address of st1 will no longer exist, An error occurred, causing the program to crash.

[summary] - constructor, destructor, copy construction

1. Constructor -- initialization, which is called automatically when the object is instantiated to ensure that the instantiated object must be initialized

Constructor is the default member function. If you don't write it yourself, the compiler will generate one. If you write it yourself, the compiler will not generate it.

For compiler default generated constructors

  • Do not handle built-in type member variables
  • Call his default constructor on a custom type member variable

2. Destructor to clean up the resources in the object. If the object needs resource cleanup, you need to implement the destructor yourself. The destructor will be called automatically after the declaration cycle of the object. If the destructor is implemented correctly, the resources in the object will be cleaned up.

If we don't implement it, the compiler will generate the default destructor. If we implement it, the compiler won't implement it

For default build destructors

  • Do not process member variables of built-in types
  • Call its destructor on a custom type member variable

 

3. Copy construction: use objects of the same type to initialize instance objects

If we don't implement it, the compiler will generate a default copy constructor

Generate copy structure by default:

  • The built-in type completes the value copy in byte order -- shallow copy
  • A custom type member variable will call its copy construct

 

Topics: C++ Back-end