C# 类继承中的私有字段都去了哪里?
最近在看 C++ 类继承中的字段内存布局,我就很好奇 C# 中的继承链那些 private 字段都哪里去了? 在内存中是如何布局的,毕竟在子类中是无法访问的。
一:举例说明
为了方便讲述,先上一个例子:
internal class Program
{
static void Main(string[] args)
{
Chinese chinese = new Chinese();
int num = chinese.b; //b 字段无法访问,编译报错
Console.WriteLine(num);
}
}
public class Person
{
public int a = 10;
private int b = 11;
}
public class Chinese : Person
{
public int c = 12;
}
根据 C# 的类继承原则,上面的 chinese.b
写法肯定是无法被编译的,因为它属于父类的 私有字段,既然无法被访问,那这个 private b
到底去了哪里呢? 要想找到答案,只能先从 chinese
实例处的汇编代码看起,看看有没有什么意外收获。
二:查看 chinese 处汇编代码
在 new chinese()
处下一个断点,查看 Visual Stduio 2022
的反汇编窗口。
接下来我稍微解读下:
1. 根据 MT 类型 实例化 chinese
07FD6176 mov ecx,87205C4h
07FD617B call CORINFO_HELP_NEWSFAST (06E30C0h)
这里的 87205C4h
就是 Chinese 类型的 MT,然后通过 CLR 下的 CORINFO_HELP_NEWSFAST
处的方法进行实例化。
2. 使用 chinese 的构造函数进行类初始化
07FD6180 mov dword ptr [ebp-40h],eax
07FD6183 mov ecx,dword ptr [ebp-40h]
07FD6186 call CLRStub[MethodDescPrestub]@7e34871e07fd5d20 (07FD5D20h)
07FD618B mov eax,dword ptr [ebp-40h]
这里的 eax 是 CORINFO_HELP_NEWSFAST
初始化方法的返回值,可以在 ecx,dword ptr [ebp-40h]
处下一个断点,观察它的内存布局。
从布局图看,此时的 chinese 只是一个清零的默认状态,此时的 a,b,c
三个字段还没有被赋值,那什么时候被赋值呢? 这就是构造函数要做的事情了,也就是上面的 CLRStub[MethodDescPrestub]@7e34871e07fd5d20 (07FD5D20h)
指令,接下来在 07FD618B
处下一个断点,再次观察 0x02C9F528
处的内存地址,也就是 ebp-40
的位置,接下来我们继续执行,截图如下:
从图中可以看到,当构造函数执行完之后,有三处内存地址(变红)被赋值了,依次是 a,b,c
,这时候是不是让人眼前一亮。
3. 洞察真相
原来那个 b=11
并没有丢,而是被 chinese
类给完全继承下来的,而且布局规则是 父类
字段在前, 子类
字段在后的一种方式,有点意思,接下来的问题是如何把它提取出来?
三:如何提取 b 字段
如果是 C 语言,我们用 *(pointer+2)
就可以轻松提取,那用托管的 C# 如何去实现呢? 可以用复杂的 Marshal
包装类,应该也可以变相的使用 Span
去搞定,这里我就不麻烦了,直接用非安全代码下的 指针
去摆平,在 a
字段偏移 +4 的位置上提取, 参考代码如下:
static void Main(string[] args)
{
unsafe
{
Chinese chinese = new Chinese();
fixed (int* ch = &chinese.a)
{
int b = *(ch + 1);
Console.WriteLine($"b={b}");
}
}
}
}
哈哈,是不是挺有意思。
C# 类继承中的私有字段都去了哪里?的更多相关文章
- C++ 类的继承四(类继承中的重名成员)
//类继承中的重名成员 #include<iostream> using namespace std; /* 自己猜想: 对于子类中的与父类重名的成员,c++编译器会单独为子类的这个成员变 ...
- 『无为则无心』Python面向对象 — 55、多层继承和继承中的私有成员
目录 1.Python支持多层继承 (1)多层继承实现 (2)多层继承和多重继承区别 2.继承中的私有成员 (1)继承中父类私有属性和私有方法 (2)获取和修改私有属性值 1.Python支持多层继承 ...
- C++类继承中的构造函数和析构函数 调用顺序
思想: 在C++的类继承中,构造函数不能被继承(C11中可以被继承,但仅仅是写起来方便,不是真正的继承) 建立对象时,首先调用基类的构造函数,然后在调用下一个派生类的构造函数,依次类推: 析构对象时, ...
- (C++)C++类继承中的构造函数和析构函数
思想: 在C++的类继承中, 建立对象时,首先调用基类的构造函数,然后在调用下一个派生类的构造函数,依次类推: 析构对象时,其顺序正好与构造相反: 例子: #include <iostream& ...
- C++ 类的继承五(类继承中的static关键字)
//类继承中的static关键字 #include<iostream> using namespace std; /* 派生类中的静态成员 基类定义的静态成员,将被所有派生类共享 根据静态 ...
- MySQL 中删除的数据都去哪儿了?
不知道大家有没有想过下面这件事? 我们平时调用 DELETE 在 MySQL 中删除的数据都去哪儿了? 这还用问吗?当然是被删除了啊 那么这里又有个新的问题了,如果在 InnoDB 下,多事务并发的情 ...
- C# 类型运算符重载在类继承中的调用测试
这是一篇晦涩难懂的片面的研究 一,简单的继承层次 class CA { } class CB : CA{ } class CC : CB{ } } void Test(CA oa){//CATest ...
- C#类继承中构造函数的执行序列
不知道大家在使用继承的过程中有木有遇到过调用构造函数时没有按照我们预期的那样执行呢?一般情况下,出现这样的问题往往是因为类继承结构中的某个基类没有被正确实例化,或者没有正确给基类构造函数提供信息,如果 ...
- C++基础——类继承中方法重载
一.前言 在上一篇C++基础博文中讨论了C++最基本的代码重用特性——类继承,派生类可以在继承基类元素的同时,添加新的成员和方法.但是没有考虑一种情况:派生类继承下来的方法的实现细节并不一定适合派生类 ...
随机推荐
- nodejs教程---基于expressJs框架,实现文件上传(upload)?
文件上传功能在nodejs初期是一件很难实现的功能,之后出现了formidable勉强能解决这个问题,但是express框架出现之后基于这个框架开发的中间件有更好的方法来处理文件上传,这个中间件就是m ...
- vim 下几种比较省劲的方式(vi结合着用)
Vim的几种模式 正常模式:可以使用快捷键命令,或按:输入命令行. 插入模式:可以输入文本,在正常模式下,按i.a.o等都可以进入插入模式. 可视模式:正常模式下按v可以进入可视模式, 在可视模式下, ...
- 【LeetCode】358.K 距离间隔重排字符串
358.K 距离间隔重排字符串 知识点:哈希表:贪心:堆:队列 题目描述 给你一个非空的字符串 s 和一个整数 k,你要将这个字符串中的字母进行重新排列,使得重排后的字符串中相同字母的位置间隔距离至少 ...
- 帝国CMS随机调用栏目
[e:loop={'select * from [!db.pre!]enewsclass where bclassid in(1) order by rand() desc limit 10',10, ...
- 重定向管道流读取TXT文本第一次读取为""空字符串、type xxx.txt | go run . 报错、BOM头、[239,186,191] 字节数组
重定向管道流读取TXT文本第一次读取为""空字符串.type xxx.txt | go run . 报错.BOM头.[239 186 191] 字节数组
- 【原创】记一次DouPHP站点的RCE实战之旅
声明 本次实践是在合法授权情况下进行,数据已经全部脱敏,主要是提供思路交流学习,请勿用于任何非法活动,否则后果自负. 实战记录 信息收集 1,踩点站点 通过fofa 查到目标DouPHP框架该站点(也 ...
- partTwo自动出题程序第一阶段
课堂测试1:像二柱子那样,花二十分钟写一个能自动生成30道小学四则运算题目的 "软件" 代码实现 import java.util.Random;//import java.uti ...
- 计算属性、侦听属性、局部与全局组件使用、组件通信(父子互传)、ref属性、动态组件和keep-alive、插槽
今日内容概要 计算属性 侦听属性 局部组件和全局组件 组件通信之父传子 组件通信之子传父 ref属性(组件间通信) 动态组件和keep-alive 插槽 内容详细 1.计算属性 # 插值的普通函数,只 ...
- python基础练习题(题目 求输入数字的平方,如果平方运算后小于 50 则退出)
day32 --------------------------------------------------------------- 实例046:打破循环 题目 求输入数字的平方,如果平方运算后 ...
- Aop踩坑!记一次模板类调用注入属性为空的问题
问题起因 在做一个需求的时候,发现原来的代码逻辑都是基于模板+泛型的设计模式,模板用于规整逻辑处理流程,泛型用来转换参数和选取实现类.听上去是不是很nice! 类目录结构 AbstractTestAo ...