Constructor
concept
class Date{ public: void SetDate(int year, int month, int day){ _year = year; _month = month; _day = day; } void Display(){ cout <<_year<< "-" <<_month << "-"<< _day <<endl; } private: int _year; int _month; int _day; }; int main(){ Date d1; d1.SetDate(2018,5,1); d1.Display(); Date d2; d2.SetDate(2018,7,1); d2.Display(); return 0; }
looking at the above functions, we can find that if each object needs to call the member function after it is created, it will be very troublesome. What can we do to solve it?
we can use the constructor to solve this problem. The constructor is a special member function with the same name as the class name. It is automatically called by the compiler when we create the object to ensure that each data member has an appropriate initial value and is only called once in the life cycle of the object.
characteristic
- The function name is the same as the class name;
- No return value;
class Date{ public: //Constructor, the same as the class name, with no return value Date(int year, int month, int day){ _year = year; _month = month; _day = day; } private: int _year; int _month; int _day; };
- Constructors can be overloaded. When an object is instantiated, the compiler automatically calls the corresponding constructor;
class Date{ public : //1. Parameterless constructor Date (){} //2. Constructor with parameters 1 Date (int year, int month, int day ){ _year = year ; _month = month ; _day = day ; } //3. Constructor with parameters 2 Date (int year, int month, int day, int num){ _year = year ; _month = month ; _day = day ; } private : int _year ; int _month ; int _day ; }; void TestDate(){ Date d1; //Call parameterless constructor Date d2 (2015, 1, 1); //Call constructor with parameters 1 Date d3 (2015, 2, 2, 520);//Call the constructor with parameters 2 //Note: if you create an object through a parameterless constructor, the object does not need to be followed by parentheses, otherwise it becomes a function declaration //The function of the following code: it declares the d3 function, which has no parameters and returns an object of date type Date d4(); }
- If the constructor is not explicitly defined in the class, the C + + compiler will automatically generate a parameterless default constructor. Once the user explicitly defines the constructor, the compiler will no longer generate it;
- The parameterless constructor, the full default constructor, and the constructor generated by default without writing the compiler are all called the default constructor, but there can only be one default constructor;
class Date{ public: //Parameterless constructor Date(){ _year = 1900 ; _month = 1 ; _day = 1; } //Full default constructor Date (int year = 1900, int month = 1, int day = 1){ _year = year; _month = month; _day = day; } private : int _year ; int _month ; int _day ; }; void Test(){ //Only one of the above two constructors can be saved, otherwise there will be ambiguity when instantiating a parameterless object, and an error will be reported below Date d1; }
- In C + +, types are divided into built-in types (basic types) and custom types. A built-in type is a type whose syntax has been defined; Custom type is the type defined by class/ struct/ union. When the member variable of our class has a custom type, after instantiating an object, when calling the constructor, the constructor will call their corresponding constructor for the custom type;
class Time{ public: Time(){ cout << "Time()" << endl; _hour = 0; _minute = 0; _second = 0; } private: int _hour; int _minute; int _second; }; class Date{ private: // Basic type (built-in type) int _year; int _month; int _day; // Custom type Time _t; }; int main(){ Date d; return 0; }
- The calling order of the constructor of class is: the global object is constructed after the local object, and the static object is constructed after the ordinary object;
Destructor
concept
the destructor has the opposite function of the constructor, but the destructor does not destroy the object (the destruction of local objects is generally completed by the compiler), but the object will automatically call the destructor to clean up some resources of the object when it is destroyed, such as the memory space manually opened by malloc. These are the resources that the destructor needs to clean up;
characteristic
- The destructor name is preceded by the character ~;
- Destructor has no parameters and no return value;
//Define a sequence table class typedef int DataType; class SeqList{ public : //Destructor, which is mainly used to clean up the resource space occupied by the class ~SeqList() {//Resource cleanup}
- A class has only one destructor. If it is not explicitly defined, the system will automatically generate a default destructor;
- At the end of the object life cycle, the C + + compilation system will automatically call the destructor;
//Define a sequence table class typedef int DataType; class SeqList{ public : //Constructor SeqList (int capacity = 10){ //Manually open up memory space _pData = (DataType*)malloc(capacity * sizeof(DataType)); //If the space application fails, it will exit the program assert(_pData); _size = 0; _capacity = capacity; } //Destructor, which is mainly used to clean up the resource space occupied by the class ~SeqList(){ if (_pData){ free(_pData ); // Free up space on the heap _pData = nullptr; // Set pointer to null _capacity = 0; _size = 0; } } private : int* _pData ; size_t _size; size_t _capacity; };
- Destructors are the same as constructors. When the system calls constructors, destructors will first call their destructors for custom types;
- The destructor of class is called in the reverse order of constructor call. The global object is constructed before the local object, and the static object is constructed before the ordinary object;
copy constructor
concept
the copy constructor has only a single formal parameter, which is a reference to the object of this class type (const modification is commonly used, and we will talk about why to use reference later). It is automatically called by the compiler when creating a new object with an existing class type object;
characteristic
- Copy constructor is an overloaded form of constructor;
- There is only one parameter of the copy constructor, and the parameter must be passed by reference. Using the value passing method will cause infinite recursive call. The following figure shows the error result, and the code below is the correct writing method;
class Date{ public: //Constructor Date(int year = 1900, int month = 1, int day = 1){ _year = year; _month = month; _day = day; } //Copy constructor, which is overloaded with constructor //Parameter is a class object reference Date(const Date& d){ year = d._year; _month = d._month; _day = d._day; } private: int _year; int _month; int _day; }; int main(){ Date d1; //The usage method is that when defining an object, the contents in parentheses are the object to be copied Date d2(d1); return 0; }
- If the definition is not displayed, the system generates a default copy constructor, which will simply and directly assign a copy to the member variable. This copy is called shallow copy or value copy. Whether written by yourself or generated by the system, the copy constructor of the user-defined type will be called automatically when the user-defined type is encountered.
- When we implement the object copy of a simple class, we can use the system generated copy constructor instead of implementing the copy constructor ourselves. However, if there are member variables of resource allocation, then using the system generated copy constructor will make an error. The following code makes an error for this reason;
in the following code, the object s1 applies for a space to store "hello" content. Assuming that the first address of the space is 0X11, then s1_ str = 0x11; At this time, the copy constructor s2 is constructed. Since we do not display and define the copy constructor, the system will automatically generate it, and then directly copy the content of s1 to s2, so s2_ str = 0x11; After the end of the object life cycle, the system automatically calls the destructor, first execute free(s2._str), and then execute free(s1._str). Then the problem comes. At this time, the 0X11 space is released twice. The first time, 0X11 does not belong to us. When the second time, there will be a problem. In the future, we can solve it through deep copy;
class String{ public: //Constructor String(const char* str = "jack"){ _str = (char*)malloc(strlen(str) + 1); strcpy(_str, str); } //Destructor ~String(){ cout << "~String()" << endl; free(_str); } private: char* _str; }; int main(){ String s1("hello"); //Use the existing s1 object to copy and construct a new s2 object String s2(s1); }
Operator overloading
concept
I believe we all know that function overloading means that functions with the same name and different parameters perform different operations. In C + +, operators can also be overloaded. For example, in our date class, when we want to compare the sizes of two dates, we can't compare them directly by using the greater than or less than sign. At this time, we can overload the operator and write the comparison rules in the function, In this way, we can use operators to compare custom types;
the keyword operator needs to be used in operator overloading. The syntax is as follows:
return type operator operator(Parameter 1, Parameter 2, ...){ //Operation performed }
matters needing attention
- You cannot create new operators by connecting other symbols. You can only overload existing legal operators: for example, operator @ is wrong;
- Overloaded operators must have an operand of class type or enumeration type;
- The meaning of built-in type operators cannot be changed. For example, the meaning of built-in integer + cannot be changed to make it an operator for subtraction;
- When an overloaded function is a class member, its formal parameter is one less than the operand, because the member function has a default formal parameter this, which is limited to the first parameter, and the this pointer points to the calling object or the first operand from left to right;
- .*,::,sizeof,?:,., Note that the above five operators cannot be overloaded. This is a rule. There is no reason;
- The operator overload defined in the global cannot call the member variable in the private. What should I do? We can solve it after we learn friends;
- The following is a date class. There is a comparison operator overload in the class, so that it can compare whether two dates are equal:
class Date{ public: //Full default constructor Date(int year = 1900, int month = 1, int day = 1){ _year = year; _month = month; _day = day; } // It should be noted here that this refers to the object calling the function or the first operand from left to right // bool operator==(Date* this, const Date& d2) bool operator==(const Date& d2){ //The operation here is actually this - >_ year == d2._ year return _year == d2._year && _month == d2._month && _day == d2._day; } private: int _year; int _month; int _day; }; void Test (){ Date d1(2018, 9, 26); Date d2(2018, 9, 27); //Normal call cout<< d1.operator==(d2) << endl; //This is a short form. The this pointer automatically points to the first operand from left to right cout<< d1 == d2 << endl; }
- When we overload the pre addition and post addition, we will find that they cannot be overloaded, because the two functions have the same name, the same parameters and different return values. In this case, we can do the following:
//Take the date class as an example //Pre addition, no parameter, this pointer points to the calling object or operand //Returns a reference to an object. This is because pre addition returns the result after addition, so reference can be used date& operator++(){ //content } //Post plus, with parameters, but without passing any parameters, the compiler will automatically recognize that this pointer points to the calling object or operand //Return a copy of an object. Since the latter is used first and then added, it is necessary to define a temporary object to save the content not added and return it. We do not have access to the temporary variable, so we cannot use the reference date operator++(int){ //content }
Assignment operator overload
when we want to assign the content of d2 to d1 after defining d1 and d2 objects, can they be realized? It has been verified that it is OK, because in C + + classes, there is an overloaded function of assignment operator. Its function is to assign all the values of one class to another class. This function can display the definition of, or be automatically generated by the system; The code is as follows:
class Date{ public : //Constructor Date(int year = 1900, int month = 1, int day = 1){ _year = year; _month = month; _day = day; } //copy constructor Date (const Date& d){ _year = d._year; _month = d._month; _day = d._day; } //Assignment operator overload Date& operator=(const Date& d){ if(this != &d){ _year = d._year; _month = d._month; _day = d._day; } } private: int _year ; int _month ; int _day ; };
- The member function has only one parameter, and the other is the default this pointer, which points to the called object or the first operand from left to right;
//Assign the value of d2 to d1 //Complete writing d1.operator=(d2); //Simplified writing d1 = d2;
- The return value of the function is a reference to an object. In this way, chain assignment can be performed, as follows:
//First assign the value of d3 to d2, and then return the reference of an object //Whether d2 or d3 is returned, it is equal, and then assigned to d1 d1 = d2 = d3;
- You can do a small optimization in the function. When the address of this pointer and parameter are the same, it means that an object is assigned to itself, which can be skipped and not executed;
- In fact, assignment operator overloading is almost the same as copy constructor. Assignment operator overloading is to assign the value of an object to another existing object, and copy constructor is to create a new object with the value of an object;
- When we don't define the overloaded function of assignment operator, the system will automatically generate one, but note that when there are resources in the object, we can't directly use the function automatically generated by the system, because there will be errors, and the reason is the same as that of copying constructor;
const and fetch address
const modifier class member function
call the class member function modified by const as const member function; Const modifies the class member function. In fact, it modifies the implicit this pointer of the member function, indicating that no member of the class can be modified in the member function. In other words, on the basis of the type of pointer constant class * const this, it becomes the type of constant pointer constant const class * const this, which means that neither the pointing nor the pointing content can be modified.
the method is as follows:
class Date{ public : void Display(){ cout<< "Display()" << endl; cout<< "year:" << _year << endl; cout<< "month:" << _month << endl; cout<< "day:" << _day << endl; } //Write const after the function void Display() const{ cout<<"Display() const" << endl; cout<< "year:" <<_year<< endl; cout<< "month:" <<_month<< endl; cout<< "day:" <<_day << endl; } private : int _year ; // year int _month ; // month int _day ; // day }; void Test (){ Date d1; d1.Display(); const Date d2; d2.Display(); }
matters needing attention
- Const objects cannot call non const member functions;
- Non const objects can call const member functions;
- Other non const member functions cannot be called in const member functions;
- Other const member functions can be called in non const member functions;
Address fetching operation
in the class, we don't need to care about the address fetching function with or without const modification. The system will automatically generate two default address fetching overloaded functions; Because if we operate manually, it is easy to cause errors. For example, if we return an unknown address instead of the address pointed to by this pointer, it will cause undefined behavior. What's more, if we return the entry address of a virus, it will cause serious consequences.
class Date{ public : Date* operator&(){ //It is easy to make mistakes here. If any one of them can be returned, it is easy to cause vulnerabilities to the Trojan virus return this; } const Date* operator&()const{ //It is easy to make mistakes here. If any one of them can be returned, it is easy to cause vulnerabilities to the Trojan virus return this; } private : int _year ; // year int _month ; // month int _day ; // day };