C++ classes and objects (4)

1. Copy constructor

1.1 Concept

In real life, there may exist a self just like you, which we call a twin.
insert image description here
When creating an object, can you create a new object that is the same as an existing object?

Copy constructor: There is only a single formal parameter , which is a reference to the object of this class type (usually const decoration), which is automatically called by the compiler when creating a new object with an existing class type object.

1.2. Features

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

1.2.1. An overloaded form of the copy constructor constructor;

1.2.2. There can only be one parameter of the copy constructor, which is a reference to the object of this class type, and cannot be called by value. Compilation will directly report an error, or directly enter an infinite loop.

class Date
{
    
    
public:
Date(int year = 1900, int month = 1, int day = 1)
{
    
    
_year = year;
_month = month;
_day = day;
}
// Date(const Date& d)  // 正确写法
  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 image description here
Note: Calling the copy constructor is called when defining a new class. If two types d1 and d2 of two classes have been defined, d1=d2 is an overload of the assignment operator, which is a simple copy and will not be called Copy constructor!

Therefore, when writing a copy constructor, if it is called by value, the copy constructor will be called all the time, and there will be endless recursive calls.
insert image description here

1.2.3. If the copy constructor is not explicitly defined, the compiler will generate a default copy constructor. The default copy constructor completes the copy according to the byte order of memory storage. This kind of copy is called shallow copy, or value copy.

insert image description here
Note: In the default copy constructor generated by the compiler, the built-in type is directly copied in byte mode, while the custom type is copied by calling its copy constructor.

1.2.4. The default copy constructor generated by the compiler is a shallow copy

insert image description here
insert image description here
Note: If there is no resource application involved in the class, you don’t need to write the copy constructor, just use the default copy constructor; once it involves resource application, the copy constructor must be written, otherwise it is a shallow copy.

1.2.5. Typical calling scenarios of copy constructor

  • Create a new object using an existing object
  • The function parameter type is a class type object
  • The return value type of the function is a class type

insert image description here

insert image description here
When the newly defined class type object is used to accept the return value of the function, the compilation will be optimized, and the copy constructor will only be called once, and two consecutive calls will be combined into one.

In order to improve the efficiency of the program, when passing parameters to general objects, try to use the reference type as much as possible, and use references as much as possible according to the actual scene when returning.

2. Operator overloading

2.1 Asking questions

Compare the size of the date
[If the function is written like this]
insert image description here
insert image description here
When the function is defined, it is not named according to the function, and no comments are added. It is difficult to know what the function is when the function is called, and it is difficult to understand when the function is read again. If the comparison between classes can use > or < symbols, it will be very simple, so this requires the keyword operator of operator overloading.
insert image description here
insert image description here
This way it will be easy to understand

2.2. Operator overloading

Operators can be used for built-in types. Through operator overloading, we can flexibly perform operations on the corresponding results of operators for our custom types, so as to achieve the effect of simplification.

C++ introduces operator overloading 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 and parameter list are similar to ordinary functions.

The function name is: the keyword operator followed by the operator symbol that needs to be overloaded

Function prototype: return value type operator (parameter list)

Notice:

  • New operators cannot be created by linking other symbols: e.g. operator@
  • An overloaded operator must have a class type parameter
  • Operators used for built-in types, whose meaning cannot be changed, for example: built-in integer +, whose meaning cannot be changed
  • When overloaded as a class member function, its formal parameters appear to be 1 less than the number of operands, because the first parameter of the member function is the hidden this
  • insert image description here

Note that the above five operators cannot be overloaded, especially the first one to remember

[Global operator overloading]
insert image description here
[Operator overloading member functions]
insert image description here

2.3. Assignment operator overloading

① Assignment operation overload format

  • Parameter type : const T&, passing by reference can improve the efficiency of parameter passing
  • **Return value type: **T&, return reference can improve the efficiency of return, and the purpose of return value is to support continuous assignment
  • Detect whether you assign a value to yourself (judging whether the address is the same)
  • Return * this: To compound the meaning of continuous assignment
    insert image description here
    ②Assignment operation can only be overloaded as a member function of a class, and cannot be made into a global function
    insert image description here
    Reason: If the assignment operation does not display the implementation, the compiler will generate a default assignment operation overloaded function. At this time, the user implements a global assignment operator overload outside the class, which conflicts with the default assignment operator overload generated by the compiler in the class, so the assignment operator overload can only be a member function of the class.
    ③** If the user does not explicitly define the assignment operator overload, the compiler will generate a default operator overload, which is copied byte by byte in the form of value. **Note: Built-in type member variables are directly assigned, while custom type member variables need to call the operator overload of the corresponding class to complete the assignment.
    insert image description here
    Now that the default assignment operator overloading function generated by the compiler can already complete byte-ordered value copying, do I still need to implement it myself? Of course classes like the Date class are unnecessary. What about the following classes? Try to verify it?
// 这里会发现下面的程序会崩溃掉?这里就需要我们以后讲的深拷贝去解决。
typedef int DataType;
class Stack
{
    
    
public:
	Stack(size_t capacity = 10)
	{
    
    
		_array = (DataType*)malloc(capacity * sizeof(DataType));
		if (nullptr == _array)
		{
    
    
			perror("malloc申请空间失败");
			return;
		}
		_size = 0;
		_capacity = capacity;
	}
	void Push(const DataType& data)
	{
    
    
		// CheckCapacity();
		_array[_size] = data;
		_size++;
	}
	~Stack()
	{
    
    
		if (_array)
		{
    
    
			free(_array);
			_array = nullptr;
			_capacity = 0;
			_size = 0;
		}
	}
private:
	DataType* _array;
	size_t _size;
	size_t _capacity;
};
int main()
{
    
    
	Stack s1;
	s1.Push(1);
	s1.Push(2);
	s1.Push(3);
	s1.Push(4);
	Stack s2;
	s2 = s1;
	return 0;
}

Note: If resource management is not involved in the class, whether the assignment operator can be implemented or not; once resource management is involved, it must be implemented.
insert image description here

Discrimination: Assignment operator overloading function and constructor
Assignment operator overloading: assignment between two existing objects Constructor
: initializing another object with an existing object
insert image description here

2.4. The distinction between pre-++ and post-++

class Date
{
    
    
public:
Date(int year = 1900, int month = 1, int day = 1)
{
    
    
_year = year;
_month = month;
_day = day;
}
// 前置++:返回+1之后的结果
// 注意:this指向的对象函数结束后不会销毁,故以引用方式返回提高效率
Date& operator++()
{
    
    
_day += 1;
return *this;
}
// 后置++:
// 前置++和后置++都是一元运算符,为了让前置++与后置++形成能正确重载
// C++规定:后置++重载时多增加一个int类型的参数,但调用函数时该参数不用传递,编译器
自动传递
// 注意:后置++是先使用后+1,因此需要返回+1之前的旧值,故需在实现时需要先将this保存
一份,然后给this+1
//    而temp是临时对象,因此只能以值的方式返回,不能返回引用
Date operator++(int)
{
    
    
Date temp(*this);
_day += 1;
return temp;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
    
    
Date d;
Date d1(2022, 1, 13);
d = d1++;   // d: 2022,1,13  d1:2022,1,14
d = ++d1;   // d: 2022,1,15  d1:2022,1,15
return 0;
}

Guess you like

Origin blog.csdn.net/zxj20041003/article/details/130407578