17.继承的基本规则

17.面向对象-继承-继承的基本规则


17.1 知识点

基本概念

  • 一个类 A 继承一个类 B

  • 类 A 将会继承类 B 的成员(不包括构造函数、析构函数和友元等)

  • A 类将拥有 B 类的特征和行为(根据访问权限决定能否访问)

  • 被继承的类称为父类、基类、超类

  • 继承的类称为子类、派生类

  • 子类可以有自己的特征和行为

  • 特点:

    • 传递性:子类可以间接继承父类的父类(前提是访问权限允许)
    • 多继承:子类可以有多个父类

基本语法

  • 使用访问修饰符来改变父类成员在子类中的访问方式

  • 语法格式:

    class 子类名 : 继承方式 父类名
    {
        // 子类自己的成员
    };
    
  • 访问修饰符回顾(3P):

    • public —— 公共的,自己(内部)和别人(外部)都能访问和使用(完全公开)
    • private —— 私有的,自己(内部)才能访问和使用,不写默认为 private(严格私有)
    • protected —— 保护的,自己(内部)和子类才能访问和使用(对子类开放)
  • 父类成员在不同继承方式下的访问级别:

    父类原来级别 public 继承后 protected 继承后 private 继承后
    public public protected 不可访问
    protected protected protected 不可访问
    private 不可访问 不可访问 不可访问
  • 当前继承时不受影响,父类是什么样子就是什么样访问级别;若后续再继承,则会受到这里的限制。

实例

#pragma once
#include <iostream>
using namespace std;
class Teacher
{
public:
    // 老师的名字
    string name;
    // 老师自我介绍的方法
    void SpeakName()
    {
        number = 1;
        f = 1.1f;
        cout << name << endl;
    }
protected:
    int number = 0;
private:
    float f = 2.3f;
};
#pragma once
#include "Teacher.h"
class TeachingTeacher : public Teacher
{
public:
    string subject;
    void SpeakSubject()
    {
        SpeakName();

        // public 外部、内部、子类都能用
        cout << name << endl;  //(子类中使用)

        // protected 内部、子类可以使用
        cout << number << endl;  //(子类中使用)

        // private 内部使用
        // cout << f << endl;  //(子类中使用) // 报错

        cout << subject << endl;
    }

    int x = 1;
    void test()
    {
        cout << "TeachingTeacher" << endl;
    }

    void test2()
    {
        cout << "TeachingTeacher2" << endl;
    }
};
#pragma once
#include "TeachingTeacher.h"
class ChineseTeacher : public TeachingTeacher
{
public:
    void Skill()
    {
        // cout << number << endl;
        cout << "一行白鹭上青天" << endl;
    }

    int x = 2;
    using TeachingTeacher::test2;

    void test()
    {
        cout << "ChineseTeacher" << endl;
    }

    void test2(int i)
    {
        cout << "ChineseTeacher2" << endl;
    }
};
ChineseTeacher ct;
ct.name = "小韬老师";
ct.subject = "语文";
ct.SpeakName();     // 小韬老师
ct.SpeakSubject();  // 小韬老师\n小韬老师\n1\n语文
ct.Skill();         // 一行白鹭上青天

子类和父类的同名成员

  • C++ 中允许子类存在和父类同名的成员,但不建议这样使用

  • 子类同名成员会覆盖父类成员

    cout << ct.x << endl;         // 2 打印 ChineseTeacher 的 x 变量
    ct.test();                    // ChineseTeacher
    
  • 可通过作用域解析符 :: 强制访问父类成员

    cout << ct.TeachingTeacher::x << endl;    // 1 打印 TeachingTeacher 的 x 变量
    ct.TeachingTeacher::test();               // TeachingTeacher
    
      //如果在内部用 直接 父类名::成员
      //如果在外部用 直接 对象.父类名::成员
    
  • 子类同名不同参数的成员函数会隐藏父类所有同名函数(即使参数不同也不能直接访问),可用 using 父类名::方法名; 解决隐藏问题

    //子类同名不同参数成员函数会隐藏父类成员
    //当子类定义了一个和父类同名但参数不同的函数
    //父类中所有同名函数都会被隐藏,即使参数不同也不能再直接访问!
    //可以通过 using 父类名::父类方法名 来解决隐藏问题
    // 
    //比如现在TeachingTeacher有个无参的test2方法
    //ChineseTeacher有个有一个int参数的test2方法
    //看起来是两个函数
    //但是直接执行test2会报错 因为子类同名不同参数成员函数会隐藏父类成员
    
    //ct.test2();//报错
    
    //但是如果在ChineseTeacher类中 添加如下代码
    //using TeachingTeacher::test2; 
    //就可以正常执行
    ct.test2();//TeachingTeacher2
    ct.test2(666);//ChineseTeacher2
    

强行禁止类被继承

  • 如果不希望一个类可以被继承,可使用 final 关键字修饰类

  • 语法:

    class 类名 final
    {
    };
    

总结

  • 继承的基本语法

    class 子类名 : 继承方式 父类名
    {
        // 子类自己的成员
    };
    
  • 父类成员在不同继承方式下的访问权限一览:

    父类原来级别 public 继承后 protected 继承后 private 继承后
    public public protected 不可访问
    protected protected protected 不可访问
    private 不可访问 不可访问 不可访问
  • 继承方式使用访问修饰符来限制父类成员在后续继承中的可见性

  • 特性:

    • 传递性:子类可间接继承父类的父类
    • 多继承:子类可有多个父类

17.2 知识点代码

Teacher.h

#pragma once
#include<iostream>
using namespace std;
class Teacher
{
public:
    //老师的名字
    string name;
    //老师自我介绍的方法
    void SpeakName()
    {
        number = 1;
        f = 1.1f;
        cout << name << endl;
    }
protected:
    int number = 0;
private:
    float f = 2.3f;
};

TeachingTeacher.h

#pragma once
#include "Teacher.h"
class TeachingTeacher : public Teacher 
{
public:
    string subject;
    void SpeakSubject()
    {
        SpeakName();

        //public 外部 内部 子类都能用
        cout << name << endl;//(子类中使用)

        //protected 内部 子类可以使用
        cout << number << endl;//(子类中使用)

        //private 内部使用
        //cout << f << endl;//(子类中使用)//报错

        cout << subject << endl;
    }

    int x = 1;
    void test()
    {
        cout << "TeachingTeacher" << endl;
    }

    void test2()
    {
        cout << "TeachingTeacher2" << endl;
    }
};

ChineseTeacher.h

#pragma once
#include "TeachingTeacher.h"
class ChineseTeacher : public TeachingTeacher
{
public:
    void Skill()
    {
        //cout << number << endl;
        cout << "一行白鹭上青天" << endl;
    }

    int x = 2;
    using TeachingTeacher::test2;

    void test()
    {
        cout << "ChineseTeacher" << endl;
    }

    void test2(int i)
    {
        cout << "ChineseTeacher2" << endl;
    }
};

Lesson17_面向对象_继承_继承的基本规则.cpp

#include <iostream>
using namespace std;
#include "ChineseTeacher.h"
int main()
{
    #pragma region 知识点一 基本概念
    //一个类A继承一个类B
    //类A将会继承类B的成员(不包括构造函数、析构函数和友元等)
    //A类将拥有B类的特征和行为(根据访问权限决定能否访问)

    //被继承的类
    //称为 父类、基类、超类

    //继承的类
    //称为子类、派生类

    //子类可以有自己的特征和行为    

    //特点
    //1.传递性 子类可以间接继承父类的父类(前提是访问权限允许)
    //2.多继承 子类可以有多个父类
    #pragma endregion

    #pragma region 知识点二 基本语法
    //class 子类名 : 继承方式 父类名 
    //{
    //    //子类自己的成员
    //};

    //继承方式就是使用访问修饰符来
    //改变父类成员在子类中的访问方式
    // 
    //回顾访问修饰符作用
    // 3P
    // public —— 公共的  自己(内部)和别人(外部)都能访问和使用(完全公开,任何地方都能访问)
    // private —— 私有的  自己(内部)才能访问和使用  不写 默认为private(严格私有,只有当前类内部才能访问)
    // protected —— 保护的  自己(内部)和子类才能访问和使用(对自己和子类开放,外部不可访问)
    // 决定类内部的成员 的 访问权限
    //
    //父类成员原本访问级别	public继承后	         protected继承后	          private继承后
    //     public	           public	            protected	            不可访问
    //     protected	     protected	            protected	            不可访问
    //     private	          不可访问	            不可访问	                不可访问
    //继承方式 是用3P去限制父类中成员的访问级别的
    //当前继承时,不会受到影响,父类是什么样就是什么样的访问级别
    //但是如果之后还存在继承关系,那么之后的类就会收到这里的影响了
    #pragma endregion

    #pragma region 知识点三 实例
    ChineseTeacher ct;
    ct.name = "小韬老师";
    ct.subject = "语文";
    ct.SpeakName();//小韬老师
    ct.SpeakSubject();
    //小韬老师
    //小韬老师
    //1
    //语文
    ct.Skill();
    //一行白鹭上青天
    #pragma endregion

    #pragma region 知识点四 子类和父类的同名成员
    //C++中允许子类存在和父类同名的成员
    //但是不建议这样使用

    //子类同名成员会覆盖父类成员
    cout << ct.x << endl;//2 打印的ChineseTeacher的x变量 
    ct.test();//ChineseTeacher

    //但可以通过作用域解析符::来强制访问父类成员
    //比如: 父类名::成员
    cout << ct.TeachingTeacher::x << endl;//1 打印的TeachingTeacher的x变量 
    ct.TeachingTeacher::test();//TeachingTeacher

    //如果在内部用 直接 父类名::成员
    //如果在外部用 直接 对象.父类名::成员



    //子类同名不同参数成员函数会隐藏父类成员
    //当子类定义了一个和父类同名但参数不同的函数
    //父类中所有同名函数都会被隐藏,即使参数不同也不能再直接访问!
    //可以通过 using 父类名::父类方法名 来解决隐藏问题
    // 
    //比如现在TeachingTeacher有个无参的test2方法
    //ChineseTeacher有个有一个int参数的test2方法
    //看起来是两个函数
    //但是直接执行test2会报错 因为子类同名不同参数成员函数会隐藏父类成员

    //ct.test2();//报错
    
    //但是如果在ChineseTeacher类中 添加如下代码
    //using TeachingTeacher::test2; 
    //就可以正常执行
    ct.test2();//TeachingTeacher2
    ct.test2(666);//ChineseTeacher2


    #pragma endregion

    #pragma region 知识点五 强行禁止类被继承
    //如果我们不希望一个类可以被继承
    //我们可以通过final关键词来修饰类
    //基本语法:
    //class 类名 final
    //{
    //}
    //在类名后加上final关键字,就可以禁止该类被继承了
    #pragma endregion

    //总结
    //继承的基本语法
    //class 子类名 : 继承方式 父类名 
    //{
    //    //子类自己的成员
    //};
    //父类成员原本访问级别	public继承后	         protected继承后	          private继承后
    //     public	           public	            protected	            不可访问
    //     protected	     protected	            protected	            不可访问
    //     private	          不可访问	            不可访问	                不可访问
    //继承方式 是用3P去限制父类中成员的访问级别的
    //当前继承时,不会受到影响,父类是什么样就是什么样的访问级别
    //但是如果之后还存在继承关系,那么之后的类就会收到这里的影响了

    //1.传递性 子类可以间接继承父类的父类(前提是访问权限允许)
    //2.多继承 子类可以有多个父类
}

17.3 练习题

写一个人类,人类中有姓名,年龄属性,有说话行为,战士类继承人类,有攻击行为

#pragma once
#include <iostream>
using namespace std;
class Person
{
public:
    string name;
    int age;

    void Speak(string str);
};
#include "Person.h"

void Person::Speak(string str)
{
    cout << str << endl;
}
#pragma once
#include "Person.h"
class Warrior : public Person
{
public:
    void Atk(Warrior& otherWarrior);
};
#include "Warrior.h"

void Warrior::Atk(Warrior& otherWarrior)
{
    cout << this->name << "打了" << otherWarrior.name << endl;
}
Warrior w1;
w1.name = "韬老师";
w1.age = 18;

Warrior w2;
w2.name = "奥特曼";
w2.age = 999;

w1.Speak("我要打死你");
w1.Atk(w2);
w2.Speak("你相信光吗?");
w2.Atk(w1);

// 我要打死你
// 韬老师打了奥特曼
// 你相信光吗?
// 奥特曼打了韬老师

17.4 练习题代码

Person.h

#pragma once
#include <iostream>
using namespace std;
class Person
{
public:
    string name;
    int age;

    void Speak(string str);
};

Person.cpp

#include "Person.h"
void Person::Speak(string str)
{
    cout << str << endl;
}

Warrior.h

#pragma once
#include "Person.h"
class Warrior : public Person
{
public:
    void Atk(Warrior& otherWarrior);
};

Warrior.cpp

#include "Warrior.h"

void Warrior::Atk(Warrior& otherWarrior)
{
    cout << this->name << "打了" << otherWarrior.name << endl;
}

Lesson17_练习题.cpp

#include <iostream>
#include "Warrior.h"
int main()
{
    #pragma region 练习题
    /*写一个人类,人类中有姓名,年龄属性,有说话行为
    战士类继承人类,有攻击行为*/

    Warrior w1;
    w1.name = "韬老师";
    w1.age = 18;

    Warrior w2;
    w2.name = "奥特曼";
    w2.age = 999;

    w1.Speak("我要打死你");
    w1.Atk(w2);
    w2.Speak("你相信光吗?");
    w2.Atk(w1);

    //我要打死你
    //韬老师打了奥特曼
    //你相信光吗?
    //奥特曼打了韬老师

    #pragma endregion

}


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏