C++------继承

目录

一、什么是继承

二、继承的方式

1.基类private成员在派生类无论什么继承都不可见

2.基类成员只想在派生类访问,不想在类外访问用protect

3.基类的其他成员在子类的访问方式

4.默认的继承方式 

三、基类和派生类对象赋值转换 

四.继承中的作用域

五.派生类的默认成员函数 

1.默认构造

2.拷贝构造 

3.赋值重载

 4.析构函数

 ​编辑

 六.继承与友元

七、继承与静态成员 


一、什么是继承

C++继承的目的是为了让代码可以复用,在之前,我们有代码需要复用的时候,会写一个函数,然后对传递需要的参数给这个函数,也是实现了代码的复用。

C++推出了类这一概念,类里面不仅仅可以存放函数,还可以存放变量,同时我们也可以继承这个类,来使得类里面的数据可以被其他类共享。

继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能,这样产生新的类,称派生类。

继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。以前我们接触的复用都是函数复用,继承是类设计层次的复用。

这里Student类和Teacher类通过public来继承了Person类

Student类和Teacher类是子类,也叫派生类

public是继承方式,选择了共有继承(还有其他继承方式,我们下文再讲)

Person类是父类,也叫做基类

C++------继承_第1张图片

Student类和Teacher类并没有写_name成员和_age成员,但由于继承了Person,也就可以访问并使用Person类里面的成员了。

C++------继承_第2张图片

二、继承的方式

在之前类和对象里,我们讲解了private,和public访问限定符,这里我们有引入了protected访问限定符,同时这三个访问限定符也可以是继承方式。

C++------继承_第3张图片

 他们之前的区别是什么呢?

 C++------继承_第4张图片

我们对上面这个表做一个总结

1、2、 3最重要

  1. 基类private成员在派生类中无论以什么方式继承都是不可见的。这里的不可见是指基类的私 有成员还是被继承到了派生类对象中,但是语法上限制派生类对象不管在类里面还是类外面 都不能去访问它。
  2. 基类private成员在派生类中是不能被访问,如果基类成员不想在类外直接被访问,但需要在派生类中能访问,就定义为protected。可以看出保护成员限定符是因继承才出现的。
  3. 实际上面的表格我们进行一下总结会发现,基类的私有成员在子类都是不可见。基类的其他成员在子类的访问方式 == Min(成员在基类的访问限定符,继承方式),public > protected > private。
  4. 使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public,不过 最好显示的写出继承方式。
  5. 在实际运用中一般使用都是public继承,几乎很少使用protetced/private继承,也不提倡 使用protetced/private继承,因为protetced/private继承下来的成员都只能在派生类的类里面使用,实际中扩展维护性不强

具体什么意思我们一点一点的讲

1.基类private成员在派生类无论什么继承都不可见

这里访问没有问题

C++------继承_第5张图片

C++------继承_第6张图片

无论什么继承方式,基类(父类)的私有成员都无法在派生类和类外访问。

2.基类成员只想在派生类访问,不想在类外访问用protect

C++------继承_第7张图片

3.基类的其他成员在子类的访问方式

基类的其他成员在子类的访问方式 == Min(成员在基类的访问限定符,继承方式)

public > protected > private。

访问限定符和继承方式中选两个里面小的那个

举例子,下面是Person类是共有成员,Student类共有继承了Person类,因此新建个Student 类对象可以访问Person类里面的成员。

C++------继承_第8张图片

我们切换为protected继承,Student创建的类对象里的继承下来的成员会变成protected,类外面就无法访问了。

C++------继承_第9张图片

4.默认的继承方式 

 下面我们没有写继承的方式,直接 :类名,他说有的继承方式就是class或者struct的默认访问限定符, class 为私有,struct为共有。C++------继承_第10张图片

第5点就不多讲解了,我们在实际开发中一般都是用public继承方式,protected和public访问限定符。

三、基类和派生类对象赋值转换 

这里将b给到了a,发生了隐式类型转化。

C++------继承_第11张图片

C++------继承_第12张图片

因此如果使用&(引用)就会报错,因为临时对象具有常性,&需要变量。因此报错。

C++------继承_第13张图片

而在继承当中,也可以写出这样的代码,却不会报错

C++------继承_第14张图片

因为编译器做了切片处理,Student类对象给到Person,会将Student里面的内容给切割掉,只保留继承下来的内容,再给到Person类对象 。

注意:只能派生类对象赋值给基类类对象,    基类对象不能赋值给派生类对象。

C++------继承_第15张图片

四.继承中的作用域

当派生类和基类有着同名对象或者函数时,如果调用会调用自己的那一份数据,基类的数据会被隐藏起来。

如下

C++------继承_第16张图片

如果想访问基类的这份数据,需要再访问的时候添加上作用域

C++------继承_第17张图片

需要注意的是如果是成员函数的隐藏,只需要函数名相同就构成隐藏。

五.派生类的默认成员函数 

1.默认构造

下面这个例子,在派生类初始化中不能直接使用基类的成员进行初始化,可以通过父类的构造函数来初始化

C++------继承_第18张图片C++------继承_第19张图片

2.拷贝构造 

拷贝构造也需要调用父类的拷贝构造来进行初始化,这里运用了之前我们学到的知识点,子类对象传递给父类对象,发生了切割。

C++------继承_第20张图片

3.赋值重载

赋值重载也可以通过代码服用来完成,注意要加上Person::代表是父类里面的operator=函数,否则会一直调用自己的导致栈溢出。

C++------继承_第21张图片

 4.析构函数

我们写了父类和子类的析构

C++------继承_第22张图片

 C++------继承_第23张图片

我们只定义了一个Student类对象,发现竟然调用了Person类的构造函数和析构函数,父类的析构函数不需要显示调用,子类析构函数结束后会自动调用父类的析构,析构保证先子后父

这是C++祖师爷这么设计的,如果发生了继承

会先调用父类的构造函数,在调用子类的构造函数,析构时会先析构子类的,再析构父类的。

测试代码

class Person
{
public:
    Person(const char* name = "peter")
        : _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)
        : Person(name)
        , _num(num)
    {
        cout << "Student()" << endl;
    }
    Student(const Student& s)
        : Person(s)
        , _num(s._num)
    {
        cout << "Student(const Student& s)" << endl;
    }
    Student operator=(const Student& s)
    {
        if(&s != this)
        {
            Person::operator=(s);
            _num = s._num;
        }
        cout << "Student(const Student& s)" << endl;
        return *this;
    }
    ~Student()
    {
        cout << "~Student()" << endl;
    }

protected:
    int _num; //学号
};
void Test()
{
    Student s("Jona", 18);
}

 六.继承与友元

友元函数不能类继承,也就是说基类友元不能访问子类私有和保护成员

C++------继承_第24张图片

想要不报错,需要在子类也添加上友元函数。 

七、继承与静态成员 

静态成员的继承不会重新生成,而是同一份。

图中我们可以看到Person类和Student类的_count地址一样。

C++------继承_第25张图片

你可能感兴趣的:(c++,开发语言)