Copy constructor for game development, i.e. copy constructor (explicit keyword and call time of copy constructor) (C + + basis)

Copy constructor for game development, i.e. copy constructor (explicit keyword and call time of copy constructor) (C + + basis)

The copy constructor is a special constructor that is called when one class object is assigned to another class object.
If the copy constructor is not overridden, the compiler will automatically generate it. If the copy constructor is rewritten, the compiler will not generate the default copy constructor, and the default constructor compiler will not generate it automatically. Programmers need to write it by themselves.
The copy constructor is generally used for deep copy (it needs to be overridden if pointers are used inside the class).
Syntax: class name (const class name & variable name) {function body}

Constructors of C + + classes are classified by type: ordinary constructors and copy constructors (copy constructors)

1. Copy constructor of class (copy constructor)

	class A
	{
	public:
		//The copy constructor is a special constructor
		/*If the copy constructor is not overridden, the compiler will automatically generate it.
		If the copy constructor is rewritten, the compiler will not generate the default copy constructor,
		The default constructor compiler will not be generated automatically, and programmers need to write by themselves.*/
		//Called when a class is assigned to another class
		//Generally used for deep copy
		//If a pointer is used inside a class, it needs to be overridden
		//Syntax: class name (const class name & variable name) {function body}

		int a;
		A()
		{
			std::cout << "Call default constructor" << std::endl;
			_age = 0;
		}

		//Parameterized constructor
		A(int age) {
			std::cout << "1 Parameters" << std::endl;
			_age = age;
		}

		A(const A &a_)
		{
			std::cout << "Call copy constructor" << std::endl;
			a = a_.a;
			_age = a_._age;
		}

		void Print() {
			std::cout << "Age:" << _age << std::endl;
		}

	private:
		int _age;
	};

	int main()
	{
		A a1;
		a1.a = 200;
		A a2(a1);

		//It is very similar to assignment. The semantics is not clear and is not recommended
		A a3 = a1;
		return 0;
	}

About using anonymous objects to call copy constructors:

class A
	{
	public:
		int a;
		A()
		{
			std::cout << "Call default constructor" << std::endl;
			_age = 0;
		}
		
		//Parameterized constructor
		A(int age) {
			std::cout << "1 Parameters" << std::endl;
			_age = age;
		}

		A(const A &a_)
		{
			std::cout << "Call copy constructor" << std::endl;
			a = a_.a;
			_age = a_._age;
		}

		void Print() {
			std::cout << "Age:" << _age << std::endl;
		}

	private:
		int _age;
	};
	
	int main()
	{
		//Anonymous object: an object without a name.
		//Anonymous objects: Show call constructors
		A();
	
		//Anonymous objects call the copy constructor of a3 entities
		A a3 = A(300);
		a3.Print();

		//Anonymous objects call a4 entity copy constructors
		//Note: use anonymous object initialization to determine which constructor depends on the parameter type of the anonymous object
		A a4(A(400));
		a4.Print();

		//At this time, A(a6) is equivalent to A a6
		A(a6);
		a6.Print();
	return 0;
}

B is the instantiated object of A, A = the difference between A(b) and A(b)?
When A(b) has an instantiated object to receive, the compiler considers it an anonymous object; When there are no variables to connect, the compiler thinks that your A(b) is equivalent to a and B.

TIPS: cannot call copy constructor to initialize anonymous object.
Examples are as follows:

	class B {
	public:
		B() {
			std::cout << "Default constructor !" << std::endl;
		}
		B(const B& teacher) {
			std::cout << "copy constructor !" << std::endl;
		}
	public:
		int mAge;
	};
	
	int main()
	{
		B t1;
		B(t1);//Error, cannot initialize an anonymous function with copy constructor!!
		return 0;
	}

2.explicit keyword

explicit is used to modify the constructor to prevent implicit conversion.
It is mainly for single parameter constructors (or multi parameter constructors with default values for all parameters except the first parameter).
Limit the use in Construction: class object entity = initialization, which is initialized in this format.

	class A
	{
	public:
		explicit A(int a) { std::cout << "Constructor A" << std::endl; }
	
		//Explicit defines semantics and avoids ambiguity
		A(const A &a_)
		{
			std::cout << "Call copy constructor" << std::endl;
			a = a_.a;
		}
	};
	
	class B
	{
	public:
		B(int a) { std::cout << "Constructor A" << std::endl; }
	};
	
	int main(int argc, char** argv)
	{
		A a1 = 1; //Error, implicit conversion not allowed
		A a2(1);  //correct

		B b1 = 1; //correct
		B b2(2); //correct

		A a3;
		a3.a = 200;
		A a4(a3);

		//It is very similar to assignment. The semantics is not clear and is not recommended
		A a5 = a1;//Wrong. This usage is not allowed after the condition explicit is attached
		return 0;
	}

3. Call timing of copy constructor

The data structure is as follows:

	class A
	{
	public:
		A()
		{
			std::cout << "Default constructor!" << std::endl;
			_nAge = 10;
		}

		A(int age)
		{
			std::cout << "Parameter constructor!" << std::endl;
			_nAge = age;
		}

		A(const A& person)
		{
			std::cout << "Copy constructor!" << std::endl;
			_nAge = person._nAge;
		}

		~A()
		{
			std::cout << "Destructor!" << std::endl;
		}
	private:
		int _nAge;
	};

	void test(A p) {}

	A test2()
	{
		A p(10);
		std::cout << "local variable p: " << *(int*)&p << std::endl;
		return p;
	}

	void test3()
	{
		A p = test2();
		std::cout << "local variable p: " << *(int *)&p << std::endl;
	}

1. When the old object initializes, the new object will call the copy constructor

int main()
{
	//1. Old object initializes new object
	A p(10);
	A p1(p);
	A P2 = A(p);//Equivalent to A p2(A(p));
	A p3 = p;//Equivalent to A p3(p);
	return 0;
}

2. The formal parameter of the function is an ordinary class object, and the argument is also an ordinary class object. Calling the function will call the copy constructor

int main()
{
	//2. The formal parameter of the function is an ordinary class object, and the argument is also an ordinary class object. Calling the function will call the copy constructor
	A p4(10);
	test(p4);
	return 0;
}

3. The local class object returned by the function will call the copy constructor

int main()
{
	//3. The local class object returned by the function will call the copy constructor
	test2();
	return 0;
}

4. Call the function that returns the local class object and initialize another class object

In the debug mode of vs2017, call the copy constructor once
In the release mode of vs2017, the copy constructor is not called

int main()
{
	//4. Call the function that returns the local class object and initialize another class object
	//In the debug mode of vs2017, call the copy constructor once
	//In the release mode of vs2017, the copy constructor is not called
	test3();
	return 0;
}


TIPS: test3() indicates that the compiler will optimize the call of copy constructor during compilation.

Keywords: C++ Game Development

Added by justsomeone on Wed, 22 Dec 2021 04:05:12 +0200