day4 4.1继承概念与方式、继承的权限及修改

C++ 继承与派生,继承性是面向对象程序设计最重要的特征,可以说,如果没有掌握继承性,就等于没有掌握类和对象的精华,就是没有掌握面向对象程序设计的真谛

继承的概念

继承是类与类之间的关系,是一个很简单很直观的概念,与现实世界中的继承类似,例如儿子继承父亲的财产;

继承(Inheritance)可以理解为一个类从另一个类获取成员变量和成员函数的过程;
例如类 B 继承于类 A,那么 B 就拥有 A 的成员变量和成员函数;被继承的类称为父类或基类,继承的类称为子类或派生类;(所以基类与派生类,父类与子类说的都是继承

派生类除了拥有基类的成员,还可以定义自己的新成员,以增强类的功能;

以下是两种典型的使用继承的场景:

  1. 当你创建的新类与现有的类相似,只是多出若干成员变量或成员函数时,可以使用继承,这样不但会减少代码量,而且新类会拥有基类的所有功能;

  2. 当你需要创建多个类,它们拥有很多相似的成员变量或成员函数时,也可以使用继承;可以将这些类的共同成员提取出来,定义为基类,然后从基类继承,既可以节省代码,也方便后续修改成员;

下面,我们定义了一个基类 People,然后由此派生出 Student 类:

#include <cstdio>

using namespace std;

class People {
public:
    void setname(const char *name) { m_name = name; }
    void setage(int age) { m_age = age; }
    const char *getname() const { return m_name; }
    int getage() const { return m_age; }
private:
    const char *m_name;
    int m_age;
};

class Student : public People {
public:
    void setscore(float score) { m_score = score; }
    float getscore() const { return m_score; }
private:
    float m_score;
};

int main() {
    Student s;
    s.setname("Otokaze");
    s.setage(18);
    s.setscore(111);
    printf("name: %s, age: %d, score: %g\n", s.getname(), s.getage(), s.getscore());
    return 0;
}

本例中,People 是基类,Student 是派生类。Student 类继承了 People 类的成员,同时还新增了自己的成员变量 m_score 和成员函数 setscore()、getscore();这些继承过来的成员,可以通过子类对象访问,就像自己的一样;

class Student : public People

class 后面的“Student”是新声明的派生类,冒号后面的“People”是已经存在的基类;在“People”之前有一关键宇 public,用来表示是公有继承;

继承方式包括 public(公有的)、private(私有的)和 protected(受保护的),此项是可选的,如果不写,那么默认为 private;

继承权限和继承方式

继承方式限定了基类成员在派生类中的访问权限,包括 public(公有的)、private(私有的)和 protected(受保护的);此项是可选项,如果不写,默认为 private(成员变量和成员函数默认也是 private);

现在我们知道,public、protected、private 三个关键字除了可以修饰类的成员,还可以指定继承方式;

public、protected、private 修饰类的成员

类成员的访问权限由高到低依次为 public –> protected –> private,public 成员可以通过对象来访问,private 成员不能通过对象访问;

现在再来补充一下 protected;protected 成员和 private 成员类似,也不能通过对象访问;但是当存在继承关系时,protected 和 private 就不一样了:基类中的 protected 成员可以在派生类中使用,而基类中的 private 成员不能在派生类中使用;

public、protected、private 指定继承方式

不同的继承方式会影响基类成员在派生类中的访问权限:

  1. public继承方式
    基类中所有 public 成员在派生类中为 public 属性;
    基类中所有 protected 成员在派生类中为 protected 属性;
    基类中所有 private 成员在派生类中不能使用。

  2. protected继承方式
    基类中的所有 public 成员在派生类中为 protected 属性;
    基类中的所有 protected 成员在派生类中为 protected 属性;
    基类中的所有 private 成员在派生类中不能使用。

  3. private继承方式
    基类中的所有 public 成员在派生类中均为 private 属性;
    基类中的所有 protected 成员在派生类中均为 private 属性;
    基类中的所有 private 成员在派生类中不能使用。

通过上面的分析可以发现:

  1. 基类成员在派生类中的访问权限不得高于继承方式中指定的权限;例如,当继承方式为 protected 时,那么基类成员在派生类中的访问权限最高也为 protected,高于 protected 的会降级为 protected,但低于 protected 不会升级;再如,当继承方式为 public 时,那么基类成员在派生类中的访问权限将保持不变;
    也就是说,继承方式中的 public、protected、private 是用来指明基类成员在派生类中的最高访问权限的;

  2. 不管继承方式如何,基类中的 private 成员在派生类中始终不能使用(不能在派生类的成员函数中访问或调用)

  3. 如果希望基类的成员能够被派生类继承并且毫无障碍地使用,那么这些成员只能声明为 public 或 protected;只有那些不希望在派生类中使用的成员才声明为 private;

  4. 如果希望基类的成员既不向外暴露(不能通过对象访问),还能在派生类中使用,那么只能声明为 protected;

注意,我们这里说的是基类的 private 成员不能在派生类中使用,并没有说基类的 private 成员不能被继承
实际上,基类的 private 成员是能够被继承的,并且(成员变量)会占用派生类对象的内存,它只是在派生类中不可见,导致无法使用罢了;
private 成员的这种特性,能够很好的对派生类隐藏基类的实现,以体现面向对象的封装性;

由于 private 和 protected 继承方式会改变基类成员在派生类中的访问权限,导致继承关系复杂,所以实际开发中我们一般使用 public;

在派生类中访问基类 private 成员的唯一方法就是借助基类的非 private 成员函数,如果基类没有非 private 成员函数,那么该成员在派生类中将无法访问;

改变访问权限

使用 using 关键字可以改变基类成员在派生类中的访问权限,例如将 public 改为 private、将 protected 改为 public 等:

#include <cstdio>

using namespace std;

class A {
protected:
    int m_a;
    char m_b;
    float m_c;
private:
    char *m_d;
};

class B : public A {
public:
    using A::m_a;
protected:
    using A::m_b;
//    using A::m_d; // 基类的private成员在派生类中不可见
private:
    using A::m_c;
};

int main() {
    B b;
    b.m_a = 1;
    return 0;
}

注意:在派生类中只能访问基类的非 private 成员,使用 using 时,也必须遵循这个规则;
对于父类的 public/protected 成员:using 可以将其改为 public、protected、private 属性;
对于父类的 private 成员:由于在派生类中不可见,所以也就不能使用 using 改变属性;

发布了94 篇原创文章 · 获赞 66 · 访问量 5480

猜你喜欢

转载自blog.csdn.net/qq_44861675/article/details/105110679