c++ 基础知识回顾 继承 继承的本质就是数据的copy
c++ 基础知识笔记
继承
什么是继承 继承就是子类继承父类的成员属性以及方法
继承的本质就是 数据的复制 是编译器帮我们做了很多操作
class Base
{
public:
Base(){
cout << "Base 构造函数"<< endl;
}
~Base(){
cout << "Base 析构函数" << endl;
}
};
class Sub : public Base
{
public:
Sub(){
cout << "Sub 构造函数"<< endl;
}
~Sub(){
cout << "Sub 析构函数"<<endl;
}
};
void Test(){
Sub sub;
cout << sizeof(sub)<<endl;
}

这个时候我们打印出来的 Sub的大小是1
因为它没有任何数据
如果说我们这个时候在Base 和Sub类中各自增加两个int 类型的成员变量 我们再来看看Sub的大小
class Base
{
public:
Base(){
cout << "Base 构造函数"<< endl;
}
~Base(){
cout << "Base 析构函数" << endl;
}
private:
int x;
int y;
};
class Sub : public Base
{
public:
Sub(){
cout << "Sub 构造函数"<< endl;
}
~Sub(){
cout << "Sub 析构函数"<<endl;
}
public:
int a;
int b;
};
void Test(){
Sub sub;
cout << sizeof(sub)<<endl;
}

这个时候我们可以看到结果变成了16
为什么是 16呢 因为Base 与 Sub各自有两个int类型的成员变量 int 类型占用4个字节 所以Sub自己有两个int类型的变量 然后又继承了 Base的 所以这个时候的Sub大小就是 以Base为起始+Sub的大小所以就是16个字节
然后我们在构造函数中给这两个类的各自成员赋上初始值再观察下反汇编的代码


我们仔细看 编译器帮我们分配了 Sub类的临时内存
我们仔细看一下ECX 存储的就是 我们定义的Sub类的首地址
大小 正好是16个字节 目前还未初始化 所以使用CC填充
下面就是直接调用了Sub类的构造函数我们单步进去看看

我们跟到Sub的构造函数中可以很明显的看到 先调用了 基类Base 的构造函数 完成Base的成员初始化
然后再初始化Sub类中自身的成员变量
push ebp
004018B1 mov ebp,esp
004018B3 push 0FFh
004018B5 push offset __ehhandler$??0Sub@@QAE@XZ (00447599)
004018BA mov eax,fs:[00000000]
004018C0 push eax
004018C1 mov dword ptr fs:[0],esp
004018C8 sub esp,44h
004018CB push ebx
004018CC push esi
004018CD push edi
004018CE push ecx
004018CF lea edi,[ebp-50h]
004018D2 mov ecx,11h
004018D7 mov eax,0CCCCCCCCh
004018DC rep stos dword ptr [edi]
004018DE pop ecx
004018DF mov dword ptr [ebp-10h],ecx
004018E2 mov ecx,dword ptr [ebp-10h]
004018E5 call @ILT+395(Base::Base) (00401190)
004018EA mov dword ptr [ebp-4],0
004018F1 push offset @ILT+215(std::endl) (004010dc)
004018F6 push offset string "Sub \xb9\xb9\xd4\xec\xba\xaf\xca\xfd" (0046e01c)
004018FB push offset std::cout (00479a28)
00401900 call @ILT+665(std::operator<<) (0040129e)
00401905 add esp,8
00401908 mov ecx,eax
0040190A call @ILT+500(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004011f9)
0040190F mov eax,dword ptr [ebp-10h]
00401912 mov dword ptr [eax+8],1Eh
00401919 mov ecx,dword ptr [ebp-10h]
0040191C mov dword ptr [ecx+0Ch],28h
00401923 mov dword ptr [ebp-4],0FFFFFFFFh
0040192A mov eax,dword ptr [ebp-10h]
0040192D mov ecx,dword ptr [ebp-0Ch]
00401930 mov dword ptr fs:[0],ecx
00401937 pop edi
00401938 pop esi
00401939 pop ebx
0040193A add esp,50h
0040193D cmp ebp,esp
0040193F call __chkesp (00406f70)
00401944 mov esp,ebp
00401946 pop ebp
00401947 ret
这里还可以很明显的看到 首先用 mov dword ptr [ebp-10h],ecx
把我们定义的Sub类的对象的首地址 存放到了 ebp-10h 的一个临时变量中
然后调用完基类Base的构造函数后
0040190F mov eax,dword ptr [ebp-10h]
00401912 mov dword ptr [eax+8],1Eh
00401919 mov ecx,dword ptr [ebp-10h]
0040191C mov dword ptr [ecx+0Ch],28h
对Sub类中的成员 a 、b分别赋值
mov dword ptr [eax+8],1Eh 这一段 可以 = [this+0x8] = 30
mov dword ptr [ecx+0Ch],28h 这一段 可以 = [this+0xc] = 40
有没有疑问说为什么 a的地址跑到了 this+8的位置了?
其实前8个字节已经被Base中的成员变量占用了
我们可以看看内存中的数据

可以看到 this+0 与 this+4 的位置分别存放了 十进制 的10、20的整数值
而this +8 与 this +0xc 的位置 分别存放了 十进制的 30 、40的整数值
到了这里 大家应该明白了 其实继承就是 数据的复制这个说法了吧 其实就是编译器帮我们自动生成了很多我们看不到的代码
现在看到这里 我提出一个小问题 怎么修改 Base中的x 和y的值呢?

相信聪明的你已经懂了

c++ 基础知识回顾 继承 继承的本质就是数据的copy的更多相关文章
- Java基础知识回顾(一):字符串小结
Java的基础知识回顾之字符串 一.引言 很多人喜欢在前面加入赘述,事实上去技术网站找相关的内容的一般都应当已经对相应知识有一定了解,因此我不再过多赘述字符串到底是什么东西,在官网中已经写得很明确了, ...
- C#基础知识回顾-- 反射(1)
C#基础知识回顾-- 反射(1) 反射(reflection)是一种允许用户获得类型信息的C#特性.术语“反射”源自于它的工作方式: Type对象映射它所代表的底层对象.对Type对象进行查询可以 ...
- Java基础知识回顾之七 ----- 总结篇
前言 在之前Java基础知识回顾中,我们回顾了基础数据类型.修饰符和String.三大特性.集合.多线程和IO.本篇文章则对之前学过的知识进行总结.除了简单的复习之外,还会增加一些相应的理解. 基础数 ...
- C#学习笔记(基础知识回顾)之值类型和引用类型
一:C#把数据类型分为值类型和引用类型 1.1:从概念上来看,其区别是值类型直接存储值,而引用类型存储对值的引用. 1.2:这两种类型在内存的不同地方,值类型存储在堆栈中,而引用类型存储在托管对上.存 ...
- C++ 基础知识回顾总结
一.前言 为啥要写这篇博客?答:之前学习的C和C++相关的知识,早就被自己忘到一边去了.但是,随着音视频的学习的不断深入,和C/C++打交道的次数越来越多,看代码是没问题的,但是真到自己操刀去写一些代 ...
- java基础知识回顾之---java String final类普通方法
辞职了,最近一段时间在找工作,把在大二的时候学习java基础知识回顾下,拿出来跟大家分享,如果有问题,欢迎大家的指正. /* * 按照面向对象的思想对字符串进行功能分类. * ...
- C#基础知识回顾-- 反射(3)
C#基础知识回顾-- 反射(3) 获取Type对象的构造函数: 前一篇因为篇幅问题因为篇幅太短被移除首页,反射这一块还有一篇“怎样在程序集中使用反射”, 其他没有什么可以写的了,前两篇主要是铺垫, ...
- C#基础知识回顾--线程传参
C#基础知识回顾--线程传参 在不传递参数情况下,一般大家都使用ThreadStart代理来连接执行函数,ThreadStart委托接收的函数不能有参数, 也不能有返回值.如果希望传递参数给执行函数, ...
- python爬虫主要就是五个模块:爬虫启动入口模块,URL管理器存放已经爬虫的URL和待爬虫URL列表,html下载器,html解析器,html输出器 同时可以掌握到urllib2的使用、bs4(BeautifulSoup)页面解析器、re正则表达式、urlparse、python基础知识回顾(set集合操作)等相关内容。
本次python爬虫百步百科,里面详细分析了爬虫的步骤,对每一步代码都有详细的注释说明,可通过本案例掌握python爬虫的特点: 1.爬虫调度入口(crawler_main.py) # coding: ...
- scrapy实战1,基础知识回顾和虚拟环境准备
视频地址 https://coding.imooc.com/learn/list/92.html 一. 基础知识回顾 1. 正则表达式 1)贪婪匹配,非贪婪匹配 .*? 非贪婪 . ...
随机推荐
- 交互式计算和开发环境:IPython
- es6 默认参数、rest参数、扩展运算符
1.默认值 现在可以在定义函数的时候指定参数的默认值了,而不用像以前那样通过逻辑或操作符来达到目的了. function sayHello(name){ //传统的指定默认参数的方式 var name ...
- less的引入和使用
文章地址:https://www.cnblogs.com/sandraryan/ 之前就了解过less,但项目一直用的是css,所以,重新做一次系统的了解,顺便写个博客Orz 简介 less和sass ...
- Android TextView点击效果
在Android开发中,我们有时候需要单独的点击某一段文本,如图所示: 如上图,我们要求点击新用户注册这个TextView,为了有更好的用户体验,我们肯定要设置该TextView的点击效果.下面介绍如 ...
- 洛谷P3313 [SDOI2014]旅行 题解 树链剖分+线段树动态开点
题目链接:https://www.luogu.org/problem/P3313 这道题目就是树链剖分+线段树动态开点. 然后做这道题目之前我们先来看一道不考虑树链剖分之后完全相同的线段树动态开点的题 ...
- SuperSocket通过本地证书仓库的证书来启用 TLS/SSL
你也可以通过本地证书仓库的证书,而不是使用一个物理文件. 你只需要在配置中设置你要使用的证书的storeName和thumbprint: <server name="EchoServe ...
- Json --- Jackson工具
一.Jackson简介 Jackson是一个简单基于Java应用库,Jackson可以轻松的将Java对象转换成json对象和xml文档,同样也可以将json.xml转换成Java对象.Jackson ...
- SpringData Jpa、Hibernate、Jpa 三者之间的关系
JPA规范与ORM框架之间的关系是怎样的呢? JPA规范本质上就是一种ORM规范,注意不是ORM框架--因为JPA并未提供ORM实现,它只是制订了一些规范,提供了一些编程的API接口,但具体实现则由服 ...
- P1004 奶牛与牧场
题目描述 有一个牧场,牧场上的牧草每天都在匀速生长,这片牧场可供 \(a\) 头牛吃 \(b\) 天,或可供 \(c\) 头牛吃 \(d\) 天,那么,这片牧场每天新生的草量最多可供几头牛吃1天? 输 ...
- HashMap深入理解
Map 的实现类有 HashMap.LinkedHashMap.TreeMap.IdentityHashMap.WeakHashMap.Hashtable.Properties 等等. 关于 Hash ...