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的更多相关文章

  1. Java基础知识回顾(一):字符串小结

    Java的基础知识回顾之字符串 一.引言 很多人喜欢在前面加入赘述,事实上去技术网站找相关的内容的一般都应当已经对相应知识有一定了解,因此我不再过多赘述字符串到底是什么东西,在官网中已经写得很明确了, ...

  2. C#基础知识回顾-- 反射(1)

    C#基础知识回顾-- 反射(1)   反射(reflection)是一种允许用户获得类型信息的C#特性.术语“反射”源自于它的工作方式: Type对象映射它所代表的底层对象.对Type对象进行查询可以 ...

  3. Java基础知识回顾之七 ----- 总结篇

    前言 在之前Java基础知识回顾中,我们回顾了基础数据类型.修饰符和String.三大特性.集合.多线程和IO.本篇文章则对之前学过的知识进行总结.除了简单的复习之外,还会增加一些相应的理解. 基础数 ...

  4. C#学习笔记(基础知识回顾)之值类型和引用类型

    一:C#把数据类型分为值类型和引用类型 1.1:从概念上来看,其区别是值类型直接存储值,而引用类型存储对值的引用. 1.2:这两种类型在内存的不同地方,值类型存储在堆栈中,而引用类型存储在托管对上.存 ...

  5. C++ 基础知识回顾总结

    一.前言 为啥要写这篇博客?答:之前学习的C和C++相关的知识,早就被自己忘到一边去了.但是,随着音视频的学习的不断深入,和C/C++打交道的次数越来越多,看代码是没问题的,但是真到自己操刀去写一些代 ...

  6. java基础知识回顾之---java String final类普通方法

    辞职了,最近一段时间在找工作,把在大二的时候学习java基础知识回顾下,拿出来跟大家分享,如果有问题,欢迎大家的指正. /*     * 按照面向对象的思想对字符串进行功能分类.     *      ...

  7. C#基础知识回顾-- 反射(3)

    C#基础知识回顾-- 反射(3)   获取Type对象的构造函数: 前一篇因为篇幅问题因为篇幅太短被移除首页,反射这一块还有一篇“怎样在程序集中使用反射”, 其他没有什么可以写的了,前两篇主要是铺垫, ...

  8. C#基础知识回顾--线程传参

    C#基础知识回顾--线程传参 在不传递参数情况下,一般大家都使用ThreadStart代理来连接执行函数,ThreadStart委托接收的函数不能有参数, 也不能有返回值.如果希望传递参数给执行函数, ...

  9. python爬虫主要就是五个模块:爬虫启动入口模块,URL管理器存放已经爬虫的URL和待爬虫URL列表,html下载器,html解析器,html输出器 同时可以掌握到urllib2的使用、bs4(BeautifulSoup)页面解析器、re正则表达式、urlparse、python基础知识回顾(set集合操作)等相关内容。

    本次python爬虫百步百科,里面详细分析了爬虫的步骤,对每一步代码都有详细的注释说明,可通过本案例掌握python爬虫的特点: 1.爬虫调度入口(crawler_main.py) # coding: ...

  10. scrapy实战1,基础知识回顾和虚拟环境准备

        视频地址 https://coding.imooc.com/learn/list/92.html   一. 基础知识回顾     1. 正则表达式 1)贪婪匹配,非贪婪匹配 .*? 非贪婪 . ...

随机推荐

  1. 当flex遇到white-space: nowrap; 排版就飞了的神奇问题 吐血

    在做一个移动端排班的时候需要某一行的字超出的部分用省略号代替  然后写着发现后面排版乱了 HTML结构如下  我想让第二个span的内容加省略号 css正确的代码如下 .list { width: 1 ...

  2. 在 Windows Azure 中运行SuperSocket

    关键字: Windows Azure, WorkRole, InputEndPoint, 云计算, 微软云 什么是 Windows Azure? Windows Azure 是微软的云计算平台!微软的 ...

  3. [C#] 调试silverlight的时候,总是报“向占位程序传送了空的索引指针”

    这是由于visual studio在调试silverlight的时候,必须和ie一起工作. 按照以下步骤可以把ie设为visual studio的默认浏览器(不用修改操作系统的默认浏览器): 1) 在 ...

  4. UA

    我们可以通过userAgent来判断,比如检测某些关键字,例如:AppleWebKit*****Mobile或AppleWebKit,需要注意的是有些浏览器的userAgent中并不包含AppleWe ...

  5. laravel构造函数和中间件执行顺序问题

    今天想重构下代码结构: BaseController.php 放置公共的中间件 class BaseController { public function __construct(){ $this- ...

  6. 2019-9-2-Visual-Studio-自定义项目模板

    title author date CreateTime categories Visual Studio 自定义项目模板 lindexi 2019-09-02 12:57:38 +0800 2018 ...

  7. linux scull 代码read 方法

    read 的返回值由调用的应用程序解释: 如果这个值等于传递给 read 系统调用的 count 参数, 请求的字节数已经被传送. 这是最好的情况. 如果是正数, 但是小于 count, 只有部分数据 ...

  8. P1084 骑士的工作

    题目描述 你作为一个村的村长,保卫村庄是理所当然的了.今天,村庄里来了一只恶龙,他有n个头,恶龙到处杀人放火.你着急了.不过天无绝人之路,现在来了一个骑士团.里面有m位成员,每个人都可以砍掉一个大小不 ...

  9. element-ui后台管理系统表单resetFields功能实现

    项目中有‘新增’和‘编辑’弹出dialog功能,并且为同一个dialog. html代码: 新增时,这样的样式 编辑时,这样的样式 所以在编辑完关闭dialog后,需要清空表单,一开始简单的使用了el ...

  10. P1047 汉诺塔

    题目描述 汉诺塔是根据一个印度传说形成的数学问题:有三根杆子A, B, C, A杆上有n个穿孔圆盘, 盘的尺寸由下到上依次变小. 要求按照下列规则将所有圆盘移至C杆: 每次只能移动一个圆盘 大盘不能叠 ...