C + + -- initialization and cleaning of objects

Object initialization and cleanup

  • In life, the electronic products we buy will basically have factory settings. One day, we will delete some of our own information data when we are not in use to ensure security
  • The object-oriented in C + + comes from life. Each object will also have initial settings and settings for cleaning data before object destruction.

1 constructor and destructor

Object initialization and cleanup are also two very important security issues

​ An object or variable has no initial state, and the consequences of its use are unknown

​ Similarly, after using an object or variable, it will also cause some security problems if it is not cleaned up in time

c + + uses constructors and destructors to solve the above problems. These two functions will be automatically called by the compiler to complete object initialization and cleaning.

The initialization and cleanup of objects are what the compiler forces us to do, so if we don't provide construction and destructor, the compiler will provide

The constructor and destructor provided by the compiler are empty implementations.

  • Constructor: its main function is to assign value to the member attribute of the object when creating the object. The constructor is automatically called by the compiler without manual call.
  • Destructor: the main function is that the system will automatically call and perform some cleaning work before the object is destroyed.

Constructor syntax: class name () {}

  1. Constructor, no return value and no void
  2. The function name is the same as the class name
  3. Constructors can have arguments, so overloading can occur
  4. When the program calls the object, it will automatically call the construction without manual call, and it will only be called once

Destructor syntax: ~ class name () {}

  1. Destructor, no return value, no void
  2. The function name is the same as the class name, and the symbol is added before the name~
  3. Destructors cannot have parameters, so overloading cannot occur
  4. The program will automatically call the destructor before the object is destroyed. There is no need to call it manually, and it will only be called once
class Person
{
public:
	//Constructor
	Person()
	{
		cout << "Person Constructor call for" << endl;
	}
	//Destructor
	~Person()
	{
		cout << "Person Destructor call" << endl;
	}

};

void test01()
{
	Person p;
}

int main() {
	
	test01();

	system("pause");

	return 0;
}

2 classification and call of constructor

Two classification methods:

​ According to parameters, it can be divided into parametric structure and nonparametric structure

​ By type, it can be divided into ordinary structure and copy structure

Three call modes:

​ bracketing

​ Display method

​ Implicit transformation method

Example:

//1. Constructor classification
// According to the classification of parameters, it is divided into parametric and nonparametric constructions. Nonparametric construction is also called default constructor
// According to the type, it can be divided into ordinary structure and copy structure

class Person {
public:
	//Parameterless (default) constructor
	Person() {
		cout << "non-parameter constructor !" << endl;
	}
	//Parameterized constructor
	Person(int a) {
		age = a;
		cout << "Parameterized constructor!" << endl;
	}
	//copy constructor 
	Person(const Person& p) {
		age = p.age;
		cout << "copy constructor !" << endl;
	}
	//Destructor
	~Person() {
		cout << "Destructor!" << endl;
	}
public:
	int age;
};

//2. Call of constructor
//Call parameterless constructor
void test01() {
	Person p; //Call parameterless constructor
}

//Call the constructor with parameters
void test02() {

	//2.1 bracket method, commonly used
	Person p1(10);
    //Person p2(10);// Parameterized constructor call
	//Person p3(p2);// Copy constructor call
	//Note 1: calling the parameterless constructor cannot be parenthesized. If it is, the compiler considers it a function declaration
	//Person p2();

	//2.2 explicit method
	Person p2 = Person(10); 
	Person p3 = Person(p2);
	//Writing Person(10) alone means that the anonymous object is destructed immediately after the end of the current line

	//2.3 implicit transformation method
	Person p4 = 10; // Person p4 = Person(10); 
	Person p5 = p4; // Person p5 = Person(p4); 

	//Note 2: anonymous objects cannot be initialized with copy constructors. The compiler considers them object declarations
	//Person p5(p4);
}

int main() {

	test01();
	//test02();

	system("pause");

	return 0;
}

3. Call timing of copy constructor

In C + +, there are usually three situations when copying constructor calls

  • Initialize a new object with an already created object
  • Value is passed to function parameters
  • Returns a local object as a value

Example:

class Person {
public:
	Person() {
		cout << "non-parameter constructor !" << endl;
		mAge = 0;
	}
	Person(int age) {
		cout << "Parameterized constructor!" << endl;
		mAge = age;
	}
	Person(const Person& p) {
		cout << "copy constructor !" << endl;
		mAge = p.mAge;
	}
	//Destructor called before freeing memory
	~Person() {
		cout << "Destructor!" << endl;
	}
public:
	int mAge;
};

//1. Initialize a new object with an already created object
void test01() {

	Person man(100); //The p object has been created
	Person newman(man); //Call copy constructor
	Person newman2 = man; //copy construction 

	//Person newman3;
	//newman3 = man; // Instead of calling the copy constructor, the assignment operation
}

//2. The method of value transfer is to transfer values to function parameters
//Equivalent to Person p1 = p;
void doWork(Person p1) {}
void test02() {
	Person p; //non-parameter constructor 
	doWork(p);
}

//3. Return local objects as values
Person doWork2()
{
	Person p1;
	cout << (int *)&p1 << endl;
	return p1;
}

void test03()
{
	Person p = doWork2();
	cout << (int *)&p << endl;
}


int main() {

	//test01();
	//test02();
	test03();

	system("pause");

	return 0;
}

4 constructor call rules

By default, the c + + compiler adds at least three functions to a class

1. Default constructor (no parameters, empty function body)

2. Default destructor (no parameters, empty function body)

3. The default copy constructor copies the value of the attribute

Constructor calling rules are as follows:

  • If the user defines a parameterized constructor, c + + will no longer provide a default parameterless construct, but will provide a default copy construct

  • If you define a copy constructor, c + + will not provide another constructor

Example:

class Person {
public:
	//Parameterless (default) constructor
	Person() {
		cout << "non-parameter constructor !" << endl;
	}
	//Parameterized constructor
	Person(int a) {
		age = a;
		cout << "Parameterized constructor!" << endl;
	}
	//copy constructor 
	Person(const Person& p) {
		age = p.age;
		cout << "copy constructor !" << endl;
	}
	//Destructor
	~Person() {
		cout << "Destructor!" << endl;
	}
public:
	int age;
};

void test01()
{
	Person p1(18);
	//If you do not write a copy construct, the compiler will automatically add a copy construct and do a shallow copy operation
	Person p2(p1);

	cout << "p2 Your age is: " << p2.age << endl;
}

void test02()
{
	//If the user provides a parameter construct, the compiler will not provide a default construct, but a copy construct
	Person p1; //At this time, if the user does not provide the default structure, an error will occur
	Person p2(10); //User provided parameters
	Person p3(p2); //At this time, if the user does not provide a copy structure, the compiler will provide it

	//If the user provides a copy construct, the compiler does not provide other constructors
	Person p4; //At this time, if the user does not provide the default structure, an error will occur
	Person p5(10); //At this time, if the user does not provide a parameter, an error will occur
	Person p6(p5); //Users provide their own copy structure
}

int main() {

	test01();

	system("pause");

	return 0;
}

5 deep copy and light copy

Deep and shallow copy is not only a classic interview question, but also a common pit

Shallow copy: a simple assignment copy operation, which brings problems: the memory in the heap area is repeatedly released

Deep copy: reapply space in the heap area for copy operation

Example:

class Person {
public:
	//Parameterless (default) constructor
	Person() {
		cout << "non-parameter constructor !" << endl;
	}
	//Parameterized constructor
	Person(int age ,int height) {
		
		cout << "Parameterized constructor!" << endl;

		m_age = age;
		m_height = new int(height);
		
	}
	//copy constructor   
	Person(const Person& p) {
		cout << "copy constructor !" << endl;
		//If you do not use deep copy to create new memory in the heap, it will lead to the problem of repeatedly freeing the heap caused by shallow copy
		m_age = p.m_age;
		m_height = new int(*p.m_height);
		
	}

	//Destructor
	~Person() {
		cout << "Destructor!" << endl;
		if (m_height != NULL)
		{
			delete m_height;
		}
	}
public:
	int m_age;
	int* m_height;
};

void test01()
{
	Person p1(18, 180);

	Person p2(p1);

	cout << "p1 Age: " << p1.m_age << " Height: " << *p1.m_height << endl;

	cout << "p2 Age: " << p2.m_age << " Height: " << *p2.m_height << endl;
}

int main() {

	test01();

	system("pause");

	return 0;
}

Conclusion: if the attribute is opened in the heap area, you must provide your own copy constructor to prevent the problems caused by shallow copy

6 initialization list

effect:

C + + provides initialization list syntax to initialize attributes

Syntax: constructor (): Property 1 (value 1), property 2 (value 2) {}

Example:

class Person {
public:

	////Traditional initialization
	//Person(int a, int b, int c) {
	//	m_A = a;
	//	m_B = b;
	//	m_C = c;
	//}

	//Initialization list mode
	Person(int a, int b, int c) :m_A(a), m_B(b), m_C(c) {}
	void PrintPerson() {
		cout << "mA:" << m_A << endl;
		cout << "mB:" << m_B << endl;
		cout << "mC:" << m_C << endl;
	}
private:
	int m_A;
	int m_B;
	int m_C;
};

int main() {

	Person p(1, 2, 3);
	p.PrintPerson();


	system("pause");

	return 0;
}

7 class objects as class members

A member in a C + + class can be an object of another class, which we call an object member

For example:

class A {}
class B
{
    A a;
}

Class B has object A as A member and A as an object member

Then, when creating B objects, which is the order of construction and Deconstruction of A and B?

Example:

class Phone
{
public:
	Phone(string name)
	{
		m_PhoneName = name;
		cout << "Phone structure" << endl;
	}

	~Phone()
	{
		cout << "Phone Deconstruction" << endl;
	}

	string m_PhoneName;

};


class Person
{
public:

	//The initialization list tells the compiler which constructor to call
	Person(string name, string pName) :m_Name(name), m_Phone(pName)
	{
		cout << "Person structure" << endl;
	}

	~Person()
	{
		cout << "Person Deconstruction" << endl;
	}

	void playGame()
	{
		cout << m_Name << " use" << m_Phone.m_PhoneName << " Brand mobile phone! " << endl;
	}

	string m_Name;
	Phone m_Phone;

};
void test01()
{
	//When a member in a class is an object of another class, we call it an object member
	//The order of construction is: call the construction of object members first, and then call the construction of this class
	//The tectonic sequence is opposite to that of the structure
	Person p("Zhang San" , "Apple X");
	p.playGame();

}


int main() {

	test01();

	system("pause");

	return 0;
}

8 static members

Static members are called static members by adding the keyword static before member variables and member functions

Static members are divided into:

  • Static member variable
    • All objects share the same data
    • Allocate memory at compile time
    • In class declaration, out of class initialization
  • Static member function
    • All objects share the same function
    • Static member functions can only access static member variables

Example 1: static member variables

class Person
{
	
public:

	static int m_A; //Static member variable

	//Static member characteristics:
	//1 allocate memory during compilation
	//2. Declaration within class and initialization outside class
	//3 all objects share the same data

private:
	static int m_B; //Static member variables also have access rights
};
int Person::m_A = 10;
int Person::m_B = 10;

void test01()
{
	//There are two ways to access static member variables

	//1. Through object
	Person p1;
	p1.m_A = 100;
	cout << "p1.m_A = " << p1.m_A << endl;

	Person p2;
	p2.m_A = 200;
	cout << "p1.m_A = " << p1.m_A << endl; //Share the same data
	cout << "p2.m_A = " << p2.m_A << endl;

	//2. By class name
	cout << "m_A = " << Person::m_A << endl;


	//cout << "m_B = " << Person::m_ B << endl; // Private access not available
}

int main() {

	test01();

	system("pause");

	return 0;
}

Example 2: static member function

class Person
{

public:

	//Static member function features:
	//1 programs share a function
	//2 static member functions can only access static member variables
	
	static void func()
	{
		cout << "func call" << endl;
		m_A = 100;
		//m_B = 100; // Error, non static member variables cannot be accessed
	}

	static int m_A; //Static member variable
	int m_B; // 
private:

	//Static member functions also have access rights
	static void func2()
	{
		cout << "func2 call" << endl;
	}
};
int Person::m_A = 10;


void test01()
{
	//There are two ways to access static member variables

	//1. Through object
	Person p1;
	p1.func();

	//2. By class name
	Person::func();


	//Person::func2(); // Private access not available
}

int main() {

	test01();

	system("pause");

	return 0;
}

Posted by creative on Fri, 13 May 2022 05:11:54 +0300