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 特点: ★独占一行 ★可以设置宽高 ★ 嵌套(包含)下,子块元素宽度(没有定义情况下)和父块元素宽度默认一致. 行内元素 ...
随机推荐
- Mybatis配置详解
一.SqlSession的使用范围说明 1.SQLSessionFactoryBuilder 通过SqlSessionFactoryBuilder创建会话工厂SqlSessionFactory, ...
- 深入学习Redis(3):主从复制
前言 在前面的两篇文章中,分别介绍了Redis的内存模型和Redis的持久化. 在Redis的持久化中曾提到,Redis高可用的方案包括持久化.主从复制(及读写分离).哨兵和集群.其中持久化侧重解决的 ...
- Jenkins配置从节点
配置从节点步骤 在Master的站点上创建节点配置信息 在Slave访问Jenkins站点,然后下载运行服务Slave端必须安装Jdk 两种运行方式: windows 服务 运行jar包 成功后的节点 ...
- maven构建失败。
maven项目编译报“Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1” 解决方案:setting.x ...
- “崩溃了?不可能,我全 Catch 住了” | Java 异常处理
前言 今天我们来讨论一下,程序中的错误处理. 在任何一个稳定的程序中,都会有大量的代码在处理错误,有一些业务错误,我们可以通过主动检查判断来规避,可对于一些不能主动判断的错误,例如 RuntimeEx ...
- python 生成 1900-2100 的二十四节气文件
[学习笔记] 转载 #!/usr/bin/python3.7# -*- coding:utf-8 -*- '''整体思路1:根据公式算出节气日期 1900 年到 2100 200 年的时间2:特殊的 ...
- 图解CSS3-flex布局
前言 最近笔者在复习以前基础知识,发现很多细的知识点还是需要重新再总结一番.本文对flex布局进行图解说明,以后忘了的同学可以随时过来查看,欢迎转载,烦请注明出处. 主体 万丈高楼平地起,熟悉flex ...
- Android之Fragment详解
文章大纲 一. 什么是Fragment二. Fragment生命周期三. Fragment简单实例四.Fragment实战五.项目源码下载六.参考文章 一. 什么是Fragment Fragmen ...
- C# 接口《通俗解释》
接口 为什么要用接口?好处在哪里? 如果你的工作是一个修水管的,一天客户找上你让你帮装水管,但是有个要求,就是客户喜欢管子是三角形的. 你立马买了三角形的水管回来,在墙上弄个三角形的口子,客户付了钱, ...
- Linux常用命令速查-汇总篇
Linux常用命令速查-用户管理 Linux常用命令速查-文件管理 Linux常用命令速查-系统监控 Linux常用命令速查-网络管理 Linux常用命令速查-定时任务 Linux常用命令速查-Vim