c++继承


前言

继承( inheritance)。继承是软件复用的一种方式,通过继承,可以在吸收现有类的各种性能(即数据和行为)的基础上,再加以定制或增强来创建新类。
C++提供了三类继承: public(公有的)、protected(受保护的)和 private(私有的)继承。


一、基类和派生类

1.基类和派生类

事实上,继承和派生是密不可分的,是一般与特殊的关系,就像水果与苹果的关系。继承就是保留祖先类的东西,派生是在前者的基础上,派生出自己特有的东西。基类更加通用,而派生类更加具体
在各种形式的继承中,基类的private成员都不能被它的派生类直接访问,但是这些private 基类成员仍得到了继承(即它们仍被视为是派生类的一部分)
通过从基类继承而来的成员函数,派生类能够操作基类中的 private 成员(但需要这些继承而来的成员函数在基类中提供这种功能)。
要注意的是,友元函数是不被继承的。

2.基类和派生类之间的关系

使用继承时,类层次结构中所有类共同的数据成员和成员函数在基类中声明。当需要对这些共同特征进行修改时,程序员只需在基类中进行修改,于是派生类也就继承了相应修改。如果不采用继承机制,则需要对所有包含有问题代码副本的源代码文件一一进行修改。
在派生类构造函数调用其基类的构造函数时,如果传递给基类构造函数的参数,它的个数和类型与基类构造函数的相应定义不符,将导致编译错误。
在派生类的构造函数中,采用成员初始化器列表显式地调用基类的构造函数和初始化成员对象,可以防止重复初始化,即调用了默认构造函数之后,又在派生类构造函数中再次修改数据成员。

3.protected数据

使用protected访问在public和 private 访问之间提供了一级折中的保护。基类的protected成员既可以在基类的体内被基类的成员和友元访问,又可以被由基类派生的任何类的成员和友元访问。
把基类的数据成员声明为 protected,这样派生类就可以直接修改这些数据。因为直接访问protected 数据成员可以免去调用设置或获取成员函数的开销,所以继承protected 数据成员会使程序的性能稍稍有所提高。

使用protected数据将产生两个问题:

  • 派生类对象不必使用成员函数设置基类的protected数据成员的值。因此,派生类可以很容易地将无效的值赋给基类的 protected 数据,导致对象处于不一致的状态。
  • 派生类成员函数实现很可能太依赖基类的实现。实际上,派生类应该只依赖基类提供的服务(也就是非 private 成员函数),而不应该依赖于基类的实现。当使用了基类的protected数据时,如果修改了基类的实现,那么同时还可能需要修改该基类所有的派生类。在这种情况下,我们称该程序是“脆弱”的,因为基类中的一个小的改动就可以“破坏”派生类的实现。程序员应该能够修改基类的实现,同时仍旧能够向派生类提供相同的服务。当然,如果基类提供的服务改变了,就必须重新实现派生类。

4.利用成员函数get访问数据成员

我们调用这个类的获取和设置成员函数访问它的私有数据成员。如果决定更改这些数据成员的名称,那么无须修改函数的定义,只需修改直接操作这些数据成员的获取和设置成员函数即可。这些修改只发生在基类中,派生类无须丝毫变动。
利用成员函数访问数据成员的值可能比直接访问这些数据稍慢些。但是,如今优化的编译器经过精心设置,可以隐式地执行许多优化工作。所以,程序员应该致力于编写出符合软件工程原则的代码,而将优化问题留给编译器去做。一条好的准则是:“不要怀疑编译器”。

二、派生类中的构造函数和析构函数

1.构造函数

实例化派生类的对象启动了一连串构造函数的调用,其中派生类的构造函数在执行它自己的任务之前,先显式地调用(通过基类成员的初始化器)或隐式(调用基类的默认构造函数)地调用其直接基类的构造函数。同样,如果该基类也是从其他的类派生而来的,则该基类构造函数需调用类层次结构中直接在该基类上的类的构造函数。在这个构造函数调用链中,调用的最后一个构造函数是在继承层次结构中最顶层的构造函数,但是实际上它的函数体是最先执行完毕的,最早调用的派生类构造函数最晚完成其函数体的执行。每个基类构造函数初始化派生类对象继承的该基类的数据成员。
当程序创建一个派生类对象时,派生类构造函数立即调用基类的构造函数,基类的构造函数的函数体执行,然后派生类的成员初始化器执行,最后派生类构造函数的函数体执行。如果这时的继承层次结构有多层,那么这一过程还将向上翻滚。

2.析构函数

当销毁派生类的对象时,程序将调用对象的析构函数。这又将展开一连串的析构函数调用,其中派生类的析构函数,派生类的直接基类、派生类的间接基类及类的成员的析构函数,会按照它们构造函数执行次序的相反顺序依次执行。当调用派生类对象的析构函数时,该析构函数执行其任务,然后调用继承层次结构中上一层基类的析构函数。这一过程重复进行,直到继承层次结构顶层的最后一个基类的析构函数被调用。之后,该对象就从内存中被删除了。


假设我们创建一个派生类对象,这个派生类及其基类中都包含(通过组成)其他类的对象。当这个派生类的对象被创建时,首先执行基类成员对象的构造函数,然后执行基类构造函数的函数体,接着执行派生类成员对象的构造函数,最后执行派生类构造函数的函数体。派生类对象析构函数的调用顺序与相应的构造函数的调用顺序正好相反。
派生类不会继承基类的构造函数、析构函数和重载的赋值运算符。但是,派生类的构造函数、析构函数和重载的赋值运算符可以调用基类的构造函数、析构函数和重载的赋值运算符函数。

public、protected和 private继承

派生类中基类成员可访问性的总结

在这里插入图片描述

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值