C/CPLUS

C++<第二十一篇>:继承

2022-01-23  本文已影响0人  NoBugException

继承是面向对象的主要特征之一,它使得一个类可以从现有类中派生,而不必重新定义一个新类。
继承的实质就是用已有数据类型创建新的数据类型,并保留已有数据类型的特点,以旧类为基础创建新类,新类包含了旧类的成员变量和成员函数,并且可以在新类中添加新的成员变量和成员函数。
旧类被称为基类或者父类,新类被称为派生类或者子类。

(1)类继承的一般格式
class 派生类名: [继承方式] 基类名
{
    成员...
}

派生类又称子类,基类又称父类,所以以下的格式和前者是一致的:

class 子类类名: [继承方式] 父类名
{
    成员...
}

继承方式有三种,分别是公有型(public)、保护型(protected)和私有型(private)。

(2)继承的使用

假设有一个 Pesonal(人) 对象,Pesonal有姓名和年龄两个属性:

class Pesonal 
{
private:
    string mName; // 姓名
    int mAge; // 年龄

public:
    void setName(string name) 
    {
        mName = name;
    }

    string getName() 
    {
        return mName;
    }

    void setAge(int age) 
    {
        mAge = age;
    }

    int getAge() 
    {
        return mAge;
    }
};

还有一个Student(学生)对象,Student有姓名、年龄、成绩三个属性:

class Student
{
private:
    string mName; // 姓名
    int mAge; // 年龄
    int16_t mScore; // 成绩

public:
    void setName(string name)
    {
        mName = name;
    }

    string getName()
    {
        return mName;
    }

    void setAge(int age)
    {
        mAge = age;
    }

    int getAge()
    {
        return mAge;
    }

    void setScore(int score) 
    {
        mScore = score;
    }

    int getScore() 
    {
        return mScore;
    }
};

学生也是人,因此学生也有人的特性,Student也具有Pesonal的姓名和年龄两种属性,所以,这两个类可以使用继承关系。
我们需要对Student类做下修改,代码如下:

class Student:public Pesonal
{
private:
    int16_t mScore; // 成绩

public:

    void setScore(int score) 
    {
        mScore = score;
    }

    int getScore() 
    {
        return mScore;
    }
};

Student类中,只要添加Student特有的属性即可,Student可以使用Pesonal中的属性。

使用代码如下:

Student student;
student.setName("zhangsan");
student.setAge(16);
student.setScore(90);

cout << "姓名:" << student.getName() << endl;
cout << "年龄:" << student.getAge() << endl;
cout << "成绩:" << student.getScore() << endl;
(2)访问控制和继承

派生类可以访问基类中所有的非私有成员。因此基类成员如果不想被派生类的成员函数访问,则应在基类中声明为 private。

我们可以根据访问权限总结出不同的访问类型,如下所示:

访问 public protected private
同一个类 yes yes yes
派生类(子类) yes yes no
外部的类 yes no no

一个派生类继承了所有的基类方法,但下列情况除外:

(3)继承方式

继承方式有 public、private、protected 3种,3种继承方式说明如下:

我们几乎不使用 protected 或 private 继承,通常使用 public 继承。当使用不同类型的继承时,遵循以下几个规则:

(4)构造函数和析构函数的访问顺序

为了方便研究派生类和基类构造函数和析构函数的调用顺序,需要写一个演示代码:

#include <iostream>
#include <string>

using namespace std;

class Pesonal 
{
private:
    string mName; // 姓名
    int mAge; // 年龄

public:
    Pesonal() 
    {
        cout << "构造函数 --- Pesonal" << endl;
    }
    ~Pesonal() 
    {
        cout << "析构函数 --- Pesonal" << endl;
    }

    void setName(string name) 
    {
        mName = name;
    }

    string getName() 
    {
        return mName;
    }

    void setAge(int age) 
    {
        mAge = age;
    }

    int getAge() 
    {
        return mAge;
    }
};

class Student:public Pesonal
{
private:
    int16_t mScore; // 成绩

public:
    Student()
    {
        cout << "构造函数 --- Student" << endl;
    }
    ~Student()
    {
        cout << "析构函数 --- Student" << endl;
    }
    void setScore(int score) 
    {
        mScore = score;
    }

    int getScore() 
    {
        return mScore;
    }
};

int main()
{
    Student student;
    student.setName("zhangsan");
    student.setAge(16);
    student.setScore(90);

    cout << "姓名:" << student.getName() << endl;
    cout << "年龄:" << student.getAge() << endl;
    cout << "成绩:" << student.getScore() << endl;

    return 0;
}

在运用时,我们只创建了派生类对象,调用后的输出结果是:

构造函数 --- Pesonal
构造函数 --- Student
姓名:zhangsan
年龄:16
成绩:90
析构函数 --- Student
析构函数 --- Pesonal

所以,构造函数的调用顺序是:

基类(父类)  -->     派生类(子类)

析构函数的调用顺序和构造函数相反:

派生类(子类)  -->   基类(父类)
(5)子类显式调用父类的构造函数

当子类实例化时,子类和父类的构造函数都会被执行;
子类执行哪个构造函数取决于子类实例化传入的参数;
那么,到底执行了父类的哪个构造函数呢?

一般情况下,默认调用父类没有形式参数的构造方法,如果想要调用父类有形式参数的构造方法,我们需要显式调用父类的构造函数,代码如下:

Pesonal类的带参构造方法:

Pesonal(string name, int age)
{
    mName = name;
    mAge = age;
}

Student类的无参构造方法:

Student() :Pesonal("zhangsan", 16)
{
    
}

此时,先调用Pesonal类的带参构造方法,再调用Student类的无参构造方法。

(6)上转型对象

上转型其实就是子类转成父类,我们先看下代码:

Student student;
student.setName("zhangsan");
student.setAge(16);
student.setScore(90);

Pesonal pesonal = student; // 上转型,子类转成父类

cout << "姓名:" << pesonal.getName() << endl;
cout << "年龄:" << pesonal.getAge() << endl;

Student有一个属性:成绩,由于Student继承Pesonal,相当于Student有三个属性:姓名、年龄、成绩;
Pesonal只有两个属性:姓名、年龄;
当Student赋值给Pesonal时,即:

Pesonal pesonal = student; // 上转型,子类转成父类

pesonal只能访问Pesonal类中的成员,不能访问Student中的成员。

如果需要父类转成子类,这样的转换属于降级转换,降级转换必须使用强制转换,父类转子类的强制转换和上转型相反。

(7)多重继承

C++可以多重继承,多重继承的一般形式为:

class <派生类名>:<继承方式1><基类名1>,<继承方式2><基类名2>,…
{
    <派生类类体>
};

多个基类用逗号隔开。

子类可以调用多个父类的公有型和保护型的成员。

[本章完...]

上一篇 下一篇

猜你喜欢

热点阅读