C + + classes and objects -- initialization and cleaning of objects

4.2 initialization and cleaning of objects

  • 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.

4.2.1 constructors and destructors

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 cleaning of objects are what the compiler forces us to do, so if we don't provide construction and destruction, the compiler will provide

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

  • Constructor: it is mainly used to assign values to the member properties of the object when creating the object. The constructor is automatically called by the compiler without manual call.
  • Destructor: it is mainly used to automatically call and perform some cleaning 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 construct without manual call, and it will only be called once

Destructor syntax: ~ class name () {}

  1. Destructor, no return value, no write 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, without manual call, and will only call it once
#include <iostream>
using namespace std;

// Object initialization and cleanup
// 1. Constructor to perform the initial operation
class Person
{
public:
	// 1. Constructor
	// No return value, no need to write void
	// The function name is the same as the class name
	// Constructors can have parameters and can be overloaded
	// When creating an object, the constructor will be called automatically, and it will be called once
	Person()
	{
		cout << "Person Call to constructor" << endl;
	}

	// 2. The destructor performs a cleanup operation
	// void is not written if there is no return value
	// The function name is the same as the class name, and the name is preceded by~
	// Destructors cannot have parameters and cannot be overloaded
	// The destructor will be called automatically and only once before the object is destroyed
	~Person()
	{
		cout << "Person Destructor call for" << endl;
	}

};

// Construction and deconstruction are necessary implementations. If we don't provide them ourselves, the compiler will provide a construction and Deconstruction of an empty implementation
void test01()
{
	Person p; // For the data on the stack, release the object after test01 is executed
}



int main()
{

	test01();

	//Person p;

	system("pause");

	return 0;
}

4.2.2 classification and calling of constructors

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:

#include <iostream>
using namespace std;

// 1. Classification and call of constructor
// classification
//   Parameterless construction (default construction) and parameterless construction are classified according to parameters
//   Construct a common copy constructor by type
class Person
{
public:
	// Constructor
	Person()
	{
		cout << "Person Call to parameterless constructor" << endl;
	}
	Person(int a)
	{
		age = a;
		cout << "Person Call with parameter constructor" << endl;
	}
	// copy constructor 
	Person(const Person& p)
	{
		// Copy all the attributes of the incoming person to me
		age = p.age;
		cout << "Person Call to copy constructor" << endl;
	}

	~Person()
	{
		cout << "Person Call to destructor" << endl;
	}

	int age;

};

// call
void tste01()
{
	// 1. Bracket hair
	//Person p1; //  Call to default constructor
	//Person p2(10); //  Parameterized constructor
	//Person p3(p2); //  copy constructor 

	// matters needing attention
	// When calling the default constructor, do not add ()
	// Because of the following line of code, the compiler will consider it as a declaration of a function and will not consider it as creating an object
	// Person p4();


	//Cout < < P2's age is: < < P2 age << endl;
	//Cout < < P3's age is: < < P3 age << endl;

	// 2. Display method
	//Person p1;
	//Person p2 = Person(10); //  Parametric structure
	//Person p3 = Person(p2); //  copying functions 

	//Person(10); //  Anonymous object features: after the execution of the current line, the system will immediately recycle the anonymous object
	//cout << "aaaa" << endl;

	// Note 2
	// Do not initialize anonymous objects with copy constructors
	// The compiler will assume that Person (p3) === Person p3; Object declaration
	Person(p3);

	// 3. Implicit transformation method
	Person p4 = 10; // P4 = person (10) relative to the person written; Parametric structure
	Person p5 = p4; // copy construction 
}

int main()
{

	tste01();

	system("pause");

	return 0;
}

4.2.3 call timing of copy constructor

There are three situations in C + + when copying constructor calls

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

Example:

#include <iostream>
using namespace std;

// Copy constructor call timing



class Person
{
public:
	Person()
	{
		cout << "Person Default constructor call" << endl;
	}
	Person(int age)
	{
		m_Age = age;
		cout << "Person Parameterized constructor call" << endl;
	}
	Person(const Person& p)
	{
		m_Age = p.m_Age;
		cout << "Person Copy constructor call" << endl;

	}
	~Person()
	{
		cout << "Person Destructor call" << endl;
	}

	int m_Age;
};

// 1. Initialize a new object with an already created object
void test01()
{
	Person p1(20);
	Person p2(p1);

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

}
// 2. Value is passed to the function parameter value
void doWork(Person p)
{

}

void test02()
{
	Person p;
	doWork(p);

}

// 3. Returns a local object by value

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.2.4 constructor calling 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:

#include <iostream>
using namespace std;

// Call to constructor
// 1. Create a class, and the C + + compiler will add at least 3 functions to each class
// Default construct (empty Implementation)
// Destructor (empty Implementation)
// Copy construction (value copy)


// 2. If we write a parameterized constructor, the compiler will no longer provide the default constructor, but still provide the copy constructor
// If we write a copy constructor, the compiler will no longer provide other ordinary constructors

class Person
{

public:
	//Person()
	//{
	//	Cout < < default constructor call of person < < endl;
	//}
	//~Person()
	//{
	//	Cout < < destructor call of person < < endl;
	//}
	//Person(int age)
	//{
	//	m_Age = age;
	//	Cout < < person's parameterized constructor call < < endl;
	//}

	Person(const Person& p)
	{
		m_Age = p.m_Age;
		cout << "Person Copy constructor call" << endl;
	}

	int m_Age;
};

//void test01()
//{
//	Person p;
//	p.m_Age = 18;
//
//	Person p2(p);
//
//	Cout < < P2's age is: < < P2 m_ Age << endl;
//}

void test02()
{
	Person p;

	//Person p2(p);

	//Cout < < P2's age is: < < P2 m_ Age << endl;

}

int main()
{

	//test01();
	test02();

	system("pause");

	return 0;
}

4.2.5 deep copy and shallow copy

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

Shallow copy: a simple assignment copy operation

Deep copy: re apply for space in the heap area for copy operation

Example:

#include <iostream>
using namespace std;

// Deep and shallow copies

class Person
{
public:
	Person()
	{
		cout << "Person Default constructor call for" << endl;
	}
	Person(int age, int height)
	{
		m_Age = age;
		m_Height = new int(height);
		cout << "Person Parameterized constructor call" << endl;
	}

	// Implement the copy constructor to solve the problems caused by shallow copy
	Person(const Person& p)
	{
		cout << "Person Copy constructor call" << endl;
		m_Age = p.m_Age;
		// m_Height = p.m_Height; //  The compiler's default implementation is this line of code
		// Deep copy operation
		m_Height = new int(*p.m_Height);
	}

	~Person()
	{
		// Destruct the code and release the heap development data
		if (m_Height != NULL)
		{
			delete m_Height;
			m_Height = NULL;
		}
		cout << "Person Destructor call for" << endl;
	}

	int m_Age;

	int* m_Height;
};

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

	cout << "p1 Your age is:" << p1.m_Age << " Height:" << *p1.m_Height << endl;

	Person p2(p1);

	cout << "p1 Your age is:" << p2.m_Age << " Height:" << *p2.m_Height << endl;
}



int main()
{

	test01();

	system("pause");

	return 0;
}

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

4.2.6 initialization list

effect:

C + + provides initialization list syntax to initialize attributes

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

Example:

#include <iostream>
using namespace std;

// Initialization list

class Person
{
public:

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


	// Initialization list initialization properties
	Person(int a, int b, int c) : m_A(a), m_B(b), m_C(c)
	{

	}

	int m_A;
	int m_B;
	int m_C;
};

void test01()
{
	// Person p(10, 20, 30);

	Person p(30, 20, 10);

	cout << "m_A: " << p.m_A << endl;
	cout << "m_B: " << p.m_B << endl;
	cout << "m_C: " << p.m_C << endl;

}

int main()
{

	test01();

	system("pause");

	return 0;
}

4.2.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 A B object, which is the order of construction and Deconstruction of A and B?

Example:

#include <iostream>
using namespace std;

// Class objects as class members

// Mobile phone class
class Phone
{
public:

	Phone(string p)
	{
		m_PName = p;
		cout << "Phone constructor call " << endl;
	}

	~Phone()
	{
		cout << "Phone Destructor call" << endl;
	}

	// Name of mobile phone brand
	string m_PName;
};

class Person
{

public:

	// Phone m_Phome = pName;  //  Implicit transformation method
	Person(string name, string pName) : m_Name(name), m_Phone(pName)
	{
		cout << "Person constructor call " << endl;
	}

	~Person()
	{
		cout << "Person Destructor call" << endl;
	}


	// full name
	string m_Name;
	// mobile phone
	Phone m_Phone;
};


// When other class objects are members of this class, class objects are constructed first, and then themselves. The deconstruction order is opposite
void test01()
{
	Person p("Zhang San", "Apple MAX");

	cout << p.m_Name << "Take:" << p.m_Phone.m_PName << endl;
}

int main()
{

	test01();

	system("pause");

	return 0;
}

4.2.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
    • Inner class declaration, outer 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

#include <iostream>
using namespace std;

// Static member
class Person
{
public:

	// 1. All objects share the same data
	// 2. Memory is allocated at compile time
	// 3. Inner class declaration, outer class initialization
	static int m_A;

	// Static member variables also have access rights
private:

	static int m_B;
};

int Person::m_A = 100;
int Person::m_B = 200;

void test01()
{
	Person p;

	cout << p.m_A << endl;

	Person p2;
	p.m_A = 200;

	// 200
	cout << p.m_A << endl;
}

void test02()
{
	// Static member variables do not belong to an object, and all objects share the same data
	// Therefore, static member variables can be accessed in two ways

	// 1. Access through objects
	//Person p;
	//cout << p.m_A << endl;

	// 2. Access by class name
	cout << Person::m_A << endl;
	// cout << Person::m_ B << endl; //  Private static member variable not accessible outside class
}

int main()
{

	// test01();
	test02();


	system("pause");
	return 0;
}

Example 2: static member function

#include <iostream>
using namespace std;

// Static member function
// All objects share a function
// Static functions can only access static members

class Person
{
public:
	
	// Static member function
	static void func()
	{
		m_A = 100; // Static member functions can access static member variables
		// m_B = 200; //  Static member functions cannot access non static member variables, and it is impossible to distinguish which object is m_B attribute
		cout << "static void func call" << endl;
	}

	static int m_A; // Static member variable
	int m_B; // Non static member variable

private:
	static void func2()
	{
		cout << "static void func2 call" << endl;
	}
};

int Person::m_A = 0;

// There are two ways to access
void test01()
{
	// 1. Access by object
	Person p;
	p.func();


	// 2. Access by class name
	Person::func();

	// Person::func2();  //  Private static member function not accessible outside class

}

int main()
{

	test01();

	system("pause");

	return 0;
}

Added by vomitbomb on Sat, 08 Jan 2022 15:26:21 +0200