1 Inheritance and Derivation
Reusability in C++ is achieved by inheriting this mechanism. Inheritance allows us to define a class based on another class, which makes it easier to create and maintain an application. By doing so, you can reuse code functionality and improve execution efficiency.
When you create a class, you don't need to rewrite new data members and member functions, just specify that the new class inherits the members of an existing class. This existing class is called a base class, and the newly created class is called a derived class.
Inheritance and derivation are two terms of the same meaning. Inheritance represents the is a relationship. For example, mammals are animals and dogs are mammals, so dogs are animals.
For example, Class B inherits Class A and can be referred to as deriving Class B from Class A. Class A is called the base class (parent class) and class B is called the derived class (subclass).
2 Composition of derived classes
Members of derived classes consist of two main parts, one inherited from the base class and the other new members they add. Members inherited from the base class express their commonalities, while new members reflect their individualities. Derived classes have their own individualities and make derived classes meaningful.
Be careful:
A derived class inherits all the base class methods except the following:
-
Constructors, destructors, and copy constructors for base classes.
-
Overloaded operator for base class.
-
Friend function of base class.
3 Inheritance type
When a class derives from a base class, it can be inherited to several types: public, protected, or private.
-
Public inheritance: When a class inherits in a public manner, the access properties of the public and protected members of the base class remain the same in the derived class, while the private members of the base class are not accessible. That is, the public and protected members of the base class are inherited to the derived class and remain public and protected members of the derived class. Other members of derived classes can access them directly. Neither members of the derived class nor objects of the derived class have access to private members of the base class.
-
Protected inheritance: In protected inheritance, both public and private members of the base class appear in the derived class as protected members, while private members of the base class are inaccessible. Other members of a derived class have direct access to the public and protected members inherited from the base class, but they are not accessible outside the class through objects of the derived class, neither members of the derived class nor objects of the derived class can access private members of the base class.
-
Private inheritance: When a class inherits in a private manner, both public and protected members in the base class appear as private members in the derived class, while the private members of the base class are not accessible in the derived class. Public members of the base class and protected members are inherited as private members of the derived class, and other members of the derived class can access them directly, but they are not accessible outside the class through objects of the derived class. Neither members of a derived class nor objects of a derived class have access to private members inherited from the base class. After multiple private inheritances, members of the base class become inaccessible. Private inheritance is therefore less used.
Be careful:
1. No matter how the base class is inherited, derived classes cannot directly use the private members of the base class.
2. When inheriting, the inheritance type defaults to private if the access modifier is not used.
4 Single Inheritance
A class can be derived from more than one class, or single inheritance if only one class is derived. The syntax is as follows:
class Derived Class Name:Inheritance Type Base Class Name { Derived Class Body; };
Inheritance types are access modifiers, one of which is public, protected, or private. If no access modifier is used, it defaults to private.
Suppose you have a base class, Shape, and Rectangle is its derived class, as follows:
#include <iostream> using namespace std; // base class class Shape { public: void setWidth(int w) { width = w; } void setHeight(int h) { height = h; } protected: int width; int height; }; // Derived Class class Rectangle: public Shape { public: int getArea() { return (width * height); } }; int main(void) { Rectangle Rect; Rect.setWidth(5); Rect.setHeight(7); // Area of output object cout << "Total area: " << Rect.getArea() << endl; return 0; }
When the above code is compiled and executed, it produces the following results:
Total area: 35
5-plus inheritance
Multiple inheritance means that a subclass can have multiple parent classes, which inherit the attributes of multiple parent classes. The syntax is as follows:
class Derived Class Name:Inheritance Type 1 Base Class Name 1,Inheritance Type 2 Base Class Name 2,... { Derived Class Body; };
Inheritance types are access modifiers, one of which is public, protected, or private. If no access modifier is used, it defaults to private.
The base classes are separated by commas.
Suppose a derived class Rectangle inherits from the base class Shape and the base class PaintCost, as follows:
#include <iostream> using namespace std; // Base class Shape class Shape { public: void setWidth(int w) { width = w; } void setHeight(int h) { height = h; } protected: int width; int height; }; // Base class PaintCost class PaintCost { public: int getCost(int area) { return area * 70; } }; // Derived Class class Rectangle: public Shape, public PaintCost { public: int getArea() { return (width * height); } }; int main(void) { Rectangle Rect; int area; Rect.setWidth(5); Rect.setHeight(7); area = Rect.getArea(); // Area of output object cout << "Total area: " << Rect.getArea() << endl; // Total Output Cost cout << "Total paint cost: $" << Rect.getCost(area) << endl; return 0; }
When the above code is compiled and executed, it produces the following results:
Total area: 35 Total paint cost: $2450
6 Virtual Inheritance
If a derived class derives from more than one base class and they have a common base class, ambiguity may arise when accessing the names declared in that base class.
6.1 Ambiguity in Multiple Inheritance
6.1.1 Schematic storage structure for C-like objects with multiple derivations
6.2 virtual Inheritance
-
If a derived class derives from more than one base class and they have a common base class, ambiguity may arise when accessing the names declared in that base class.
-
If there is a common base class on multiple inheritance paths, at a junction of the inheritance paths, the common base class will produce multiple base class subobjects in the object of the derived class.
In order for this common base class to produce only one child object in a derived class, it must be declared virtual inheritance so that it is called a virtual base class.
The virtual inheritance declaration uses the keyword virtual
The syntax is as follows:
Class class name: virtual inherited type parent class name
Inheritance types are access modifiers, one of which is public, protected, or private. If no access modifier is used, it defaults to private.
6.2.1 Schematic storage structure of multiple derived C-like objects with virtual base classes
7 Constructions and Destructions in Inheritance
7.1 Type Compatibility Principles
Type compatibility rules refer to the substitution of objects from public (pulic) derived classes wherever a base class is required.
The alternatives referred to in the type compatibility rules include the following:
-
Subclass objects can be used as parent objects
-
Subclass objects can be assigned directly to parent objects
-
Subclass objects can directly initialize parent objects
-
A parent pointer can point directly to a child class object
-
Parent references can refer directly to subclass objects
After substitution, derived class objects can be used as objects in the base class, but only members inherited from the base class can be used.
The sample code is as follows:
// inheritTest1.cpp, // Rules for verifying type compatibility /* The alternatives referred to in the type compatibility rules include the following: 1. Subclass objects can be used as parent objects 2. Subclass objects can be assigned directly to parent objects 3. Subclass objects can directly initialize parent objects 4. A parent pointer can point directly to a child class object 5. Parent references can refer directly to subclass objects */ #include <iostream> using namespace std; class Parent { public: void printParent() { cout << "this is ParentClass" << endl; } int parent_age; }; class Child : public Parent { public: void printChild() { cout << "this is ChildClass" << endl; } }; void printByPoint(Parent *parent) { parent->printParent(); } void printByReference(Parent& parent) { parent.printParent(); } int main() { Child childTest_1; childTest_1.printParent(); // 1. Subclass objects can be used as parent objects cout << "Verify that subclass objects can be used successfully as parent objects" << endl; Child childTest_2; childTest_2.parent_age = 18; // 2. Subclass objects can be assigned directly to parent objects cout << "Verifying that subclass objects can be directly assigned to parent objects succeeds" << endl; Child childTest_3; childTest_3.parent_age = 1; // Note: Subclass objects initialize parent objects, and public members of parent objects must also be initialized, otherwise removing this sentence will cause an error. Parent parentTest_3 = childTest_3; // 3. Subclass objects can directly initialize parent objects cout << "Verify that subclass objects can directly initialize parent objects successfully" << endl; Child childTest_4; Parent *parentTest_4 = NULL; parentTest_4 = &childTest_4; // 4. Parent pointers can point directly to subclass objects printByPoint(parentTest_4); cout << "Verify parent pointer can point directly to child class object successfully" << endl; Child childTest_5; Parent &parentTest_5 =childTest_5; // 5. Parent references can refer directly to subclass objects printByReference(parentTest_5); cout << "Verify parent reference can refer directly to subclass object successfully" << endl; return 0; }
Run result:
7.2 Constructing destructive invocation principles in inheritance
- Subclass objects are created by calling the parent's constructor first, and after the parent's constructor is executed, the subclass's constructor is executed
2. When the parent class constructor has parameters, it needs to be explicitly called in the initialization list of the child class
3. Destructor calls are invoked in the reverse order as constructors
The sample code is as follows:
// inheritTest2.cpp, construct destructive invocation principle in inheritance #include <iostream> using namespace std; class Parent { public: Parent(const char* temp_s) { this->s = temp_s; cout << "Parent class parametric constructor runs"<< endl; } ~Parent() { cout << "Parent Destructor Run" << endl; } private: const char* s; }; class Child : public Parent { public: Child(int temp_age):Parent("I am a parent") { this->age = temp_age; cout << "Subclass parametric constructor runs"<< endl; } Child(int temp_age,const char *temp_s):Parent(temp_s) { this->age = temp_age; cout << "Subclass parametric constructor runs"<< endl; } ~Child() { cout << "Subclass destructor run" << endl; } private: int age; }; int main() { Child child_1(18); //Child_child 2(18,'I'm a parent'); // This statement can also be implemented return 0; }
Run result: