C + + empty class
What are the default constructors for C + + empty classes?
class Empty { public: Empty(); // Default constructor Empty( const Empty&); // Copy constructor ~Empty(); // Destructor Empty& operator=( const Empty&); // Assignment operator Empty* operator&(); // Addressing operator const Empty* operator&() const; // Addressing operator const };
1, Explain
Constructors, destructors and assignment functions are the most basic functions of each class. They are so common that people are easy to be careless. In fact, these seemingly simple functions need to be studied more deeply.
Each class has only one destructor and one assignment function, but it can have multiple constructors (including a copy constructor, others are called ordinary constructors). For any class A, if you do not want to write the above functions, the C + + compiler will automatically generate four default functions for a, such as
A(void); / / default parameterless constructor
A(const A &a); / / default copy constructor
~A(void); / / default destructor
A & operate =(const A &a); / / default assignment function
This can not help but make people wonder, since it can automatically generate functions, why should programmers write them?
The reasons are as follows:
(1) if "default parameterless constructor" and "default destructor" are used, the opportunity of autonomous "initialization" and "cleanup" is abandoned, and the good intentions of C + + inventor Stroustrup are in vain.
(2) "default copy constructor" and "default assignment function" are implemented in the way of "bit copy" rather than "value copy". If the class contains pointer variables, these two functions are bound to make mistakes.
Take the class String as an example,
// The structure of String is as follows class String { public: String(const char *str = NULL); // Normal constructor String(const String &other); // copy constructor ~ String(void); // Destructor String & operate =(const String &other); // Assignment function private: char *m_data; // Used to save strings };
//The normal constructor and destructor of String are as follows:
// Constructor for String String::String(const char *str) { if (str == NULL) { m_data = new char[1]; *m_data = '\0'; } else { int length = strlen(str); m_data = new char[length + 1]; strcpy(m_data, str); } } // Destructor of String String::~String(void) { if (m_data) { // Due to m_data is an internal data type and can also be written as delete m_data; delete [] m_data; } }
II. Source of constructor and destructor
As a more advanced language than C, C + + provides a better mechanism to enhance the security of programs. C + + compiler has strict type safety check function. It can find almost all syntax problems in the program, which is really a great help to programmers. However, the fact that the program has passed the compilation check does not mean that the error no longer exists. In the big family of "errors", the status of "syntax errors" can only be regarded as a little brother. High level mistakes are usually hidden deeply, just like a cunning criminal. It's not easy to catch him.
According to experience, many imperceptible program errors are caused by variables that are not initialized or cleared correctly, and initialization and clearing are easy to be forgotten. Stroustrup fully considered this problem when designing C + + language and solved it well: put the object initialization in the constructor and the cleanup in the destructor. When an object is created, the constructor is executed automatically. When the object dies, the destructor is executed automatically. In this case, you don't have to worry about forgetting the initialization and cleaning of objects.
Constructors and destructors cannot be named casually. They must be recognized by the compiler before they can be executed automatically. The naming method of Stroustrup is simple and reasonable: let the constructor and destructor have the same name as the class. Because the purpose of the destructor is opposite to that of the constructor, prefix '~' to show the difference.
In addition to the name, another special feature of constructors and destructors is that they do not have a return value type, which is different from functions with a return value type of void. The mission of constructors and destructors is very clear, just like birth and death. If they have return value types, the compiler will be overwhelmed. To prevent extraneous branches, simply specify that there is no return value type.
3, Constructor initialization list
Constructor has a special initialization method called "initialization expression table" (initialization table for short). The initialization table is after the function parameter table, but before the function body {}. This means that the initialization in this table occurs before any code in the function body is executed.
Rules for using constructor initialization table:
1. If the class has an inheritance relationship, the derived class must call the constructor of the base class in its initialization table.
For example
class A { A(int x); // Constructor of A }; class B : public A { B(int x, int y); // Constructor of B }; B::B(int x, int y) :A(x) // Call the constructor of A in the initialization table { }
2. The const constant of a class can only be initialized in the initialization table because it cannot be initialized by assignment in the function body
3. Class data members can be initialized in two ways: initialization table or function body assignment. The efficiency of these two methods is not exactly the same
3.1 initialization of Non internal data type members
Member objects of Non internal data types should be initialized in the first way to obtain higher efficiency. For example
class A {... A(void); // Parameterless constructor A(const A &other); // copy constructor A & operate =( const A &other); // Assignment function }; class B { public: B(const A &a); // Constructor of B private: A m_a; // member object };
Initialization method 1: initialized in the initialization list
B::B(const A &a) : m_a(a) { //Other initialization operations }
Note: the constructor of class B calls the copy constructor of class A in its initialization table, so that the member object m_a initialization.
Initialization method 2: the constructor is initialized
B::B(const A &a) { m_a = a; //Other initialization operations }
Note: the constructor of class B assigns a value to the member object m in the function body_ A initialization. All we see is an assignment statement, but in fact, the constructor of B does two things: first, secretly create m_a object (calling the parameterless constructor of a), and then calling the assignment function of class A to assign parameter a to m_a.
3.2 initialization of internal data type members
For data members of internal data types, the efficiency of the two initialization methods is almost the same, and the program layout of the former and the latter seems clearer. If class F is declared as follows:
class F { public: F(int x, int y); // Constructor private: int m_x, m_y; int m_i, m_j; }
Initialization method 1: initialization list
F::F(int x, int y) : m_x(x) , m_y(y) , m_i(0) , m_j(0) { //Other initialization actions }
Initialization method 2: constructor
F::F(int x, int y) { m_x = x; m_y = y; m_i = 0; m_j = 0; }
The member initialization method of internal data type recommended by individuals adopts method 1.
4, Call order of constructors and destructors
The structure starts at the root of the class hierarchy, in each layer, first calls the constructor of the base class, and then calls the constructor of the member object. Destruct is executed strictly in the reverse order of construction, which is unique, otherwise the compiler will not be able to automatically execute the destruct process.
An interesting phenomenon is that the initialization order of member objects is not affected by their order in the initialization table, but only determined by the order in which member objects are declared in the class. This is because the class declaration is unique, and the class constructor can have multiple, so there will be multiple initialization tables in different order. If the member objects are constructed in the order of the initialization table, the destructor will not get a unique reverse order.