1.什么是面向对象的继承
【1】类的继承案例
- 基类为:person,派生类为man,所有权限均为public
- 演示1:派生类“继承”了基类的成员变量
- 演示2:派生类“继承”了基类的成员方法
/*----------person.hpp-----------*/
#ifndef __PERSON_HPP__
#define __PERSON_HPP__
#include <string>
using namespace std;
class person
{
public:
//成员变量
string name;
int age;
//构造函数
//成员方法
void eat(void);
private:
};
#endif
/*----------person.cpp-----------*/
#include "person.hpp"
#include <iostream>
using namespace std;
void person::eat(void)
{
cout << name << " " << "eat" << endl;
}
/*----------man.hpp-----------*/
#ifndef __MAN_HPP__
#define __MAN_HPP__
#include "person.hpp"
class man:public person
{
public:
void work(void);
private:
protected:
};
#endif
/*----------man.cpp-----------*/
#include "man.hpp"
#include <iostream>
using namespace std;
void man::work(void)
{
cout << "coding" <<endl;
}
/*----------main.cpp-----------*/
#include "person.hpp"
#include "man.hpp"
int main(int argc, char const *argv[])
{
man lisi;
lisi.name = "LISI";
lisi.age = 33;
lisi.eat();
lisi.work();
return 0;
}
/*----------makefile-----------*/
all:
g++ person.cpp man.cpp main.cpp -o app
- C++类的继承语法如下:
class 派生类名:访问控制 基类名1,访问控制 基类名2,访问控制 基类名n //你可以想象它有很多干爹
{
// 成员变量和成员方法列表(除了构造和析构之外的成员方法)
};
【2】继承有关的几点细节
- 继承特性可以让派生类“瞬间”拥有基类的所有(当然还得考虑权限)属性和方法
- 派生类,范围小,具体。 基类,范围大,抽象;派生类又叫子类,基类又叫父类。
- 类在C++编译器的内部可以理解为结构体,派生类是由基类成员叠加派生类新成员得到的
- 继承(inheritance)和组合(composition)是软件重用的2种有效方式
- 继承是C++源生支持的一种语法特性,是C++面向对象的一种表现
- 继承特性本质上是为了代码复用
2.C++继承中的权限管控
【1】C++类中的访问权限管控回顾
public | 类内部可以访问,类的外部可以访问 |
---|---|
private | 类内部可以访问,类的外部不能访问 |
protected | 类内部可以访问,类的外部不能访问 |
【2】继承时的三种权限设置对派生类的影响
public继承(公有继承) | 父类成员在子类中保持原有访问级别 |
---|---|
private继承(私有继承) | 父类成员在子类中变为private成员 |
protected继承(保护继承) | 父类中public成员会变成protected,父类中protected成员仍然为protected,父类中private成员仍然为private |
继承时默认情况下 | 派生类为class时是private继承,而派生类为struct时是public继承 |
【3】设计类时如何规定成员的访问权限
- 需要被外界访问的成员直接设置为public
- 只能在当前类中访问的成员设置为private
- 只能在当前类和子类中访问的成员设置为protected。
【4】三种继承下父类和子类之间成员权限的改变
父类中成员的权限 | 子类继承方式 | 继承到子类之后的权限 | 解析 |
---|---|---|---|
public成员 | public继承 | 在子类中是public的 | 类内部可以访问,子类对象外部可以访问 |
private成员 | public继承 | 在子类中是比private还可怜 | 不能被直接访问,只能通过子类从父类继承而来的父类里实现了的成员函数来间接访问。 |
protected成员 | public继承 | 在子类中是protected的 | 类内部成员可以访问,子类对象外部不可以访问 |
总结:public继承,对于父类中public和protected成员的权限在子类中,其实是没有增强也没有削弱的;但是对于父类中private成员,其实在子类中是有削弱的(比private还可怜)。
父类中成员的权限 | 子类继承方式 | 继承到子类之后的权限 | 解析 |
---|---|---|---|
public成员 | private继承 | 在子类中是private的 | 类内部成员可以访问,子类对象外部不可以访问 |
private成员 | private继承 | 在子类中是比private还可怜 | 不能被直接访问,只能通过子类从父类继承而来的父类里实现了的成员函数来间接访问。 |
protected成员 | private继承 | 在子类中是private的 | 类内部成员可以访问,子类对象外部不可以访问 |
总结:如果是private继承,那么父类中的public成员和protected成员就变成了子类中的private成员,父类中的private成员成了子类中比private还可怜的那种成员。
父类中成员的权限 | 子类继承方式 | 继承到子类之后的权限 | 解析 |
---|---|---|---|
public成员 | protected继承 | 在子类中是protected的 | 类内部成员可以访问,子类对象外部不可以访问 |
private成员 | protected继承 | 在子类中是比private还可怜 | 不能被直接访问,只能通过子类从父类继承而来的父类里实现了的成员函数来间接访问。 |
protected成员 | protected继承 | 在子类中是protected的 | 类内部成员可以访问,子类对象外部不可以访问 |
总结:如果是protected继承,那么父类中的public成员和protected成员就变成了子类中的protected成员,父类中的private成员成了子类中比private还可怜的那种成员。
【5】using关键字在非public继承时的权限重开作用
- 父类的public方法在private/protected继承时,到了子类就成了private/protected而不是public了,无法用子类对象来调用了
- 解决方法1是改为public继承,有用但是有时候不得不protected或者private继承时就没办法了
- 解决方法2是在子类中再实现一个public的方法,内部调用父类继承而来的那个方法,能用但是有点麻烦而且有额外开销
- 解决方法3是在子类中使用using关键字将该方法声明为public访问权限,本质上类似于权限打洞
- 用法:在子类public声明中使用 using Base::func; 即可,不带返回值类型不带参数列表。
- 注意:using只用于private/protected继承中的权限损失找回,如果方法在父类中本来就是private的子类中没法using后访问
3.继承体系下子类和父类的关系
【1】本质上是2个独立的类
- 继承只是通过父类来快速构建子类的一种语法技术,继承后得到的子类和父类是独立的2个类
- 程序中子类的对象和父类的对象是2个独立的对象,没有任何关系,只是形成对象的模板有部分相同
- 子类对象中访问的子类从父类继承而来的成员,其实是属于子类自己的,并不是父类(对象)里面的
【2】站在子类角度看继承
- 非继承体系下的类,完全是自己“手工”构建的,所有成员根据访问权限不同而分为1个层级3大块(public,private,protected)。
- 继承体系下的子类,部分直接从父类继承,部分自己手工打造,所有成员分成2个层级(继承来的,自己写的),每个层级3大块(访问权限)
- 继承就是子类在构建自己的过程中使用的一种快速批量成员获取方法而已
【3】为什么父类private成员在子类中还有
- 思考:父类的所有成员在子类中都必须有吗?有没有可能父类有一个成员其实子类没必要具备的?
- 思考:如何做到在继承时让程序员指定父类的哪些成员参与继承,哪些不参与?
- 选择:继承就是父类所有成员全部按分类规则传给子类
【4】为什么父类private成员在子类中还有但不能直接访问
- 思考:这个规定是天然的,还是人为规定的?其实是:人为规定的。 因为:访问权限这一套本身就是人为的
- 为什么这样设计1:如果能直接访问,那就打破了父类private的含义,破坏了class的封装性
- 为什么这样设计2:父类的private成员在子类中很大可能本来就不需要去访问,所以能直接访问反而有风险,没必要
- 为什么这样设计3:间接访问合乎一个原则:在哪里定义的成员变量在哪里操作。子类和父类不是一个人写的时尤其要这样,避免问题