C++个人复习笔记(四)

文章目录

第八章 继承 (Inheritance)

8.1 引入

8.1.1 为什么需要继承 why inherit?

在 C++中代码的可重用性(software reusability)是通过继承(inheritance)这一机制来实现的。
如果没有掌握继承性,就没有掌握类与对象的精华。

8.1.2 引例

在”老师“与”学生“之前,代码重用性的思考。

//引例
//老师:姓名,性别,年龄,教课,吃饭
//学生:姓名,性别,年龄,学习,吃饭
//人类:姓名,性别,年龄,吃饭

//父类(继承关系) or 基类(派生关系):
class Human {
   
public:
    void Eating(string food)
    {
   
        cout << "i am eating " << food << endl;
    }
private:
    string _name;
    char _sex;
    int _age;
};

//子类 or 派生类:
class Teacher:public Human {
   
public:
    Teacher(string name ="NULL", char sex = 'N', int age = 0) :
        _name(name), _sex(sex), _age(age)
    {
   

    }
    void Teach(string course)
    {
   
        cout << "i am a teacher, and i am teaching " << course << endl;
    }

private:
    string _name;
    char _sex;
    int _age;
};

//子类 or 派生类:
class Student: public Human {
   
public:
    Student(string name = "NULL", char sex = 'N', int age = 0):
        _name(name),_sex(sex),_age(age)
    {
   

    }

    void Learing(string course)
    {
   
        cout << "i am a student, and i am studying " << course << endl;
    }

private:
    string _name;
    char _sex;
    int _age;
};

int main(int argc, char** argv)
{
   
    Teacher duan("DuanZhiQiang", 'M', 35);
    duan.Teach("Chinese");
    duan.Eating("BugerKing");

    Student zheng("ZhengShaoJIe", 'M', 23);
    zheng.Learing("C++");
    zheng.Eating("KFC");

    system("pause");
    return 0;
}

Human是从学生和讲师中抽象出来的共同属性。让学生和老师均继承自Human的话, 就可以实现代码的重用性了。

8.1.3 结论

继承是一种设计的结果,通常是发生于一套类库中的,设计代码重用的方式,这种关系是一种设计而为之,不是想继承,就可随便继承的。

8.2 继承

8.2.1 定义

类的继承,是新的类从已有类那里得到已有的特性或从已有类产生新类的过程就是 类的派生。原有的类称为基类或父类,产生的新类称为派生类或子类。 派生与继承,是同一种意义两种称谓

8.2.1 定性 is-a Not has-a

is-a 是一种属于关系,如:狗属于一种动物,车属于一种交通工具(DogisanAnimal.Car is a Vehicle.)在面向对象中表现为一种继承关系。可以设计一个 Animal 类,Dog 类作为 Animal 类(基类)的派生类;设计一个Vehicle类,Car类作为Vehicle类(基类)的派生类。
has-a是一种包含、组合关系。如:车包含方向盘、轮胎、发动机(Car hassteering-wheel, wheels, engine),但不能说方向盘/轮胎/发动机是一种车;狗包含腿、尾巴,但不能说腿、 尾巴是一种狗。正确的应该说车聚合(包含)了方向盘、轮胎、发动机。 因此,如果 A is a B,则 B 是 A 的基类,A 是 B 的派生类。为继承关系。如果 A 包含 B, 则B 是 A 的组成部分。为聚合关系,可以由组成部分聚合成为一个类。 宏观意义上来讲, is-ahas-a 均可以实现代码的可重用性。

8.2.3 语法

class 派生类名:[继承方式] 基类名
{
   
	派生类成员声明;
}

默认的继承方式是 private 私有继承
一个派生类可以同时有多个基类,这种情况称为多重继承,派生类只有一个基类,称为单继承。 下面从单继承讲起。

8.2.4 继承方式

8.2.4.1 分类

公有继承(public):基类的公有成员(public)和保护成员(protected)在派生类中保持原有访问属性,其私有成员仍为基类的私有成员。
私有继承(privated):基类的公有成员(public)和保护成员(protected)在派生类中成了私有成员,其私有成员仍为基类的私有成员。
保护继承(protected):基类的公有成员(public)和保护成员(protected)在派生类中成了保护成员,其私有成员仍为基类的私有成员。
本章节只讨论公有继承。其他两种之后学习。

8.2.4.2 集成方式影响了什么

继承方式规定了子类如何访问从基类继承的成员
继承方式有public,private,protected继承方式不影响派生类的原访问权限,影响了从基类继承而来的成员的访问权限,包括派生类内的访问权限和派生类对象的访问权限。
在这里插入图片描述
可以发现,卡在了子类中父类的private成员上。这种现象称之为不可见protected成员在外部访问的时候等价于privated;但是在继承中是可见的

8.2.4.3 结论

在这里插入图片描述
如何验证,父类中 protected 成员,在 public 继承后,仍然是 protected 的呢?答案是, 再次用public派生出孙子类,在其类内考查其可见性。
在这里插入图片描述

8.2.5 派生类的组成

8.2.5.1 组成图示

派生类中的成员,包含两大部分,一类是从基类继承过来的,一类是自己增加的成员。 从基类继承过过来的表现其共性,而新增的成员体现了其个性
在这里插入图片描述
这种派生类与基类的关系,我们称之为全盘接受。不管你基类里有什么,派生类通同继承下来,包括私有成员(除开构造器与析构器)。。基类有可能会造成派生类的成员冗余,比如,基类有20个功能,但是我只需要基类的一个功能,所以说基类是需设计的。
派生类有了自己的个性,使派生类有了意义。意思是,有自己的个性,这个派生类才有意义。

8.2.5.2 sizeof(父/子)
#include <iostream>
#include <typeinfo>

using namespace std;

//szieof(父/子)
class AA {
   
public:
    AA()
    {
   
        cout << "AA构造" << endl;
        cout << "&a      " << &a << endl;
        cout << "AA-this " << this << endl;
        cout << typeid(this).name() << endl;
    }
    int a;
};

class BB: public AA {
   
public:
    BB()
    {
   
        cout << "BB构造" << endl;
        cout << "&b      " << &b << endl;
        cout << "BB-this " << this << endl;
        cout << typeid(this).name() << endl;
    }
    int b;
};

class CC : public BB {
   
public:
    CC()
    {
   
        cout << "CC构造" << endl;
        cout << "&c      " << &c << endl;
        cout << "CC-this " << this << endl;
        cout << typeid(this).name() << endl;
    }
    int c;
};

int main(int argc, char** argv)
{
   
    CC cc;
    cout << "&cc " << &cc << endl;
    cout << typeid(cc).name() << endl;


    system("pause");
    return 0;
}

输出如下:
在这里插入图片描述

8.3 派生类的构造

派生类中,由基类继承而来的成员的初始化工作,还是由基类的构造函数完成,然后派生类中新增的成员在派生类的构造函数中初始化。

8.3.1 语法格式

派生类名 :: 派生类名( 总参列表 )
	:基类名(参数表), 内嵌子对象( 参数表 )
{
   
	派生类新增成员的初始化语句; 
}	

8.3.2 构造原理

8.3.2.1 图示

在这里插入图片描述

8.3.2.2 注释

由于子类中,包含了两部分内容,一部分来自父类,一部分来自子类。父类的部分,要由调用父类的构造器来完成,子类的部分,在子类的构造器中来完成始化。子类中, 有内嵌的子对象也需要构造。
顺序如下:

  • 标配:1 默认无参构造器 2 重载(包含无参) 3 默参(包含无参)
  • 先调用了基类的构造器, 或隐 “标配” 或显 “标配"也可以显,但无"标配”,必须得显。
  • 然后内嵌子对象的构造, 或隐 “标配” 或显 “标配"也可以显,但无"标配”,必须得显。
  • 必须得显,指得显示的在初始化参数列表调用, 初始化参数列表中的顺序,不代表真实的调用顺序。

就像家里来了客人,我们先给老爸倒水,再给客人倒水,最后再给自己倒水

//派生类的构造
class AAA {
   
public:
    AAA(int j):_a(j)
    {
   
        cout << "AAA构造" << endl;
        //_a = 0;
    }
    int _a;
};

class CCC {
   
public:
    CCC(int c) :_c(c)
    {
   
        cout << "CCC构造" << endl;
    }
    int _c;
};

class BBB:public AAA {
   
public:
    BBB(int a, int b, int c):AAA(a), cc(c), _b(b)
    {
   
        cout << "BBB构造" << endl;
        //_b = b;
    }
    int _b;
    CCC cc;
};

int main(int argc, char** argv)
{
   
    BBB b(3,5,10);
    cout << b._a << b._b << b.cc._c << endl;

    return 0;
}

输出如下:
在这里插入图片描述

8.3.3 实战

class Birth {
   
public:
    Birth(int year, int month, int day)
        :_year(year),_month(month),_day(day)
    {
   

    }

    void DisBirth()
    {
   
        cout << "生日:" << _year << " " << _month << " " << _day << endl;
    }

private:
    int _year;
    int _month;
    int _day;
};

class Stu {
   
public:
    Stu(string name,char sex,float score)
        :_name(name),_sex(sex),_score(score)
    {
   

    }

    void DisInfo()
    {
   
        cout << "姓名:" << _name << endl;
        cout << "性别:" << _sex << endl;
        cout << "分数:" << _score << endl;
    }

private:
    string _name;
    char _sex;
    float _score;
};

class GraStu:public Stu {
   
public:
    GraStu(string name, char sex, float score, float salary,int year,
        int month, int day)
        : Stu(name, sex, score), birth(year, month, day)
    {
   
        _salary = salary;
    }

    void Dis()
    {
   
        DisInfo();
        cout << "工资:" << _salary << endl;
        birth.DisBirth();
    }

    Birth birth;

private:
    float _salary;

};

class Doctor :public GraStu {
   
public:
    Doctor(string title, string name, char sex, float score, float salary, int year,
        int month, int day)
        :GraStu(name, sex, score, salary, year,
            month, day)
    {
   
        _title = title;
    }

    void DisDoctorInfo()
    {
   
        cout << "学位:" << _title << endl
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值