C++的三种继承方式详解以及区别


前言

我发现有时候概念性的东西,理解起来还是很难的,于是本文用简单的几个例子,来说明这三种不同的继承方式,他们之前的区别~


一、public继承

  • 基类的publicprotected成员的访问属性在派生类中保持不变,但基类的private成员不可直接访问

  • 派生类中的成员函数可以直接访问基类中的publicprotected成员,但不能直接访问基类的private成员。

  • 通过派生类的对象访问从基类继承的成员,只能访问public成员。

#include<iostream>

using namespace std;

class CFather
{
public:
int m_testA{0};
protected:
int m_testB{0};
private:
int m_testC{0};
}; class CSon: public CFather
{
void test()
{
m_testA = 1; // 编译正确 :public 继承后,在内部或者外部都可以访问public成员
m_testB = 1; // 编译正确 :public 继承后,在内部可以访问protected成员
m_testC = 1; // 编译错误 :无论哪种继承,都无法访问private成员
}
}; int main()
{
CSon _test; _test.m_testA = 2; // 编译正确 :public 继承后,在内部或者外部都可以访问public成员
_test.m_testB = 2; // 编译错误 :public 继承后,在外部无法访问protected成员
_test.m_testC = 2; // 编译错误 :无论哪种继承,都无法访问private成员 system("pause");
return 0;
}

二、protected继承

  • 基类的publicprotected成员都以private身份出现在派生类中,但基类的private成员不可直接``访问。
  • 派生类中的成员函数可以直接访问基类中的publicprotected成员,但不能直接访问基类的private成员。
  • 通过派生类的对象不能直接访问从基类继承的任何成员。
#include<iostream>

using namespace std;

class CFather
{
public:
int m_testA{0};
protected:
int m_testB{0};
private:
int m_testC{0};
}; class CSon: protected CFather
{
void test()
{
m_testA = 1; // 编译正确 :protected 继承后,在内部可以访问public成员
m_testB = 1; // 编译正确 :protected 继承后,在内部可以访问protected成员
m_testC = 1; // 编译错误 :无论哪种继承,都无法访问private成员
}
}; int main()
{
CSon _test; _test.m_testA = 2; // 编译错误 :protected 继承后,在外部无法访问public成员
_test.m_testB = 2; // 编译错误 :protected 继承后,在外部无法访问protected成员
_test.m_testC = 2; // 编译错误 :无论哪种继承,都无法访问private成员 system("pause");
return 0;
}

此时,可以这么理解为 派生类 通过 protected继承 基类 之后 ,基类 中的 public变成了protected,其他保持原样。

class CFather
{
protected:// proteced 继承之后public变成了 proteced
int m_testA{0};
protected:
int m_testB{0};
private:
int m_testC{0};
};

三、private继承

  • 基类的publicprotected成员都以private身份出现在派生类中,但基类的private成员不可直接访问
  • 派生类中的成员函数可以直接访问基类中的publicprotected成员,但不能直接访问基类的private成员。
  • 通过派生类的对象不能直接访问从基类继承的任何成员。
#include<iostream>

using namespace std;

class CFather
{
public:
int m_testA{0};
protected:
int m_testB{0};
private:
int m_testC{0};
}; class CSon: private CFather
{
void test()
{
m_testA = 1; // 编译正确 :private 继承后,在内部可以访问public成员
m_testB = 1; // 编译正确 :private 继承后,在内部可以访问protected成员
m_testC = 1; // 编译错误 :无论哪种继承,都无法访问private成员
}
}; int main()
{
CSon _test; _test.m_testA = 2; // 编译错误 :private 继承后,在外部无法访问public成员
_test.m_testB = 2; // 编译错误 :private 继承后,在外部无法访问protected成员
_test.m_testC = 2; // 编译错误 :无论哪种继承,都无法访问private成员 system("pause");
return 0;
}

此时,可以这么理解为 派生类 通过 private继承 基类 之后 ,基类 中的 publicprotected变成了private,其他保持原样。

class CFather
{
private:// private 继承之后public变成了 private
int m_testA{0};
private:// private 继承之后protected变成了 private
int m_testB{0};
private:
int m_testC{0};
};

四、三者区别

  • public继承方式

    • 基类中所有 public 成员在派生类中为 public 属性;
    • 基类中所有 protected 成员在派生类中为 protected 属性;
    • 基类中所有 private 成员在派生类中不能使用。
  • protected继承方式

    • 基类中的所有 public 成员在派生类中为 protected 属性;
    • 基类中的所有 protected 成员在派生类中为 protected 属性;
    • 基类中的所有 private 成员在派生类中不能使用。
  • private继承方式

    • 基类中的所有 public 成员在派生类中均为 private 属性;
    • 基类中的所有 protected 成员在派生类中均为 private 属性;
    • 基类中的所有 private 成员在派生类中不能使用。

下表汇总了不同继承方式对不同属性的成员的影响结果

继承方式/基类成员 public成员 protected成员 private成员
public继承 public protected 不可见
protected继承 protected protected 不可见
private继承 private private 不可见

五、总结

1.不管继承方式如何,基类中的 private 成员在派生类中始终不能使用(不能在派生类的成员函数中访问或调用)。

2.如果希望基类的成员能够被派生类继承并且毫无障碍地使用,那么这些成员只能声明为 public 或 protected;只有那些不希望在派生类中使用的成员才声明为 private。

3.如果希望基类的成员既不向外暴露(不能通过对象访问),还能在派生类中使用,那么只能声明为 protected。

4.基类成员在派生类中的访问权限不得高于继承方式中指定的权限。例如,当继承方式为 protected 时,那么基类成员在派生类中的访问权限最高也为 protected,高于 protected 的会降级为 protected,但低于 protected 不会升级。再如,当继承方式为 public 时,那么基类成员在派生类中的访问权限将保持不变。


后话

我们这里说的是基类的 private 成员不能在派生类中使用,并没有说基类的 private 成员不能被继承。实际上,基类的 private 成员是能够被继承的,并且(成员变量)会占用派生类对象的内存,它只是在派生类中不可见,导致无法使用罢了。private 成员的这种特性,能够很好的对派生类隐藏基类的实现,以体现面向对象的封装性。由于 private 和 protected 继承方式会改变基类成员在派生类中的访问权限,导致继承关系复杂,所以实际开发中我们一般使用 public。

C++的三种继承方式详解以及区别的更多相关文章

  1. python selenium 三种等待方式详解[转]

    python selenium 三种等待方式详解   引言: 当你觉得你的定位没有问题,但是却直接报了元素不可见,那你就可以考虑是不是因为程序运行太快或者页面加载太慢造成了元素不可见,那就必须要加等待 ...

  2. js的2种继承方式详解

    js中继承可以分为两种:对象冒充和原型链方式 一.对象冒充包括三种:临时属性方式.call()及apply()方式1.临时属性方式 复制代码代码如下: function Person(name){   ...

  3. Python selenium 三种等待方式详解

    1. 强制等待第一种也是最简单粗暴的一种办法就是强制等待sleep(xx),强制让闪电侠等xx时间,不管凹凸曼能不能跟上速度,还是已经提前到了,都必须等xx时间.看代码: # -*- coding: ...

  4. JavaScript五种继承方式详解

    本文抄袭仅供学习http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance.html 一. 构造函数绑定 ...

  5. Python selenium 三种等待方式详解(必会)

    很多人在群里问,这个下拉框定位不到.那个弹出框定位不到…各种定位不到,其实大多数情况下就是两种问题:1 有frame,2 没有加等待.殊不知,你的代码运行速度是什么量级的,而浏览器加载渲染速度又是什么 ...

  6. SQL-----数据库三种删除方式详解

    第一种  使用delete  语句 特点: delete 属于数据库操纵语言DML,表示删除表中的数据, 删除过程是每次从表中删除一行,并把该行删除操作作为事务记录在日志中保存 可以配合事件(tran ...

  7. Selenium 三种等待方式详解

    我们在做WEB自动化时,一般要等待页面元素加载完成后,才能执行操作,否则会报找不到元素的错误,这样就要求我们在有些场景下加等待时间. 我们平常用到的有三种等待方式: 强制等待 隐式等待 显示等待 一. ...

  8. Selenium:三种等待方式详解

    我们在做WEB自动化时,一般要等待页面元素加载完成后,才能执行操作,否则会报找不到元素的错误,这样就要求我们在有些场景下加等待时间. 我们平常用到的有三种等待方式: 强制等待 隐式等待 显示等待 一. ...

  9. Spring事务Transaction配置的五种注入方式详解

    Spring事务Transaction配置的五种注入方式详解 前段时间对Spring的事务配置做了比较深入的研究,在此之间对Spring的事务配置虽说也配置过,但是一直没有一个清楚的认识.通过这次的学 ...

随机推荐

  1. 几种常用的MOS管参数、应用电路及区别:IRF540N、IRF9540N、IRF9540

    1. IRF540N,N沟道,100V,33A,44mΩ@10V 栅极(Gate-G,也叫做门极),源极(Source-S), 漏极(Drain-D) 漏源电压(Vdss) 100V 连续漏极电流(I ...

  2. 论文解读(MVGRL)Contrastive Multi-View Representation Learning on Graphs

    Paper Information 论文标题:Contrastive Multi-View Representation Learning on Graphs论文作者:Kaveh Hassani .A ...

  3. 基于MRS-ClickHouse构建用户画像系统方案介绍

    业务场景 用户画像是对用户信息的标签化.用户画像系统通过对收集的各维度数据,进行深度的分析和挖掘,给不同的用户打上不同的标签,从而刻画出客户的全貌.通过用户画像系统,可以对各个用户进行精准定位,从而将 ...

  4. KestrelServer详解[2]: 网络链接的创建

    <注册监听终结点(Endpoint)>已经详细讲述了如何使用KestrelServer,现在我们来简单聊聊这种处理器的总体设计和实现原理.当KestrelServer启动的时候,注册的每个 ...

  5. springboot项目yml中使用中文注释报错的解决方法1

    启动springboot项目时报错:/application.yml.....这大致就是说application.yml有问题,那么目前我所知道的大致两种情况会报错,第一种是yml格式有问题,要注意缩 ...

  6. Linux下离线安装docker与fastDFS

    一.Linux下离线安装Docker 基础环境 1.操作系统:CentOS 7 2.Docker版本:docker-19.03.9.tgz 官方下载地址(打不开可能需要科学-上网) 3.官方参考文档: ...

  7. su 和 sudo的区别

    su是一个命令,可切换其他用户进行操作:而 '-' 号则是代表是否完全切换指定的用户环境信息 sudo是一个服务,可通过/etc/sudoers进行配置文件,让被限制的用户只能执行被授予的命令操作.

  8. Spring根据路径前缀获取不同Resource

    相关文章:https://www.jianshu.com/p/5bab9e03ab92 官方文档:https://docs.spring.io/spring/docs/current/spring-f ...

  9. jvm性能调优工具

    1.jstat 命令 jstat: 查看类装载,内存,垃圾收集,gc相关信息 命令参数 # jstat -option -t #option:参数选项,-t:显示系统的时间 # jstat -opti ...

  10. Mybatis入门程序(一)

    1.入门程序实现需求 根据用户id查询一个用户信息 根据用户名称模糊查询用户信息列表 添加用户(二) 更新用户(二) 删除用户(二) 2.引入Mybatis所需 jar 包(Maven工程) < ...