Inheritance-reflects the reuse of class design levels

Inheritance

Object-oriented three major features: encapsulation, inheritance, polymorphism

Among them, inheritance embodies the reuse of class design levels

It allows programmers to extend and add functions on the basis of maintaining the characteristics of the original friend class, so as to generate new classes and become derived classes.

Format :

class Tiger: public Animal
{
    pbulic:
    char "paw";
};

The Tiger here is the subclass/derived class
public is the way of inheritance
Animal is the parent/base class

example

class Person
{
    public:
    void Print()
    {
      cout<<"name"<<_name<<endl;
      cout<<"age"<<_age<<endl;
    }
    protected:
        string _name = "peter" ;//name
        int _age = 18;//age
};

class Student : public Person
{
    protected:
        int _stuid;
};

class Teacher : public Person
{
    protected:
        int _jobid;
};

Inheritance method and access qualifier:

The inheritance methods are {public, protected, private}

Access qualifiers are {public, protected, private}

base class member\inheritance method public inheritance protected inheritance

private inheritance

The public member of the base class The public member of the derived class Derived protected members of the class

private members of derived classes

Protected member of the base class Protected member of the derived class Protected member of the derived class Private members of derived classes
Private members of base classes Invisible in derived classes Derived classes Invisible Invisible in derived classes

Summary:

1. After the private member of the base class is inherited, it exists in the derived class, but it cannot be accessed regardless of whether it is inside or outside the class.

The meaning of private members: Members that do not want to be inherited by subclasses can be limited by private

2. protected is for the situation that “base class members do not want to be accessed outside the class, but can be accessed in derived classes”.

3. Class defaults to private inheritance; struct defaults to public inheritance, It is best to explicitly write the inheritance format

4. In practical applications, public inheritance is generally used (protected inheritance and private inheritance are rarely used), and private members are almost not applicable (because there are few members that cannot be inherited)

Scope in inheritance:

1. In the inheritance system, the base class and the derived class have independent scopes.

2. If there are members with the same name in the subclass and the parent class, The subclass members will block the direct access of the parent class to the members with the same name. This situation is called hiding, also called redefinition. (But for functions, it is definitely not function overloading, because Function overloading needs to be in the same scope, the function with the same name in the subclass is the hidden function of the same name in the parent class< /strong>).

Explicit access is available in subclass member functions: subclass.baseclass::baseclassmember

example

class B: public A
{
    //...
};

int main()
{
    B b;
    b. fun();
    b.A::fun();//Display access
    return 0;
}

3. If it is the hiding of member functions, as long as the function names are the same, it constitutes hiding.

4. Note that in practice, it is best not to define members with the same name in the inheritance system, which is easy to misjudge

Base class and derived class object assignment conversion

1. Subclass objects can be assigned to parent class object/parent class pointer/parent class reference. There is a vivid saying here called slicing or cutting, meaning to cut off the part of the parent class in the subclass and assign it to the past

Note that Assigning a child class to a parent class is not an implicit type conversion.

2. Parent class objects cannot be assigned to derived class objects

3. The pointer or reference of the parent class can be assigned to the pointer or reference of the subclass through forced type conversion. But it must be safe when the base class pointer points to the derived class object. Here, if the base class is a polymorphic type, you can use the dynamic cast of RTT1 (Run – Time Type Information) to identify and convert safely.

Default member function of derived class:

1. Default constructor

Same as normal classes, just one more process of calling the constructor of the parent class

If there is no default constructor in the parent class, then we must implement a default constructor for the parent class (or complete the construction initialization of the parent class in the subclass constructor).

example:

class Person
{
   public:
    string _name;//Name
    Person(const char* name)
    :_name(name)
    {}
};

class Student : public Person
{
  public:
    Student(const char* name ,int id)
    :Person(name)
    ,_id(id)
    {}
  protected:
    int_id;
};

int main()
{
    Student s("Bao Zheng",1);
    return 0;
}

2. Default constructor

Its own members are the same as ordinary classes. For the inherited parent class, its default copy construction will be called

class Student : public Person
{
  public:
    Student(const char* name ,int id)
    :Person(name)
    ,_id(id)
    {}
  protected:
    int_id;
};


   Student (const Student & s)
   :Person(s)//direct cut
   ,_num(s._num)
   {}

3. Destructor

1. The destructor of the subclass and the destructor of the parent class form a hidden

2. Due to the need of polymorphism later, the name of the destructor will be uniformly processed into destructor()

3. The destructor of the parent class will be called automatically (after the subclass function is destructed), so there is no need to explicitly call the parent class destructor in the subclass destructor)

Inheritance and Friends

Friendship cannot be inherited-friends of base classes cannot access private and protected members of derived classes

Inheritance and static members

If the base class defines a static static member, there is only one member in the entire inheritance system, and no matter how many subclasses are derived, there is only one instance of the static member.

Complex diamond inheritance and diamond virtual inheritance:

1. Single inheritance: a subclass has only one direct parent class, called single inheritance

2. Multiple inheritance: When a subclass has two or more direct parent classes, this inheritance relationship is called multiple inheritance

Question: How to define a class that cannot be inherited?

Method 1: Privatization of the parent class constructor – it is invisible in the subclass, so the constructor cannot be called when the subclass object is instantiated.

Method 2. In C++11, there is a final keyword to modify the parent class, which means that it cannot be inherited

example:

class A final
{
    //...

At this time, if there is a class B: public A will report an error

Complex diamond inheritance and diamond virtual inheritance

Diamond inheritance:

Problems of diamond-shaped inheritance: data redundancy and ambiguity (in the following example, Person will have two copies in the assistant object)

class Person
{
   public:
    string _name ; // name
};

class Student : public Person
{
   protected:
    int _num ; //student number
};

class Teacher : public Person
{
   protected:
    int _id ; // employee number
};

class Assistant : public Student, public Teacher//diamond inheritance
{
   protected:
    string _majorCourse ; // major course
};

void Test()
{
 // This will be ambiguous and it is impossible to know which one is being accessed
   Assistant a;
   a._name = "peter"; //erro
// Need to show which member of the parent class to access can solve the ambiguity problem, but the data redundancy problem cannot be solved
   a.Student::_name = "xxx";
   a.Teacher::_name = "yyy";
}

Solution: rhombus virtual inheritance virtual

Virtual inheritance will open a separate space to store redundant data, and the original space will be used to save pointers (pointing to an offset-the distance from the current space where redundant data is stored) to find the space .

class A
{
   public:
     int _a;
};

// class B : public A
class B : virtual public A//virtual inheritance
{
public:
 int _b;
};

// class C : public A
class C : virtual public A//virtual inheritance
{
   public:
    int _c;
};

class D : public B, public C//virtual inheritance
{
   public:
    int _d;
};

int main()
{
   D d;
   d.B::_a = 1;
   d.C::_a = 2;
   d._b = 3;
   d._c = 4;
   d._d = 5;
   return 0;
}

Before virtual inheritance:

From this, we can clearly see that A is in both B and C, and the data is redundant.

After using virtual inheritance:

After using the virtual inheritance in the previous code, we can see that A is stored in a newly opened space, and a pointer variable is stored in its original space, and this variable points to a hexadecimal number, which is The offset of the original space address relative to the newly opened space address of A.

However, at the same time, when we access the base class members of B and C, there will be an extra layer of calculation (offset value), which can be regarded as increasing the complexity.

Substituting the Person inheritance relationship in the previous example is:

Summary and Reflection on Inheritance

1. Many people say that the syntax of C++ is complicated, but inheritance is a manifestation. With multiple inheritance, there is diamond inheritance, and there is diamond virtual inheritance. The underlying implementation is very complicated, so it is generally not recommended to design multiple inheritance, and you must not design diamond inheritance, which is too complicated.

2. Multiple inheritance is actually a pitfall of C ++, and many languages have optimized multiple inheritance (for example, Java does not support multiple inheritance)

3. Inheritance allows you to define the implementation of derived classes based on the implementation of the base class. This kind of reuse by generating derived classes is often called white-box reuse. The term “white box” is relative to visibility: In inheritance, the internal details of the base class are visible to subclasses. Inheritance destroys the encapsulation of the base class to a certain extent, and the change of the base class has a great impact on the derived class. The dependency relationship between the derived class and the base class is very strong, and the coupling degree is high.

4. Object composition is another reuse option besides class inheritance. New and more complex functions can be obtained by assembling or combining objects. Object composition requires that the objects being composed have well-defined interfaces. This style of reuse is called black-box reuse because the internal details of the objects are invisible. Objects only appear as “black boxes”. There is no strong dependency relationship between composite classes, and the degree of coupling is low. Preferring object composition helps you keep each class encapsulated.

5. Use combinations as often as possible. The coupling degree of the combination is low, and the code maintainability is good. However, inheritance is also useful. Some relationships are suitable for inheritance, so use inheritance. In addition, to achieve polymorphism, inheritance is also necessary. The relationship between classes can use inheritance, you can use combination, use combination.

 class Car
   {
     protected:
       string _colour = "white"; // color
       string _num = "Shaanxi ABIT00"; // license plate number
   };
   
   class BMW : public Car
   {
     public:
       void Drive() {cout << "easy to open-control" << endl;}
   };
   
   class Benz : public Car
   {
     public:
        void Drive() {cout << "easy to sit-comfortable" << endl;}
   };
   
   // Tire and Car form a has-a relationship
   
   class Tire
   {
     protected:
           string _brand = "Michelin"; // brand
           size_t _size = 17; // size
   
   };
   
   class car
   {
     protected:
       string _colour = "white"; // color
       string _num = "Shaanxi ABIT00"; // license plate number
        Tire _t; // tire
   }; 
syntaxbug.com © 2021 All Rights Reserved.