Six default member functions for classes
If there is no member in a class, it is simply an empty class. Nothing in the empty class? No, any of the classes will automatically generate the following six default member functions if we don't write them.
Constructor
concept
For the following date classes:
class Date { public: void Init(int year, int month, int day) { _year = year; _month = month; _day = day; } void Print() { cout << _year << "-" << _month << "-" << _day << endl; } private: int _year; int _month; int _day; }; int main() { Date d1; d1.Init(2020, 10, 9); d1.Print(); return 0; }
For the Date class, you can set the content of the object through the SetDate public method, but if it is a little cumbersome to call this method to initialize information every time an object is created, can you set the information in it when the object is created?
The constructor is a special member function with the same name as the class. It is called automatically by the compiler when creating a class type object, ensuring that each data member has an appropriate initial value and is called only once during the object's life cycle.
Characteristic
Constructors are special member functions. It is important to note that although the name of a constructor is construction, it is important to note that the main task of a constructor is not to create objects in open space, but to initialize them.
The features are as follows:
- The function name is the same as the class name.
- No return value.
- The compiler automatically calls the corresponding constructor when the object is instantiated.
- Constructors can be overloaded.
class Date { public: //1. parameterless constructors Date() {} //2. Constructor with parameters Date(int year, int month, int day) { _year = year; _month = month; _day = day; } private: int _year; int _month; int _day; }; int main() { Date d1; //Call parameterless constructor Date d2(2021, 10, 9);//Calling a parameterized constructor //Note: If you create an object through a parameterless constructor, the object is not followed by parentheses, otherwise it becomes a function declaration //A function of the following code: declares the d3 function, which has no parameters and returns an object of type date Date d3(); }
- If no constructor is explicitly defined in the class, the C++ compiler automatically generates a default constructor with no parameters, and once the user explicitly defines the compiler, it will no longer generate.
class Date { public: //If the user shows that a constructor is defined, the compiler will no longer generate /*Date(int year, int month, int day) { _year = year; _month = month; _day = day; }*/ private: int _year; int _month; int _day; }; int main() { //Objects can also be created successfully without a constructor defined, so the default constructor generated by the compiler is called here Date d; return 0; }
- Both parameterless and full default constructors are called default constructors, and there can only be one default constructor. (It could have constituted a function overload, but they both have ambiguities, Date d; the compiler doesn't know who to call.) Note that parameterless constructors, default constructors, and constructors that we don't write the compiler's default build can all be considered default member functions (which can be called without passing parameters). Constructors generated by default by the compiler can also be constructors we write in custom classes
//Default constructor class Date { public: /*Date() { _year = 1900; _month = 1; _day = 1; }*/ //Generally, it is recommended that you write a completely default constructor directly because it is very useful Date(int year = 1900, int month = 1, int day = 1) { _year = year; _month = month; _day = day; } private: int _year; int _month; int _day; };
With respect to default member functions generated by the compiler, the compiler generates default constructors when we do not implement them. But does the default constructor seem useless? The d object calls the compiler-generated default constructor, but the d object year/month/_day, it's still a random value. What is the use of the default constructor generated by the compiler here?
Answer: C++ classifies types into built-in types (basic types) and custom types. Built-in types are those whose syntax has been defined: int/char..., custom types are those we define using class/struct/union. Looking at the program below, you will see that the compiler generates a default constructor that will call its default member function on member A of the custom type.
class A { public: A()//Must have no parameters { _a1 = 0; _a2 = 1; cout << "A()" << endl; } private: int _a1; int _a2; }; class Date { private: //Built-in type int _year; int _month; int _day; //Custom type struct/class A _aa; }; int main() { Date d1; return 0; }
As you can see here, this eccentric processing makes the grammar more complex, but it cannot be changed because it is forward compatible. At C++11, the grammar Committee patched this.
class Date { private: //Built-in type int _year=0; int _month=1; int _day=1; //Custom type struct/class A _aa; };
Here the member variable is just a definition, not an initialization. Just like function default parameters, default values are given.
Naming style for member variables:
// Let's look at this function, is it stiff? class Date { public: Date(int year) { // Is year a member variable or a function parameter here? year = year; } private: int year; }; // So you can usually write like this class Date { public: Date(int year) { _year = year; } private: int _year; };
According to the principle of local priority, year=year; The year on the left looks for year in the parameter and finds that it is the function parameter. You can also add this before year, this->year=year; In this way, year is the year of the member variable when the object is instantiated.
Destructor
concept
We know how an object comes from, and what about that object?
Destructor: Contrary to the constructor function, a destructor does not complete the destruction of an object. Local object destruction is done by the compiler. When an object is destroyed, the destructor is called automatically to clean up some resources of the class.
A class like Date does not need a destructor because there are no resources inside it to clean up.
Characteristic
Destructors are special member functions.
The features are as follows:
- The destructor name is preceded by the class name with the character ~.
- No parameter, no return value.
- A class has and only one destructor. Default destructors are automatically generated if not explicitly defined.
- At the end of the object life cycle, the C++ compilation system automatically calls the destructor.
- Default destructor generated by the compiler that calls its destructor on members of a custom type.
class Stack { public: Stack(int capacity = 4) { _a = (int*)malloc(sizeof(int) * capacity); if (_a == nullptr) { cout << "malloc fail" << endl; exit(-1); } _top = 0; _capacity = capacity; } ~Stack() { //Classes like Stack, where resources in objects need to be cleaned up, use destructors free(_a); _a = nullptr; _top = _capacity = 0; } private: int* _a; int _top; int _capacity; }; int main() { Stack st; return 0; }
In our implementation queue with two stacks, MyQueue does not have to write a constructor so that the constructor and destructor automatically generated by the compiler can accomplish the task.
class MyQueue { private: Stack _pushST; Stack _popST; }; int main() { //Stack st; MyQueue mq; return 0; }
copy constructor
concept
Constructor: Only a single parameter, which is a reference to an object of this type (commonly used const modifier), is called automatically by the compiler when a new object is created with an object of an existing class type.
Features
Copy constructors are also special member functions that are characterized by the following:
- Copy constructors are an overloaded form of constructors.
- Copy constructors have only one parameter and must use reference passes, which can cause infinite recursive calls.
class Date { public: Date(int year = 1900, int month = 1, int day = 1) { _year = year; _month = month; _day = day; } 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; }
- If the definition is not displayed, the system generates a default copy constructor. The default copy constructor object completes the copy in byte order by memory storage, which is called a shallow copy, or a value copy.
We don't write, and the copy constructs generated by the compiler by default are different from constructs and destructions. It does not distinguish between built-in types and custom type members and handles both.
1. Built-in type, shallow copy in byte order (copy in byte order, just like memcpy).
2. Custom type, which calls its copy construction to complete the copy.
class Date { public: Date(int year = 1900, int month = 1, int day = 1) { _year = year; _month = month; _day = day; } private: int _year; int _month; int _day; }; int main() { Date d1; Date d2(d1); return 0;
So the default copy constructor generated by the compiler is ready to copy the byte order values. Do we need to do it ourselves? Of course, classes like the date class are unnecessary.
Take the stack above for example, Stack st1; Stack st2(st1);
Compiler will error