C++系列总结——继承
前言
前面讲了封装,但封装只是隐藏了类内部实现。如果使用多态隐藏类本身的话,只有封装是不够的,还需要继承。
继承
通过封装。我们把一些相关的函数和变量包裹在了一起,这些函数和变量就叫做类的成员函数和成员变量。继承就是一种获取这个类的成员函数和成员变量的方式。通常,继承了某个类的类叫做该类的派生类或者子类。
根据封装的意义,当父类将部分成员函数和成员变量的访问权限设置为private时,即使被继承了,子类仍然无法访问。
下面通过例子来说明一下,子类是如何保存这些继承来的成员函数和成员变量的。
class A
{
public:
A() : a( 1 )
{
}
void foo()
{
std::cout << "A::foo()" << std::endl;
return;
}
private:
int a;
};
class B : public A
{
public:
B() : b( 2 )
{
}
private:
int b;
};
int main()
{
B x;
x.foo();
return 0;
}
继承可以是public、protected或private,不同关键字为父类设置了不同访问权限。
- public继承意味着父类所有成员成员变量的访问权限在子类中维持不变
- protected继承意味着父类中public的成员函数和成员变量在子类中变为protected
- private继承意味着父类中public和protected的成员函数和成员变量在子类中变为private
成员函数
因为类成员函数可以通过隐式参数this区分具体的调用对象,所以类成员函数只需要存在一份就可以。当子类继承父类的成员函数时,子类只是得到了通过子类对象访问父类成员函数的权利。
隐式参数意味着你没有写,但是编译器帮你写了。
当我们gdb调试上面的代码时,会发现x.foo()实际调用的就是A::foo(),而不是A::foo()的一份拷贝。
0x00000000004004fe <+8>: lea -0x10(%rbp),%rax # -0x10(%rbp)就是x的地址
0x0000000000400502 <+12>: mov %rax,%rdi # 将x的地址作为A::foo()的参数,也就是this
0x0000000000400505 <+15>: callq 0x400512 <A::foo()>
其实任何函数都只需要存在一份,成员函数只是一个稍微特殊的函数。
虚函数又是一个稍微特殊的成员函数,它也只存在一份,只不过是在调用上可能要多些操作,细节在讲多态的时候再说。
成员变量
每个类的实例对象都要变更自己的成员变量,因此其空间肯定都是独立的。当子类继承父类的成员变量时,实际只是继承了父类的数据结构。
当通过gdb打印x的值时,我们会发现它的结构如下
(gdb) p x
$1 = {<A> = {a = 1}, b = 2}
当我们直接查看x的地址的内容时,会发现A::a和B::b就是连续排布的。
(gdb) x /2x &x
0x7fffffffe540: 0x00000001 0x00000002
也就是说当子类继承父类时,子类的数据结构就是父类的成员变量加上子类自身的成员变量。
之所以父类的成员变量放在前,是因为父类指针可以直接指向子类,当以父类指针操作父类成员变量时就不需要额外进行地址偏移了。如果子类成员变量在前,那么父类指针操作时还需要跳过子类成员变量。
我们大胆推测当子类继承多个父类时,子类的数据结构就是写在前的父类的成员变量加上写在后的父类的成员变量再加上子类自身的成员变量,事实也确实如此。
多继承时,因为存在多个父类数据结构,所以当不同的父类指针指向子类时,会进行一定偏移,保证该父类指针刚好指向自己的数据结构的起始位置。
多继承会复杂化类关系图,而且在一些场景下会带来歧义,因此都不建议使用多继承。反正我自己到现在为止都没在实际项目中用过,只是在一些开源代码中看到过。
结语
继承除了是多态的基础外,还是一种复用代码的方式。但是谨记只有存在父子关系时才使用继承,如果只是为了复用代码的话,应当使用组合。
C++系列总结——继承的更多相关文章
- C++ 系列:继承
Copyright © 1900-2016, NORYES, All Rights Reserved. http://www.cnblogs.com/noryes/ 欢迎转载,请保留此版权声明. -- ...
- Python基础系列讲解——继承派生和组合的概念剖析
Python作为一门面向对象的语言,它的面向对象体系中主要存在这么两种关系,一个是“类”和“实例”的关系,另一个是“父类”和“子类”的关系. 所谓“类”是从一堆对象中以抽象的方式把相同的特征归类得到的 ...
- Java入门系列之类继承、抽象类、接口(五)
前言 C#和Java关于类.抽象类.接口使用方式基本相似,只是对应关键字使用不同罢了,本节呢,我们只是对照C#和Java中关于这三个概念在具体使用时,看看有哪些不一样的地方. 类继承 C#和Java在 ...
- Java基础系列 - 抽象类继承和接口实现
package com.inter; /** * 继承和接口的关系,单继承,多接口 * java不支持多继承,但可通过接口实现多重继承 */ public class test2 { public s ...
- Java基础系列 - 子类继承父类,调用父类的构造函数
package com.test7; public class test7 { public static void main(String[] args) { Son son = new Son(1 ...
- JavaScript总结3—对象
对象是JavaScript的基本类型,他可以从一个称为原型的对象继承属性,这种原型式继承是JavaScript的核心特征.对对象比较常见的操作有:创建,设置,查找,删除,检测和枚举他的属性.每个对象都 ...
- 简学Python第二章__巧学数据结构文件操作
#cnblogs_post_body h2 { background: linear-gradient(to bottom, #18c0ff 0%,#0c7eff 100%); color: #fff ...
- 从零开始学 Web 之 CSS(二)文本、标签、特性
大家好,这里是「 Daotin的梦呓 」从零开始学 Web 系列教程.此文首发于「 Daotin的梦呓 」公众号,欢迎大家订阅关注.在这里我会从 Web 前端零基础开始,一步步学习 Web 相关的知识 ...
- Css学习(2)
1 标签分类(显示方式) 块元素 典型代表,Div,h1-h6,p,ul,li 特点: ★独占一行 ★可以设置宽高 ★ 嵌套(包含)下,子块元素宽度(没有定义情况下)和父块元素宽度默认一致. 行内元素 ...
随机推荐
- Scala 枚举介绍及深入应用
本文详细地总结了Scala枚举的几种实现方式,对我们更好地进行函数式编程有很好地指导和帮助. Scala 枚举示例和特性 枚举(Enumerations)是一种语言特性,对于建模有限的实体集来说特别有 ...
- SpringCloud分布式微服务搭建(三)
本例子是一个springcloud的configserver,client例子 利用git存储各个服务的配置文件 server获取配置文件的仓库位置,并把server注册到eureka中,同时为了实现 ...
- [数据库锁机制] 深入理解乐观锁、悲观锁以及CAS乐观锁的实现机制原理分析
前言: 在并发访问情况下,可能会出现脏读.不可重复读和幻读等读现象,为了应对这些问题,主流数据库都提供了锁机制,并引入了事务隔离级别的概念.数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务 ...
- .net core 杂记:日记记录
ASP.NET Core 有内置的log组件,遗憾的是看了微软官方文档,貌似无法直接将日志存于文件或数据库,只能由自己实现或引用第三方日志组件. 以下为Nlog和log4net的使用记录 Nlog使用 ...
- 【响应式编程的思维艺术】 (5)Angular中Rxjs的应用示例
目录 一. 划重点 二. Angular应用中的Http请求 三. 使用Rxjs构建Http请求结果的处理管道 3.1 基本示例 3.2 常见的操作符 四. 冷热Observable的两种典型场景 4 ...
- 文件进行MD5计算
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- Odoo : 门店订货及在线签名免费开源方案
引言 Odoo是欧洲开发的,世界排名第一的开源免费ERP系统.该系统从2002开始研发,经过十几年的发展,去年下半年发布了12.0版.该软件因为免费下载,源代码开放,吸引了世界范围很多人参与使用及开发 ...
- Docker 创建 Crowd3.3.2 以及打通 Jira Software7.12.3和Confluence6.12.2 SSO 单点登录
目录 目录 1.介绍 1.1.什么是Crowd? 2.Crowd 的官网在哪里? 3.如何下载安装? 4.对 Crowd 进行配置 4.1.破解 Crowd 第一步 4.2.破解 Crowd 第二步, ...
- Jmeter接口测试-断言
JMeter接口测试-断言 对应qq群号:616961231 一个http请求发出,怎么判断执行的是否正确呢? 通过检查服务器响应数据,是否符合预期的数据, 如果是,任务成功, 如果否, 任务失败 ...
- 题目:python 打印出如下图案(菱形):
# 题目:打印出如下图案(菱形): # # * # *** # ***** # ******* # ***** # *** # * nu = 1 # 开始值 k = 2 # 变量值 while nu ...