Inheritance and derivation
01 Concepts of inheritance and derivation
Inheritance:
- When defining A new class B, if the class is similar to an existing class A (meaning that B has all the characteristics of A), then A can be A base class and B A derived class (also known as A subclass) from the base class.
Derived classes:
- Derived classes are derived by modifying and extending the base class. In derived classes, new member variables and member functions can be extended.
- A derived class has all the member functions and variables of the base class, whether private, protected, or public. Note that the private members of the base class cannot be accessed in the member functions of the derived class.
02 Examples of inheritance mechanisms needed
There are many kinds of program ape, such as C/C++ ape, Java ape, Python ape and so on. To design the programmer as a base class, we need to extract its unique properties and methods.
Common attributes (member variables) for all programmers:
- The name
- gender
- position
All programmers have common methods (member functions) :
- Do I have to work overtime?
- Is there a reward?
And different programmers have their own different attributes and methods:
- C++ program ape: whether audio and video, online game field
- Java programming ape: Is it a microservices domain
- Python programmer: is it artificial intelligence, big data domain
03 How to write derived classes
The inherited format is as follows:
classDerived class name:publicThe base class name {
};
Copy the code
Coder base class:
class Coder
{
public:
bool isWorkOvertime(a){} // Do I have to work overtime
bool isReward(a){} // Is there a reward
void Set(const string & name) // Set the name
{ m_name = name; }...private:
string m_name; / / name
string m_post; / / position
int m_sex; / / gender
};
Copy the code
PythonCoder derived classes:
class PythonCoder : public Coder
{
public:
bool isAIField(a){} // Is it an artificial intelligence domain
bool isBigDataField(a){} // Whether it is a big data domain
};
Copy the code
04 Memory space of derived objects
The size of a derived object = the size of the member variable of the base object + the size of the derived object’s own member variable. A derived object contains a base object, and the base object is stored before the new member variable of the derived object, equivalent to the base object being the header.
class CBase
{
int a1;
int a2;
};
class CDerived : public CBase
{
int a3;
};
Copy the code
Inheritance and composition
01 Two relationships between classes
Inherited relationships are “yes” relationships:
- Base class A, B “is” A derivative of base class A.
- It is logically required that A B object also “be” an A object.
The relation of inheritance is the relation of “having” :
- Class C “has” member variable I, and the member variable I belongs to class D, then C and D are compound relations.
- Logically required: D objects are inherent properties or components of C objects.
02 Use of inheritance relationships
Suppose we already have a Man class for men, and then we need some Women class for Women. The Man class and the Women class do have something in common. Is it appropriate for the Women class to inherit the Man class?
Let’s think about the logic of inheritance, assuming that Women inherit Man: A woman is also a Man. Obviously, this is clearly not true!
Therefore, it is a good practice to generalize the common characteristics of men and women, abstract a Human class to represent people, and then both Man and Woman inherit the Human class.
03 The use of compound relationships
Suppose you want to write a community dog management system:
- You need to write a “master” class.
- You need a dog.
Given that dogs have only one owner, but an owner can have up to 10 dogs, how should the “owner” and “dog” classes be designed and used? Let’s start with a few examples:
Example 1:
- Create an array of dog member objects for the master.
- Create an owner member object for the dog class.
class CDog;
class CMaster// Master class {
CDog dogs[10]; // An array of dog member objects
};
class CDogA dog / / {
CMaster m; // Member object of the host class
};
Copy the code
Example 1 can be found as follows:
- The owner class constructs 10 dog objects
- Dogs construct an owner object
Among men there are dogs, among dogs there are men:
This is bad because it creates a loop where the owner class constructs the dog object, which in turn constructs the owner object….
Example 2:
- Create an owner member object for dogs.
- Set an array of Pointers to dog objects for the master.
class CDog;
class CMaster// Master class {
CDog * pDogs[10]; // Dog object pointer array
};
class CDogA dog / / {
CMaster m; // Member object of the host class
};
Copy the code
In this way, there will be someone in the dog, and when people point to the dog with “someone in the dog”, the relationship will appear very confused, as shown below:
Example 3:
- Set an owner object pointer for the dog class;
- Create an array of dog-like objects for the host.
class CDog;
class CMaster// Master class {
CDog dogs[10]; // Array of dog objects
};
class CDogA dog / / {
CMaster * pm; // An object pointer to the host class
};
Copy the code
In this way, there will be a dog in the human, and the dog in the human will point to the owner again. Although the relationship is relatively better, it will still be confused, and the effect is as follows:
Example 4:
- Set an owner object pointer for the dog class;
- Set an array of Pointers to dog objects for the master.
class CDog;
class CMaster// Master class {
CDog * pDogs[10]; // Dog object pointer array
};
class CDogA dog / / {
CMaster * pm; // An object pointer to the host class
};
Copy the code
This is a correct example, because man and his master are independent. Through the function of the pointer, the dog can point to one master, and the master can also point to 10 dogs belonging to himself at the same time, which will be more flexible.
04 Differences between pointer objects and objects
If the pointer object is not used, the A object is also constructed along with the B object. This is not the case with Pointers, which are good for efficiency and memory.
Such as:
class Car
{
Engine engine; // Member objects
Wing * wing; // Member pointer object
};
Copy the code
Define a car. All cars have an engine, but not all cars have a wing. In this way, for cars without a wing, the wing only takes a pointer, which is also convenient to judge.
- Spatially, using Pointers saves space from constructing B objects. Instead, it opens up only one pointer in the object, rather than the size of an object B.
- In terms of efficiency, using Pointers is suitable for reuse. Object B is accessible not only to object A, but also to other objects that need to use it.
- Pointer objects can use the property of polymorphism. A pointer to a base class can point to any derived class in the derived chain.
- Pointer objects need to be instantiated only when they are needed, but when they are not in use, they need to be reclaimed manually.
Derived classes override base class members
01 cover
A derived class (subclass) may define a member with the same name as a member of the base class (parent). This is called an override. When accessing such a member in a derived class (subclass), the default is to access a member defined in the derived class. To access a member of the same name defined by the base class in a derived class, use the scope symbol ::.
Here’s a concrete example:
/ / the base class
class Father
{
public:
int money;
void func(a);
};
/ / a derived class
class Son : public Father / / inheritance
{
public:
int money; // A member variable with the same name as the base class
void func(a); // Member function with the same name as base class
void myFunc(a);
};
void Son::myFunc()
{
money = 100; // References the derived class money
Father::money = 100; // Reference base class money
func(); // A reference to a derived class
Father::func(); // References the base class
}
Copy the code
Equivalent to the storage space occupied by Son objects:
The protected member of the class
We all know that public members of a base class are accessible by derived members. Are protected and private members of a base class accessible by derived members? With that in mind, we can start with chestnuts:
class Father
{
public:
int nPublic; // Public member
protected:
int nProtected; // Protect members
private:
int nPrivate; // Private member
};
class Son : public Father
{
void func(a)
{
nPublic = 1; // OK
nProtected = 1; // error
nPrivate =1; // ok, access the protected member inherited from the base class
Son a;
a.nProtected = 1; // error,a is not the current object}};int main(a)
{
Father f;
Son s;
f.nPublic; // OK
s.nPublic; // OK
f.nProtected; // error
s.nProtected; // error
f.nPrivate; // error
s.nPrivate; // error
}
Copy the code
The protected, private members of the base class have permission for derived members:
Protected members of the base class | The private member of the base class |
---|---|
A member function of a derived class can access protected members of the base class of the current object | Cannot be accessed by a derived class member |
Constructor of a derived class
Usually when a derived constructor is initialized, the derived constructor is intended to initialize the base class constructor. So how do you initialize the base class constructor in a derived class constructor?
class Bug {
private :
int nLegs; int nColor;
public:
int nType;
Bug (int legs, int color);
void PrintBug (a){}; };class FlyBug : public Bug // FlyBug is a Bug derived class
{
int nWings;
public:
FlyBug( int legs,int color, int wings);
};
Bug::Bug( int legs, int color)
{
nLegs = legs;
nColor = color;
}
// Wrong FlyBug constructor
FlyBug::FlyBug ( int legs,int color, int wings)
{
nLegs = legs; // Cannot access
nColor = color; // Cannot access
nType = 1; // ok
nWings = wings;
}
// The correct FlyBug constructor:
FlyBug::FlyBug ( int legs, int color, int wings):Bug( legs, color)
{
nWings = wings;
}
int main(a)
{
FlyBug fb ( 2.3.4);
fb.PrintBug();
fb.nType = 1;
fb.nLegs = 2 ; // error. nLegs is private
return 0;
}
Copy the code
In the code example above:
The derived class constructor on lines 24-30 is the wrong way to initialize the base class, because the private members of the base class are not accessible by derived classes and therefore cannot be initialized.
Lines 33-36 are how the correctly derived class constructor initializes the base class constructor by calling it, always executing the base constructor before executing a derived class constructor.
From the above example, we also know that the base class object is constructed first before the derived object is constructed, so the principle of “construct first, initialize later” is still used in the destruction of the derived class, so the derived class destructor is executed first, then the base class destructor is executed.
Chestnuts as follows:
class Base
{
public:
int n;
Base(int i) : n(i)
{
cout << "Base " << n << " constructed" << endl;
}
~Base()
{
cout << "Base " << n << " destructed" << endl; }};class Derived : public Base
{
public:
Derived(int i) : Base(i)
{
cout << "Derived constructed" << endl;
}
~Derived()
{
cout << "Derived destructed" << endl; }};int main(a)
{
Derived Obj(3);
return 0;
}
Copy the code
Output result:
Base 3 constructed
Derived constructed
Derived destructed
Base 3 destructed
Copy the code
Inherited assignment compatibility rules
01 public inheritance
/ / the base class
class Base {};
/ / a derived class
class Derived : public Base {};
Base b; // Base class object
Derived d; // Derived objects
Copy the code
- Objects of derived classes can be assigned to objects of base class
b = d;
Copy the code
- Derived class objects can initialize base class references
Base & br = d;
Copy the code
- The address of a derived object can be assigned to a base pointer
Base * pb = & d;
Copy the code
Note: If the derivation is private or protected, the above three rules do not work ==
02 Protected and private inheritance
/ / the base class
class Base {};
/ / a derived class
class Derived : protected Base {};
Base b; // Base class object
Derived d; // Derived objects
Copy the code
- In protected inheritance, the public and protected members of the base class become protected members of the derived class.
- In private inheritance, public members of the base class become private members of the derived class, and protected members of the base class become inaccessible members of the derived class.
- Protected and private inheritance are not a yes relationship.
If the derived method is private or protected, there is no way to assign, reference, or pointer to a derived object to a base object as there is in the public derived method.
03 Pointer casting of base and derived classes
In the public derived case, the pointer to a derived object can be assigned directly to the base pointer
Base *ptrBase = & objDerived;
Copy the code
- PtrBase refers to an object of a Derived class
- *ptrBase can be viewed as an object of a Base class, and its public members can be accessed directly through ptrBase, but members of objDerived objects that are not Base classes cannot be accessed through ptrBase.
You can convert ptrBase to a pointer to the Derived class by forcing a pointer type conversion
Base * ptrBase = &objDerived;
Derived *ptrDerived = ( Derived * ) ptrBase;
Copy the code
Programmers need to make sure ptrBase points to an object of a Derived class, otherwise it’s easy to make mistakes.