• C++中的继承


    继承

    1️⃣ 继承的概念:继承是是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能,这样产生新的类,称派生类
    2️⃣ 继承的定义:

    class Person
    {
    public:
    	string _name;
    	string _sex;
    	int _age;
    };
    class Student :public Person
    {
    public:
    	int _No;
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    下面我们看到Person是父类,也称作基类。Student是子类,也称作派生类在这里插入图片描述
    3️⃣基类和派生类对象赋值转化:

    • 派生类对象 可以赋值给 基类的对象 / 基类的指针 / 基类的引用。这里有个形象的说法叫切片或者切割。寓意把派生类中父类那部分切来赋值过去。
      我们通过代码进行解释

    class Person
    {
    public:
    string _name;
    string _sex;
    int _age;
    };
    class Student :public Person
    {
    public:
    int _No;
    };

    int main()
    {
    Person p;
    Student s;
    s._name = “张三”;
    s._age = 20;
    s._sex = “男”;
    p = s;
    Person& rp = s;
    Person* ptrp = &s;

    cout << &s << endl;
    cout << &rp << endl;
    cout << ptrp << endl;
    rp._age++;
    ptrp->_age++;
    
    return 0;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    }
    在这里插入图片描述

    我们发现地址都一样说明可以赋值给基类的对象 / 基类的指针 / 基类的引用。

    • 基类对象不能赋值给派生类对象
      在这里插入图片描述
      在这里插入图片描述
      我们会发现它出现了这样的错误。下面的第三点就是对该错误的处理。
    • 基类的指针或者引用可以通过强制类型转换赋值给派生类的指针或者引用。但是必须是基类的指针是指向派生类对象时才是安全的。这里基类如果是多态类型
      第一个处理方法是进行强制转换:
      在这里插入图片描述

    4️⃣继承中的作用域:

    1. 在继承体系中基类和派生类都有独立的作用域。
    2. 子类和父类中有同名成员,子类成员将屏蔽父类对同名成员的直接访问,这种情况叫隐藏,也叫重定义。(在子类成员函数中,可以使用 基类::基类成员 显示访问)
    3. 需要注意的是如果是成员函数的隐藏,只需要函数名相同就构成隐藏。
    4. 注意在实际中在继承体系里面最好不要定义同名的成员。

    在这里插入图片描述
    我们通过上图,发现父类和子类都要_num我们进行实现的时候用的是子类的_num解释了上面的第二点:子类和父类中有同名成员,子类成员将屏蔽父类对同名成员的直接访问。我们要处理这个问题我们可以通过确定访问的方式进行指定访问。

    我指定了它是访问父类。通过运行我们发现这个方法是可行的。
    5️⃣.派生类的默认成员函数
    5. 派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员。如果基类没有默认的构造函数,则必须在派生类构造函数的初始化列表阶段显示调用。
    6. 派生类的拷贝构造函数必须调用基类的拷贝构造完成基类的拷贝初始化。
    7. 派生类的operator=必须要调用基类的operator=完成基类的复制。
    8. 派生类的析构函数会在被调用完成后自动调用基类的析构函数清理基类成员。因为这样才能保证派生类对象先清理派生类成员再清理基类成员的顺序。
    9. 派生类对象初始化先调用基类构造再调派生类构造。
    10. 派生类对象析构清理先调用派生类析构再调基类的析构。

    class Person
    {
    public:
    Person(const char* name)
    :_name(name)
    {
    cout << “Person()” << endl;
    }
    Person(const Person& p)
    :_name(p._name)
    {
    cout << “Person(const Person& p)” << endl;
    }
    Person& operator=(const Person& p)
    {
    cout << “Person& operator=(const Person& p)” << endl;
    if (this != &p)
    _name = p._name;
    return this;
    }
    ~Person()
    {
    cout << “~Person” << endl;
    }
    protected:
    string _name;
    };
    class Student :public Person
    {
    public:
    Student(const char
    name=" ",int num=0)
    :_num(num)
    ,Person(name)
    {
    cout << “Student(const char* name=” “,int num=0)” << endl;
    }
    Student(const Student& s)
    :Person(s)
    ,_num(s._num)
    {
    cout << “Student(const Student& s)” << endl;
    }
    Student& operator=(const Student& s)
    {
    if (this != &s)
    {
    Person::operator=(s);
    _num = s._num;
    }
    cout << “Student& operator=(const Student& s)” << endl;
    return *this;
    }
    ~Student()
    {
    cout << “~Student()” << endl;//会去调用父类的所以这边不需要写
    }
    protected:
    int _num;
    };
    int main()
    {
    Student s1(“李四”, 1);
    Student s2(s1);
    Student s3(“王五”, 2);
    s1 = s3;
    return 0;
    }

    以上10点需要读者自己通过这部分代码进行探究。
    6️⃣继承与友元

    友元关系不能继承,也就是说基类友元不能访问子类私有和保护成员。
    在这里插入图片描述
    如上图对基类使用了友元,编译器报错完美解释了友元关系不能继承
    7️⃣继承与静态成员
    基类定义了static静态成员,则整个继承体系里面只有一个这样的成员。

    class Person
    {
    public:
    Person()
    {
    ++_count;
    }
    protected:
    string _name;
    public:
    static int _count;
    };
    int Person::_count = 0;
    class Student : public Person
    {
    protected:
    int _stuNum;
    };
    class Graduate :public Student
    {
    protected:
    string _seminarCourse;
    };
    int main()
    {
    Student s1;
    Student s2;
    Student s3;
    Graduate s4;
    Person s;
    cout << " 人数 :" << Person::_count << endl;
    cout << " 人数 :" << Student::_count << endl;
    cout << " 人数 :" << s4._count << endl;
    cout << " 人数 :" << &Person::_count << endl;
    cout << " 人数 :" << &Student::_count << endl;
    cout << " 人数 :" << &s4._count << endl;
    return 0;
    }

    在这里插入图片描述
    我们通过该代码进行验证。发现static定义的_count的静态变量在类里面是唯一的。我们可以进行多次改变。
    8️⃣指定访问
    指定访问是为了解决复杂的菱形继承中的二义性。
    什么是菱形继承?
    菱形继承:是多继承的一种特殊情况。
    多继承:一个子类有两个或以上直接父类时称这个继承关系为多继承。
    单继承:一个子类只有一个直接父类时称这个继承关系为单继承。

    lass Person
    {
    public:
    string _name;
    int _a[10000];
    };
    class Student : virtual public Person
    {
    protected:
    int _num;
    };
    class Teachar :virtual public Person
    {
    protected:
    int _id;
    };
    class Assistant :public Student, public Teachar
    {
    protected:
    string _majorCourse;
    };

    在这里插入图片描述
    以上就是指定访问的使用。
    9️⃣ virtual的使用
    虚拟继承的出现是为了解决菱形继承中数据冗余和二义性的问题。
    虚拟继承写在继承方式的前面。
    在这里插入图片描述
    虚拟继承的使用,请百度。本人对虚拟继承的认知不足。

  • 相关阅读:
    42张图,带你真正搞懂redis数据类型的底层
    搭建私有组件库
    内网渗透之Windows认证(二)
    毕业设计之基于node.js+Vue+Element驾校信息管理系统
    BERT和ChatGPT简单对比
    新入职后的第一天GitLab 与 SourceTree的结合使用
    贪心算法:寻找最优方案,分配问题、区间覆盖问题、最大子列和问题等
    webpack(二)webpack介绍与基础配置
    [附源码]计算机毕业设计大学生心理健康测评系统
    gitlab操作
  • 原文地址:https://blog.csdn.net/qq_61273847/article/details/126227927