1. Construction, deconstruction and copy of inherited subclasses (see day8 in part)
1. Copy Construction of Subclasses
class Base{
public: Base(void):m_i(0){//Parametric structure } Base(int i):m_i(i){//Parametric structure } ~Base(void){} int m_i; }; class Derived:private Base{ public: Derived(void){} Derived(int i,int j):Base(i),m_i(j){} //Derived(const Derived& that):m_i(that.m_i){}//Subclasses call this copy assignment, but since there is no way to initialize base classes, base classes will be initialized in the form of parametric constructs, which does not conform to the semantics of copies. Derived(const Derived& that):m_i(that.m_i),Base(that){}//Although it can be used Base::m_i Initialize, but if m_i It's a private member, it's not accessible. //Base(that)The copy constructor of the base class subobject is called for initialization. that Will be implicitly transformed into Base Object, that is, upward modeling ~Derived(void){} int m_i }; //In the main function Derived d1(100,200); Deribved d2(d1);//copy construction
As mentioned above, the following points should be noted:
1) Subclasses do not define a copy constructor. The compiler automatically provides default copy constructors for subclasses. The function also automatically calls the copy constructor of the base class to initialize the subobjects of the base class.
2) Subobjects define copy constructors, so it is necessary to explicitly state that the base class subobjects do copy constructions in the initialization table of subclasses, otherwise the base class subobjects will be initialized in a parametric manner.
2. Copy assignment of subclasses
For the above code:
Derived d3; d3=d1;//copy assignment
For cases where deep copy and member subobjects are not involved, the default copy assignment function can be used if you want to customize the copy assignment function:
Derived& operator=(const Derived& that){//Only the copy assignment of the child object is considered, while the base class subobject calls the parametric construction. if(&that!=this){ m_i=that.m_i; //Base::m_i=that.Base::m_i;Imperfect Base::operator=(that);//Upward modelling } return *this; }
For the above code, there are the following points:
1) Subclasses do not define copy assignment operator functions, the compiler will provide default copy assignment operator functions, and the subclasses will automatically call the base class copy assignment operator functions to copy the base class subobjects.
2) When a subclass defines a copy assignment function, it is necessary to explicitly call the copy assignment function of the base class to assign the subobject of the base class. Otherwise, the normal copy assignment may not be possible.
II. Multiple Inheritance
1. Concept and Grammar
When a subclass inherits multiple base classes at the same time, such inheritance is called multiple inheritance. The initialization list for multiple inheritance is written in the day8 inheritance section.
Upward modeling
The upward modeling and single inheritance of multiple inheritance are the same, but the starting address of each base class subobject will be offset according to the inheritance order and the size of the base class subobject.
2. Name conflict
Conflicts occur when members with the same name exist in subclasses.
Example:
class A{ public: void foo(void){ } }; class B{ public: void foo(int i){ } }; class C:public A,public B{};
int main(void){ C c; //Because A Class sum B Class foo Functions have different scopes and cannot be overloaded, so ambiguity conflicts occur. c.foo(); c.foo(10); return 0; }
It can be invoked as follows
int main(void){ C c; //Because A Class sum B Class foo Functions have different scopes and cannot be overloaded, so ambiguity conflicts can occur or can be used. using Keyword introduction C Internal overload is constituted, but these two functions must satisfy the overload condition. c.A::foo(); c.B::foo(10); return 0; }
Example:
class A{ public: void foo(void){ } typedef int m_data; }; class B{ public: void foo(int i){ } int m_data; }; class C:public A,public B{ }; //Without the scope qualifier, two m_data do not want to be shut down, but they will also report conflict errors if they are used directly. The correct way to use them is as follows: C c; c.B::M_data=10; c.A::m_data num=10;
To sum up, the general method to solve name conflict is to use "class name:" method. If the conflict is a member function and the overload condition is satisfied, using keywords to introduce subclasses to solve the same name conflict.
3. Inheritance of masonry
A subclass like the one above inherits multiple base classes, which in turn inherit from the same ancestor base class, thus forming a closed-loop inheritance called masonry inheritance.
class A{ public: A(int data):m_data(data){} protected: int m_data; }; class B:public A{ public: B(int data):A(data){} void set(int data){ m_data=data; } }; class C:public A{ public: C(int data):A(data){} int get(void){ return m_data; } }; class D:public B,public C{ public: D(int data):B(data),C(data){} }; int main(void) { D d(100); d.set(200); d.get(); //m_data Acquired m_data The value is not 200, but not unchanged, but there are two copies. m_data,One exists B Subobjects of a base class, an existence and C Base class subobject. This makes the code difficult to maintain. }
As mentioned above, members of common base class (A) subobjects derived from multiple intermediate subclasses (m_data) will have multiple instances in aggregate subclass (D) objects inherited from multiple intermediate subclasses. Accessing members of a common base class by aggregating subclass (D) objects can lead to inconsistencies due to different inheritance paths.
4. Virtual Inheritance
Because there are two copies of the same data and the maintenance of the code is relatively complex, virtual inheritance can be used to solve the problem. Through virtual inheritance, common base class subobjects can be uniquely instanced in aggregated subclass objects and shared among all intermediate subclasses. So even along different inheritance paths, the members of the common base class accessed must be identical.
class A{ public: A(int data):m_data(data){} protected: int m_data; }; class B:virtual public A{//Virtual inheritance public: B(int data):A(data){} void set(int data){ m_data=data; } }; class C:virtual public A{//Virtual inheritance public: C(int data):A(data){} int get(void){ return m_data; } }; class D:public B,public C{ public: D(int data):B(data),C(data),A(data){}//D specifies the initialization of A }; int main(void) { D d(100); d.set(200); d.get(); //m_data Acquired m_data The value is not 200, but not unchanged, but there are two copies. m_data,One exists B Subobjects of a base class, an existence and C Base class subobject. This makes the code difficult to maintain. }
Virtual Inheritance Grammar:
(1) In virtual inheritance, the keyword virtual is used
(2) The aggregate subclass constructor at the end of the inheritance chain is responsible for constructing virtual base class (A) subobjects.
(3) However, all subclasses of a virtual base class (B, C, D) must explicitly specify the initialization method of the virtual base class subobject in its constructor, otherwise the compiler will initialize the base class subobject in a parametric construct.
The principle of virtual inheritance:
If the starting address of the construction object is output in the constructor of A, B, C and D, it will be found that, for example, the object constructed by D is the same as the starting address of B. In fact, there is only one m_data, which can be accessed through the pointer inside B and C (virtual pointer generated by virtual inheritance) plus offset.
3. Polymorphism (Importance)
1. Introduction
If a member function in the base class is declared as a virtual function, then the member function in the subclass that has the same prototype as that in the base class is also a virtual function, and the version in the base class is covered. This is to call virtual functions by pointing to the base class pointer of the subclass object, or by referring to the base class reference of the subclass object. The actual invocation will be the overwritten version in the subclass, not the original version in the base class. This grammatical phenomenon is called polymorphism.
The virtual function of the same prototype in the subclass and the parent class will form a covering relation, that is, the virtual function of the parent class is covered by the subclass, and the function of the subclass is a virtual function whether or not the virtual keyword is added.
class Shape{ public: Shape(int x,int y):m_x(x),m_y(y){ } virtual void draw(void){} protected: int m_x; int m_y; }; class recr;public Shape{ public: Rect(int x,int y,int w,int h): Shape(x,y),m_w(w),m_h(h){} void draw(void){ //Need only rectangular information } private: int m_w; int m_h; }; class Circle:public Shape{ public: Circle(int x,int y,int r): Shape(x,y),m_r(r){} void draw(void){ //Need to know the circular information } private: int m_r; }; void render(Shape* shapes[]){ for(int i=0;shapes[i];i++){ shape[i]->draw();//If Shape in draw()No addition virtual Keyword, you can only call base class Shape Medium draw()Function, modified to reflect polymorphism //The function invoked is no longer determined by the type of pointer, but by the actual target object type. } } int main(void){ Shape* shapes[1024]={NULL};//Implicit Upward Modeling shapes[0]=new Rect(1,2,3,4); shapes[1]=new Circle(5,6,7); //. . . render(shapes); return 0; }
2. The Conditions for Constituting Coverage of Virtual Functions
1) Only ordinary member functions of classes can be declared as virtual functions (destructors can be declared as virtual functions), global functions, static functions, static member functions, and constructors can not be declared as virtual functions.
2) Only virtually modified member functions in base classes can be overwritten as virtual functions by subclasses, regardless of the virtual keywords of subclasses.
3) Virtual functions must have the same function prototype in subclasses and base classes, i.e. function names, parameter tables, constant attributes, etc. Note that this is different from overloading, which emphasizes coverage. At the same time, the general return value also requires the same, but if the function of the subclass and the virtual function return value of the base class have inheritance relationship (reference or pointer or class type), and satisfy the above conditions, it can also complete the coverage (type covariance).