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)贪婪匹配,非贪婪匹配 .*? 非贪婪 . ...
随机推荐
- JAVA内存溢出解析(转)
JAVA内存溢出解析(转) 核心提示:原因有很多种,比如: 1.数据量过于庞大:死循环 :静态变量和静态方法过多:递归:无法确定是否被引用的对象: 2.虚拟机不回收内存(内存泄漏): 说白了就是程序运 ...
- @hdu - 6598@ Harmonious Army
目录 @description@ @solution@ @accepted code@ @details@ @description@ n 个士兵,每个士兵可以选择加入 A 组或 B 组. 有 m 个 ...
- [***]HZOJ 奇袭
C. 奇袭 题目描述 由于各种原因,桐人现在被困在Under World(以下简称UW)中,而UW马上 要迎来最终的压力测试——魔界入侵. 唯一一个神一般存在的Administrator被消灭了,靠原 ...
- chrome谷歌浏览器怎么清除指定网站cookie
https://jingyan.baidu.com/article/fa4125aced30cc28ac709230.html 在使用电脑的情况下,由于到部分网站的cookie的问题导致的部分功能失效 ...
- Android 性感美图在线浏览APP
周末无聊,遂整理了下近来常用的几个开源库,无意间又发现了一些开放接口,于是乎决定融合在一起,做个简单的"性感美图"浏览的APP,名字呢,就叫"性感沙滩",效果如 ...
- PyTorch 学习笔记(四):权值初始化的十种方法
pytorch在torch.nn.init中提供了常用的初始化方法函数,这里简单介绍,方便查询使用. 介绍分两部分: 1. Xavier,kaiming系列: 2. 其他方法分布 Xavier初始化方 ...
- oracle使用表的别名(Alias)
当在SQL语句中连接多个表时, 请使用表的别名并把别名前缀于每个Column上.这样一来,就可以减少解析的时间并减少那些由Column歧义引起的语法错误. (Column歧义指的是由于SQL中不同 ...
- PHP内置服务器
PHP在安装的时候会内置了服务器的功能,我们在使用的过程中如果只是调试,可以选择启动PHP内置的服务器,下面是windows下PHP内置服务器的启动步骤: 1.将php的D:\phpStudy\php ...
- SuperSocket通过证书文件启用 TLS/SSL
你需要通过下面的步骤修改配置文件来使用你准备好的证书文件: 在server节点设置security属性: 在server节点下增加certificate子节点: 最后配置应该像这样: <serv ...
- Python--day27--几个内置方法:__repr__()/__str__()/__del__()/__call__()/__getitem__/__setitem/delitem/__new__/__eq__/__hash__
repr方法() 双下方法__str__: 打印对象就相当于打印对象.__str__ __repr__(): __repr__是__str__的备胎,没有__str__的时候,就调用__repr__: ...