[Introduction to C++ Issue 5] Classes and Objects (2)

The 6 default member functions of the class

If there are no members in a class, it is simply called an empty class .

class A1{
    
    };

Is there really nothing in the empty class?
No, when any class does not write anything, the compiler will automatically generate the following 6 default member functions .
insert image description here
Default member function: The member function generated by the compiler without explicit implementation by the user is called the default member function

Features:

Constructor : Mainly completes the initialization work
Destructor : Mainly completes the cleanup work
Copy construction
: It is practical to initialize
and create objects of the same kind and const object to take the address (but these two rarely need to be implemented by yourself)

Constructor

Look at the following classes first, and use

class car
{
    
    
public:
	void print()
	{
    
    
		cout << "车名:" << _name << " 价格:" << _price << endl;
	}
	void Init(const char* name , const char* price)
	{
    
    
		strcpy(_name , name);//写入数据
		strcpy(_price , price);//写入数据
	}
private:
	char _name[20];//车名
	char _price[20];//价格
};
void test8()
{
    
    
	car Byd_q;//定义出对象Byd_q
	Byd_q.Init("比亚迪 秦", "99800");
	Byd_q.print();
}

For the car class, you can fill in the data for the object through the Init public method, but if you call this method to set the information every time the object is created
, it is a bit troublesome
. Can you set the information when the object is created?

The answer is yes, you need to create a constructor yourself and initialize the data in the object according to your own ideas

The constructor is a special member function with the same name as the class name, which is automatically called by the compiler when creating a class type object to ensure that each data member has a suitable initial value, and is called only once in the entire life cycle of the object .

feature

The constructor is a special member function. It should be noted that although the name of the constructor is called construction, the main task of the constructor
is not to open space to create objects, but to initialize objects.

Its characteristics are as follows:

  1. The function name is the same as the class name.
  2. No return value, no need to write the return value type before the function name (neither void)
  3. The compiler automatically calls the corresponding constructor when the object is instantiated.
  4. Constructors can be overloaded. This means that you can initialize objects in multiple ways, and the compiler will call the corresponding constructor according to the parameters you pass.
class car
{
    
    
public:
	car()//无参构造函数
	{
    
    
	
	}

	car(const char* name, const char* price)//带参构造函数
	{
    
    
		strcpy(_name, name);//写入数据
		strcpy(_price, price);//写入数据
	}
	void print()
	{
    
    
		cout << "车名:" << _name << " 价格:" << _price << endl;
	}
	void Init(const char* name , const char* price)
	{
    
    
		strcpy(_name , name);//写入数据
		strcpy(_price , price);//写入数据
	}
private:
	char _name[20];//车名
	char _price[20];//价格
};
void test9()
{
    
    
	car Byd_q;//调用无参构造函数
	car Byd_s("比亚迪 宋", "154800");//调用对应带参构造函数
	Byd_s.print();
	
	// 注意:如果通过无参构造函数创建对象时,对象后面不用跟括号,否则就成了函数声明
	//car Byd_t();
	//会报错warning C4930: 未调用原型函数(是否是有意用变量定义的?)
}

Note : If an object is created through a no-argument constructor, parentheses are not required after the object, otherwise it becomes a function declaration

The result after running:
insert image description here

  1. Constructors without parameters, all default constructors, and constructors automatically generated by the compiler if we don’t write them are all called default constructors, and the default constructor can only have one beginner C++, you may think that only when we don’t
     write , the constructor automatically generated by the compiler is called the default constructor. In fact, this is not the case. The following three types are called default constructors :
     1. We don't write constructors that are automatically generated by the compiler.
     2. A parameterless constructor written by ourselves.
     3. The default constructor written by ourselves.
    All in all, a constructor that can be called without passing parameters is a default constructor.

  2. If the constructor is not explicitly defined in the class, the C++ compiler will automatically generate a default constructor with no parameters. If the user explicitly defines it, the compiler will no longer generate it

Speaking of this, you might think: since the compiler will automatically generate a constructor if we don't write it, then we don't need to write the constructor ourselves. This kind of thinking is wrong.

For example, the following situation:

class car
{
    
    
public:
	void print()
	{
    
    
		cout << "车名:" << _name << " 价格:" << _price << endl;
	}
	void Init(const char* name , const char* price)
	{
    
    
		strcpy(_name , name);//写入数据
		strcpy(_price , price);//写入数据
	}
private:
	char _name[20];//车名
	char _price[20];//价格
};
void test9()
{
    
    
	car Byd_s;//调用默认构造函数
	Byd_s.print();
}

Since there is no custom constructor in the car class above, the Byd_s object uses the default structure, but does not initialize the data. The result of the operation is the constructor mechanism automatically generated by the compiler: 1. The structure automatically generated by
insert image description here
the
 compiler Functions do nothing for built-in types.
 2. For custom types, the compiler will call their own default constructors.

Note: In C++11, a patch has been applied for the defect of non-initialization of built-in type members, that is,
when the built-in type member variables are declared in a class, they can be given default values.

class car
{
    
    
public:
	void print()
	{
    
    
		cout << "车名:" << _name << " 价格:" << _price << endl;
	}
	void Init(const char* name , const char* price)
	{
    
    
		strcpy(_name , name);//写入数据
		strcpy(_price , price);//写入数据
	}
private:
	char _name[20] = "比亚迪 秦";//车名
	char _price[20] = "99800";//价格
};
void test9()
{
    
    
	car Byd_s;//调用默认构造函数
	Byd_s.print();
}

The built-in type member variable can be given a default value when it is declared in the class. When using the default structure of the class, the value of the member variable will be the default value when defining the object.
insert image description here

To sum up : Although the compiler will automatically generate the constructor if we don't write it, the constructor automatically generated by the compiler may not achieve the effect we want, so in most cases we need to write the constructor ourselves .

destructor

concept

Destructor: Contrary to the function of the constructor, the destructor does not complete the destruction of the object itself, and the local object destruction is done by the compiler. When the object is destroyed, it will automatically call the destructor to complete the cleanup of resources in the object.

characteristic

Destructor: It is a special member function, and its characteristics are as follows:
1. The destructor name is the character ~ before the class name.
2. No parameters and no return type.
3. A class can have only one destructor. If not explicitly defined, the system will automatically generate a default destructor.
4. Note: the destructor cannot be overloaded
5. When the object life cycle ends, the C++ compilation system automatically calls the destructor

class A
{
    
    
	public:
		A()
		{
    
    
			int* cur = (int*)malloc(sizeof(int) * 2);//申请内存
			assert(cur);
			pp = cur;
			cout << "申请内存\n";
		}
		~A()
		{
    
    
			free(pp);//释放内存
			cout << "释放内存\n";
		}
private:
		int* pp;
};
void main()
{
    
    
	A d1;
}

The running results are as follows, because the destructor will be called automatically after the scope of the local variable d1 ends.
insert image description here
5. Regarding the destructor automatically generated by the compiler, will something be done?
In the following program, we will see that the default destructor generated by the compiler calls its destructor for the self-defined type members.

class A
{
    
    
	public:
		A()
		{
    
    
			int* cur = (int*)malloc(sizeof(int) * 2);//申请内存
			assert(cur);
			pp = cur;
			cout << "申请内存\n";
		}
		~A()
		{
    
    
			free(pp);//释放内存
			cout << "释放内存\n";
		}
private:
		int* pp;
};
class B
{
    
    
public:

	A S1;
};
int main()
{
    
    
	B d1;
	return 0;
}

The operation is as follows
insert image description here
Built-in type members do not need to be cleaned up when they are destroyed, and finally the system can directly reclaim their memory;
and there is an object of class A in B in the above figure, so when B is destroyed, its destructor will call its custom type in this class the destructor function;

Summary: If there is no resource application in the class, the destructor can be omitted, and the default destructor generated by the compiler can be used directly, as shown in class A above; when there is a resource application, the destructor must be written and the corresponding memory should be released. Otherwise it will cause a resource leak

copy construction

In a certain situation, we may need to copy an identical object to use, so as not to destroy the data of the original 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

feature

  1. The copy constructor is an overloaded form of the constructor.

  2. There is only one parameter of the copy constructor and it must be a reference to a class type object . Note: If the method of passing by value is used, the compiler will report an error directly, because it will cause infinite
    insert image description here
    recursive calls .
    Because the parameter is passed by value, the formal parameter is a copy of the actual parameter. To copy the object, it needs to call the copy construction, but the parameter of the copy construction may call the copy construction when passing the parameter by value, so it will call itself infinitely recursively!

  3. If not explicitly defined, the compiler will generate a default copy constructor. The default copy constructor object is copied in byte order according to memory storage. This kind of copy is called shallow copy, or value copy.
    As shown below:insert image description here

How to customize copy construction

Note:
1: 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.
2: If there is no resource application involved in the class, the copy constructor can be written or not; once the resource application is involved, the copy constructor must be written, otherwise it is a shallow copy

Error demonstration:
insert image description here
Error reasons:
1: The default copy construction is to copy by byte, so the _number of c2 points to the same address of the _number of c1
2: This will cause the same address to be destructed twice during destructuring, thus reporting error
3: When using, the two data will overwrite each other, delete, etc., because two different objects are operating the same address

When there is a memory application, the custom copy constructor will deep copy the data , re-apply for the space as shown in the figure below, and copy the data into the new space
insert image description here
Typical call scenarios of the copy constructor:
1: Create a new object using an existing object
2 : The function parameter type is a class type object
3: The function return value type is a class type object

Note: Classes belong to custom types and generally objects are relatively large. Therefore, in order to improve program efficiency, when passing parameters to general objects, try to use reference types. When returning, use references as much as possible according to the actual scene.

operator overloading

assignment operator overloading

In order to enhance the readability of the code, operator overloading is introduced. Operator overloading is a function with a special function name, and also has its return value type, function name and parameter list. Its return value type and parameter list are similar to ordinary functions.

For example, the following is an overload of "=" :

  bool operator==(Date& d1){
    
    
        if (d1._year = _year && d1._mouth == _mouth && d1._day == _day){
    
    
            return true;
        }
        return false;
    }

The function name is: the keyword operator followed by the operator symbol that needs to be overloaded.
Function prototype: return value type operator operator (parameter list)

Note:
1: New operators cannot be created by connecting other symbols: for example, operator@ overloaded operator must have a class type parameter
2: The meaning of the operator used for built-in types cannot be changed, for example: built-in integer +, cannot change its meaning
3: When overloaded as a class member function, its formal parameters seem to be 1 less than the number of operands, because the first parameter of the member function is the hidden this
4: 【 .* 】【 :: 】 【 sizeof 】【 ? : 】 【 . 】 Note that the above 5 operators cannot be overloaded.

assignment operator overloading

1: Assignment operator overload format
1: Parameter type: const T&, passing reference can improve the efficiency of parameter passing
2: Return value type: T&, returning reference can improve the efficiency of returning, the purpose of returning value is to support continuous assignment
3: Check whether Assign value to yourself
4: Return *this: To compound the meaning of continuous assignment,
the code is as follows:

Date& operator=(const Date& d)
{
    
    
	if(this != &d)
	{
    
    
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
	return *this;
}

Two: The assignment operator can only be overloaded as a member function of a class and cannot be overloaded as a global function

Reason: If the assignment operator is not explicitly implemented, the compiler will generate a default one. At this time, if the user implements a global assignment operator overload outside the class, it will conflict 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.

Three: When the user does not explicitly implement, the compiler will generate a default assignment operator overload, which is copied byte by byte in the form of value.
Note:
1: Built-in type member variables are directly assigned
2: If resource management is not involved in the class, the assignment operator can be implemented or not; once resource management is involved, deep copy must be implemented.

pre++ and post++ overloads

// 前置++:返回+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;
}

Address and const address operator overloading

class Date
{
    
    
public :
	Date* operator&()
	{
    
    
		return this;
	}
	const Date* operator&()const
	{
    
    
		return this;
	}
private :
	int _year ; // 年
	int _month ; // 月
	int _day ; // 日
};

These two operators generally do not need to be overloaded , just use the default address overload generated by the compiler. Only in special cases, overloading is required, such as wanting others to obtain the specified content!

Guess you like

Origin blog.csdn.net/ZhuGeBin26/article/details/130462130