Chapter 2 structure, structure and copy Semantics
5.0 IntroductionA pure virtual function can be defined and called, but can only be called statically. It cannot be called through a virtual mechanism, for example, class required actbase {public: Virtual void interface () const = 0 ;}; inline void merge actbase: interface () const {...... } Class concretderived: Public abstractbase {public: void interface () const;}; inline void concretderived: interface () const {abstractbase: interface ();//......} But whether to do this depends on the class designer. But for pure virtual destructor, the class designer must define it, because every derived class destructor will be extended by the compiler, to call the destructor of each of its "virtual base classes" and "previous base classes" in the form of static calls, as long as there is no definition of any basic class destructor, the link will fail. Otherwise, do not declare the virtual destructor as pure virtual. [This is not a good note. You should follow the questions in the book to solve the problem]
5.1 object construction without inheritance
5.1.1 plain oi 'data formatThe following point (first version) is declared. It is called plain oi 'data declaration form in the C ++ standard: typedef struct {float _ x, _ y, _ z;} Point; during compilation, the compiler declares a trivial default constructor for point, a trivial destructor, a trivial copy constructor, and a trivial copy assignment operator, the address fetch operator and its const six member functions. But in fact, the compiler analyzes this declaration and attaches the plain oi 'data tag to it. When the compiler encounters the following definition of point global, both constructor and destructor are generated and called, that is, the constructor is at the beginning of the program, and the Destructor is called at exit () (exit () is generated by the system and placed before the end of main). However, in fact, if trivial members are neither defined nor called, the program acts as it does in C. For point * heap = new point; the compiler converts it to point * heap = _ new (sizeof (point )); note that no default constructor is implemented on the point object returned by the new operator. In addition, the copy constructor, value assignment operator, and destructor are all the same and are not called. They only involve some simple bit copy operations. [It seems that plain oi 'data is applicable to the struct form of C]
5.1.2 ADT form (excluding virtual functions)Rewrite plain oi 'data to the following adt form without virtual functions: Class Point {public: Point (float x = 0.0, float y = 0.0, float z = 0.0 ): _ x (x), _ y (Y), _ z (z) {}// no other copy constructor, copy operator or destructor private: Float _ x; float _ y; float _ z;}; the class size is not changed after the above encapsulation, because the access permissions for private, public, and protected, or the declaration of member functions, will not occupy additional object space. Now define point global; the default constructor will be called. The point * heap = new point is appended as a "Call operation with conditions for the default constructor": Point * heap = _ new (sizeof (point )); if (heap! = 0) Heap-> point: Point (); For Delete heap, The Destructor is not called because an destructor entity is not explicitly provided.
5.1.2 ADT form (including virtual functions)To Inherit and polymorphism, rewrite the above adt to the following class definition with virtual functions: Class Point {public: Point (float x = 0.0, float y = 0.0 ): _ x (x), _ y (y) {}// no other copy constructor, copy operator or destructor virtual float Z (); protected: Float _ x; float _ y ;}; point global; point foobar () {Point local; point * heap = new point; * heap = Local; Delete heap; return local ;} changes brought about by introduction of virtual functions: 1. each point object has a vptr pointing to the class vtbl. This pointer provides the elasticity of the Virtual Interface, but makes every object need an additional pointer. Space; 2. so that the class point definition will generate the following expansion: ① The defined constructor is appended with some code to initialize the vptr. The code is attached to the call of any base class constructor, but before any user-defined code: Point * point: Point (point * This, float X, float y): _ x (x), _ y (y) {This-> _ vptr_point = _ vtbl_point; this-> _ x = x; this-> _ y = y; return this ;} ② synthesize a copy constructor and a copy assignment operator, and its operation is no longer trivial, but the implicit destructor is still trivial, in this case, location-based operations may bring illegal settings to vptr. Inline point * point: Point (point * This, const point & RHs) {This-> _ vptr_point = _ vtbl_point; this-> _ x = RHS. x; this-> _ y = RHS. y; return this;} 3. after virtual functions are introduced, the operation will also change. ① for point global; and point * heap = new point; for global object initialization and non-virtual functions with the same heap object as ADT, the default constructor is called; ② The delete heap operation for releasing the heap object does not define the Destructor entity, so the same as above will not call the Destructor; ③ for * heap = local; the copy assignment operator of the internal synthesis will be triggered; ④ for return local; to return a local object by passing the value, the merged copy constructor will be called, namely: point foobar (point & _ result) {poi NT Local; local. Point: Point (0.0, 0.0); _ result. Point: Point (local); Local. Point ::~ Point (); // return if defined or synthesized ;}
5.2 Object Construction in the inheritance system
5.2.1 constructor expansion OverviewFor defining an object: t object; if T has a constructor (whether provided by the user or synthesized by the compiler), it will be called, and according to the inheritance system of class t, the compiler may perform the following expansion operations: 1. data member initialization operations recorded in the member initialization list will be put into the constructor itself, and the order of member declarations will be taken as the order; 2. if a member does not appear in the member initialization list but has a default constructor, the default constructor is called. 3. before that, if the class object has vptr, the initial value must be set to point to the appropriate vtbl; 4. before that, all the base class constructors at the previous layer were called in the declared order of the base class (not associated with the order in the member initialization list ):★If the base class is listed in the member initialization list, any explicitly specified parameter should be passed;★If the base class is not listed in the member initialization list and has a default constructor, the default constructor is called;★If the base class is the second or subsequent base class under multi-inheritance, this pointer must be adjusted; 5. before that, all the virtual base class constructors must be called, from left to right, from deepest to shortest;★If a class is listed in the member initialization list, any explicitly specified parameter should be passed. If it is not listed in the initialization list, but the class has a default constructor, call the constructor;★The offset of each virtual base class subobject in the class can be accessed during the execution period;★If the class object is the underlying class, its constructor may be called, and the mechanism to support this behavior must also be put in.
5.2.2 single non-virtual inheritanceObviously, this is the most simple structure in inheritance. It can be initialized according to the construction sequence of the first base class, then the class member (that is, the member constructor), and then the class itself (User-Defined code.
5.2.2 virtual inheritanceFor virtual inheritance, Because Virtual inheritance is designed to avoid multiple copies of the base class in the derived class, there is no benefit for a single virtual inheritance, instead, it will pay the cost of space and access time. Therefore, we generally only consider the situation of Multi-inheritance. In virtual inheritance, the call of the virtual base class constructor is clearly defined: it is called only when a complete Class Object is defined; if the object is just a subobject of a complete object, it will not be called (for details, see the P211-213 ).
5.2.3 vptr initialization SemanticsIf the call operation is restricted to direct calls in the constructor or destructor, then each call operation will be decided in a static way, no virtual mechanism is used (for details, see the book P214-215 ). The key to determining the virtual function list is the virtual table vtbl, which is processed by vptr. The vptr initialization operation is performed after the base class constructor calls the operation, but before the code supplied by the programmer or the members listed in the member initialization list are initialized, therefore, the execution steps of the constructor after vptr initialization are as follows: 1. in the constructor of a derived class, all constructors of the virtual base class and the previous base class are called. 2. the vptr of the object is initialized, pointing to the related vtbl; 3. if there is a member initialization list, expand it in the constructor; 4. run the custom code.
5.3 object copy Semantics
5.3.1 selection of Class Object assignmentWhen designing a class and assigning an object of the class to another class object, there are three options: 1. do nothing. Implement the default behavior, that is, copy semantics of memberwise in concept and bitwise in implementation; 2. provide an explicit copy assignment operator; 3. explicitly deny the assignment operation. You can declare the copy assignment operator as private without providing a definition. Because it is declared as private, it is no longer allowed to assign values in any location (except for member functions and friends). If it is not defined, once a member function or friend attempts to affect a copy, the program fails to be linked.
5.3.2 meaning of copy assignmentBitwise copy is sufficient and efficient by default because only simple copy operations are supported, such as no class members, no pointers, and no resource allocation, there is no need to provide your own copy assignment operator. However, if the meaning caused by default behaviors is insecure or incorrect, that is, memory leakage or alias problems, you must provide a correct copy assignment operator. For the default copy assignment operator, a class does not show bitwise copy semantics in the following cases: 1. the class contains a member object, and its class has a copy assignment operator, regardless of whether the copy assignment operator is clearly defined or implicitly synthesized; 2. when the base class of the class has a copy assignment operator; 3. class declares any virtual function; 4. class is inherited from a virtual base class, regardless of whether the base class has a copy assignment operator.
5.3.3 inherit the copy assignment operatorThe copy assignment operator of the derived class will call the copy assignment operator of the base class, and then execute other additional operations. Copy assignment operator is not performing well in the case of virtual inheritance, so you need to carefully design and describe it.
5.4 Semantic AnalysisIf the class does not define the destructor, the compiler will automatically synthesize one only when the member object (or base class) in the class has the destructor, otherwise, the Destructor is regarded as unnecessary, and therefore does not need to be merged or called. Therefore, if a constructor is defined, the idea of providing an destructor is incorrect. Before deleting an object, it is not required to clear its content first. A programmer-defined destructor is extended in a way similar to a constructor extension, but in the opposite order: 1. if the object contains a vptr, first reset it to vtbl; 2. the Destructor itself is executed, that is, the vptr will be reset before the programmer's code is executed; 3. if a class has a member class object and the latter has a destructor, they are called in reverse order of their declaration; 4. if any direct non-virtual function base class has a destructor, it is called in the reverse order of its Declaration; 5. if any of the virtual base classes have destructor, and the class currently discussed is the final class, they will be called in the reverse order of their original construction order.