C++ Inheritance and Derivation

Protected members are similar to privates and cannot be accessed through objects. But when there is an inheritance relationship, protected and private are different: the protected member in the base class can be used in a derived class, and the privated member in the base class cannot be used in a derived class.
You can only declare protected if you want members of the base class to be neither exposed (not accessible through objects) nor used in derived classes.
The following table summarizes the effects of different inheritance modes on members of different attributes

Inheritance/Base Class Membershippublic membersprotected memberprivate Members
public inheritancepublicprotectedInvisible
protected InheritanceprotectedprotectedInvisible
private InheritanceprivateprivateInvisible

Since private s and protected inheritance alter the access rights of base class members in derived classes, resulting in complex inheritance relationships, we generally use public in actual development.
Using the using keyword can change the access permissions of base class members in derived classes, such as changing public to private and protected to public.

Note: using can only change the access rights of the public and protected members in the base class, not the privates, because the privates in the base class are not visible in the derived class and cannot be used at all, so the privates in the base class cannot be accessed in the derived class in any way.

#include<iostream>
using namespace std;
//Base Class People
class People {
public:
    void show();
protected:
    char *m_name;
    int m_age;
};
void People::show() {
    cout << m_name << "Age is" << m_age << endl;
}
//Derived Class Student
class Student : public People {
public:
    void learning();
public:
    using People::m_name;  //Change protected to public
    using People::m_age;  //Change protected to public
    float m_score;
private:
    using People::show;  //Change public to private
};
void Student::learning() {
    cout << "I am" << m_name << ",This year" << m_age << "Years old, this exam" << m_score << "Score!" << endl;
}
int main() {
    Student stu;
    stu.m_name = "Xiao Ming";
    stu.m_age = 16;
    stu.m_score = 99.5f;
    stu.show();  //compile error
    stu.learning();
    return 0;
}

The code first defines the base class People, which contains two member variables of the protected property and one member function of the public property. The Student class is defined with public inheritance, and members of the People class have the same access rights in the student class by default.

However, we used using to change their default access permissions. As shown in lines 21-25 of the code, modifying the show() function to the private property reduces access permissions, and modifying the name and age variables to the public property improves access permissions.

Since the show() function is a private property, an error occurs on line 36 of the code. Comment out this line and the program output will be:
I am Xiao Ming, 16 years old, and I got 99.5 points this time!
The destructor executes in the opposite order as the constructor:
When a derived class object is created, the constructor executes in the same order as the inheritance, that is, the base class constructor is executed before the derived class constructor.
When a derived class object is destroyed, the destructor is executed in the opposite order as inheritance, that is, the derived class destructor is executed before the base class destructor.

#include <iostream>
using namespace std;
class A{
public:
    A(){cout<<"A constructor"<<endl;}
    ~A(){cout<<"A destructor"<<endl;}
};
class B: public A{
public:
    B(){cout<<"B constructor"<<endl;}
    ~B(){cout<<"B destructor"<<endl;}
};
class C: public B{
public:
    C(){cout<<"C constructor"<<endl;}
    ~C(){cout<<"C destructor"<<endl;}
};
int main(){
    C test;
    return 0;
}
Run result:
A constructor
B constructor
C constructor
C destructor
B destructor
A destructor
#include <iostream>
using namespace std;
//base class
class BaseA{
public:
    BaseA(int a, int b);
    ~BaseA();
public:
    void show();
protected:
    int m_a;
    int m_b;
};
BaseA::BaseA(int a, int b): m_a(a), m_b(b){
    cout<<"BaseA constructor"<<endl;
}
BaseA::~BaseA(){
    cout<<"BaseA destructor"<<endl;
}
void BaseA::show(){
    cout<<"m_a = "<<m_a<<endl;
    cout<<"m_b = "<<m_b<<endl;
}
//base class
class BaseB{
public:
    BaseB(int c, int d);
    ~BaseB();
    void show();
protected:
    int m_c;
    int m_d;
};
BaseB::BaseB(int c, int d): m_c(c), m_d(d){
    cout<<"BaseB constructor"<<endl;
}
BaseB::~BaseB(){
    cout<<"BaseB destructor"<<endl;
}
void BaseB::show(){
    cout<<"m_c = "<<m_c<<endl;
    cout<<"m_d = "<<m_d<<endl;
}
//Derived Class
class Derived: public BaseA, public BaseB{
public:
    Derived(int a, int b, int c, int d, int e);
    ~Derived();
public:
    void display();
private:
    int m_e;
};
Derived::Derived(int a, int b, int c, int d, int e): BaseA(a, b), BaseB(c, d), m_e(e){
    cout<<"Derived constructor"<<endl;
}
Derived::~Derived(){
    cout<<"Derived destructor"<<endl;
}
void Derived::display(){
    BaseA::show();  //Calling the show() function of the BaseA class
    BaseB::show();  //Calling the show() function of the BaseB class
    cout<<"m_e = "<<m_e<<endl;
}
int main(){
    Derived obj(1, 2, 3, 4, 5);
    obj.display();
    return 0;
}
Notice lines 64 and 65 Where we explicitly indicate which base class to call show() Function.
#include <iostream>
using namespace std;
class A{
public:
    A(int a, int b, int c);
private:
    int m_a;
    int m_b;
    int m_c;
};
A::A(int a, int b, int c): m_a(a), m_b(b), m_c(c){ }
int main(){
    A obj(10, 20, 30);
    int a1 = *(int*)&obj;
    int b = *(int*)( (int)&obj + sizeof(int) );
    A *p = new A(40, 50, 60);
    int a2 = *(int*)p;
    int c = *(int*)( (int)p + sizeof(int)*2 );
   
    cout<<"a1="<<a1<<", a2="<<a2<<", b="<<b<<", c="<<c<<endl;
    return 0;
}
Run result:
a1=10, a2=40, b=20, c=60

Previously, we said that members of C++ have access only at the syntax level, meaning that access is only for member operator. And-> work without preventing direct access through the pointer. You can think of this as the power of the pointer or as a flaw in the C++ language design.

The purpose of this section is not to access member variables of private and protected attributes. This kind of "fancy work with legs" has no practical significance. The main purpose of this section is to make you understand how the internal compiler works and the flexible use of pointers.
The iostream class in the C++ standard library is a real application case of virtual inheritance. Iostream inherits directly from istream and ostream, and both istream and ostream inherit from a common name, base_ The class of IOS is a typical diamond inheritance. Istream and ostream must adopt virtual inheritance at this time, otherwise it will cause two copies of base_to remain in the iostream class A member of the IOS class.

D::D(int a, int b, int c, int d): B(90, b), C(100, c), A(a), m_d(d){ }

Although we put A () at the end, the compiler still calls A () first, then B (), and C (), because A () is the constructor of a virtual base class and takes precedence over other constructors. If virtual inheritance is not used, the compiler will call B(), C(), A() in the order in which they appear.
The compiler accesses member variables through pointers, which point to which object uses which object's data; The compiler accesses member functions through the type of the pointer, which functions of which class the pointer belongs to.

Keywords: C++

Added by Big_Ad on Fri, 14 Jan 2022 23:56:19 +0200