- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我正在阅读 Bjarne 的论文:Multiple Inheritance for C++ .
在第 3 节第 370 页中,Bjarne 说“编译器将成员函数的调用转换为带有“额外”参数的“普通”函数调用;该“额外”参数是指向成员函数所针对的对象的指针叫做。”
我对这个额外的论点感到困惑。请看以下两个例子:
示例 1 :(第372页)
class A {
int a;
virtual void f(int);
virtual void g(int);
virtual void h(int);
};
class B : A {int b; void g(int); };
class C : B {int c; void h(int); };
----------- vtbl:
+0: vptr --------------> -----------
+4: a +0: A::f
+8: b +4: B::g
+12: c +8: C::h
----------- -----------
C* pc;
pc->g(2)
(*(pc->vptr[1]))(pc, 2)
this
点是 C*。
class A {...};
class B {...};
class C: A, B {...};
pc--> -----------
A part
B:bf's this--> -----------
B part
-----------
C part
-----------
C* pc;
pc->bf(2); //assume that bf is a member of B and that C has no member named bf.
bf__F1B((B*)((char*)pc+delta(B)), 2);
this
?
this
,我认为我们仍然可以正确访问 B 的成员。例如,要在 B::bf() 中获取类 B 的成员,我们只需要执行以下操作:*(this+offset)。这个偏移量可以被编译器知道。这是正确的吗?
A
,
B
,
C
具有与示例 1 完全相同的成员。
A
:
int a
和
f
;
B
:
int b
和
bf
(或称之为
g
);
C
:
int c
和
h
.为什么不直接使用内存布局,例如:
-----------
+0: a
+4: b
+8: c
-----------
class A {...};
class B : A {...};
class C: B {...};
C* pc = new C();
B* pb = NULL;
pb = (B*)pc;
A* pa = NULL;
pa = (A*)pc;
cout << pc << pb << pa
pa
,
pb
和
pc
有相同的地址。
class A {...};
class B {...};
class C: A, B {...};
C* pc = new C();
B* pb = NULL;
pb = (B*)pc;
A* pa = NULL;
pa = (A*)pc;
pc
和
pa
具有相同的地址,而
pb
与
pa
有一些偏移和
pc
.
class A {virtual void f();};
class B {virtual void f(); virtual void g();};
class C: A, B {void f();};
A* pa = new C;
B* pb = new C;
C* pc = new C;
pa->f();
pb->f();
pc->f();
pc->g()
pc->g()
这与示例 2 中的讨论有关。 compile 是否执行以下转换:
pc->g() ==> g__F1B((*B)((char*)pc+delta(B)))
C::f
,
this
指针必须指向
C
的开头对象(而不是
B
部分)。但是,在编译时通常不知道
B
由
pb
指出是
C
的一部分所以编译器不能减去常量
delta(B)
.
B
pb
指向的对象是
C
的一部分在编译时?据我了解,
B* pb = new C
,
pb
指向一个创建的
C
对象和
C
继承自
B
, 所以一个
B
指针 pb 指向
C
的一部分.
B
指向
pb
的指针是
C
的一部分在编译时。所以我们必须存储实际与 vtbl 一起存储的运行时的 delta(B)。所以 vtbl 条目现在看起来像:
struct vtbl_entry {
void (*fct)();
int delta;
}
pb->f() // call of C::f:
register vtbl_entry* vt = &pb->vtbl[index(f)];
(*vt->fct)((B*)((char*)pb+vt->delta)) //vt->delta is a negative number I guess
(*vt->fct)((B*)((char*)pb+vt->delta))
中不是 (C*) ???根据我的理解和 Bjarne 在 5.1 节第 377 页第一句的介绍,我们应该将 C* 作为
this
传递。这里!!!!!!
最佳答案
Bjarne wrote: "Naturally, B::bf() expects a B* (to become its this pointer)." The compiler transforms the call into:
bf__F1B((B*)((char*)pc+delta(B)), 2);
Why here we need a B* pointer to be the this?
B
隔离:编译器需要能够编译代码ala
B::bf(B* this)
.它不知道可以从
B
进一步派生哪些类。 (而且派生代码的引入可能要在
B::bf
编译后很久才会发生)。
B::bf
的代码不会神奇地知道如何将指针从其他类型(例如
C*
)转换为
B*
它可以用来访问数据成员和运行时类型信息(RTTI/虚拟调度表,类型信息)。
B*
到
B
涉及任何实际运行时类型的子对象(例如
C
)。在这种情况下,
C*
保存全局的起始地址
C
可能与
A
的地址匹配的对象子对象,以及
B
子对象是一些固定但非 0 的内存偏移量:它是必须添加到
C*
的偏移量(以字节为单位)以获得有效的
B*
拨打电话
B::bf
- 当指针从
C*
转换时,调整就完成了输入到
B*
类型。
(1) When it's a linear chain derivation (example 1), why the C object can be expected to be at the same address as the B and in turn A sub-objects? There is no problem to use a
C*
pointer to access class B's members inside the functionB::g
in example 1? For example, we want to access the member b, what will happen in runtime?*(pc+8)
?
[[[A fields...]B-specific-fields....]C-specific-fields...]
^
|--- A, B & C all start at the same address
*(pc+8)
- 没错(考虑到我们向地址添加了 8 个字节,而不是通常的 C++ 行为,即添加指针大小的倍数)。
(2) Why can we use the same memory layout (linear chain derivation) for the multiple-inheritance? Assuming in example 2, class A, B, C have exactly the same members as the example 1. A: int a and f; B: int b and bf (or call it g); C: int c and h. Why not just use the memory layout like:
-----------
+0: a
+4: b
+8: c
-----------
A
成为自己的一部分。现在是这样的:
[[A fields...][B fields....]C-specific-fields...]
^ ^
\ A&C start \ B starts
B::bf
它想知道哪里
B
对象开始 -
this
您提供的指针应该在上面列表中的“+4”处;如果您拨打
B::bf
使用
C*
那么编译器生成的调用代码将需要添加 4 以形成隐式
this
参数
B::bf()
.
B::bf()
不能简单地告诉在哪里
A
或
C
从 +0 开始:
B::bf()
对这两个类一无所知,也不知道如何到达
b
或者它的 RTTI,如果你给它一个指向它自己的 +4 地址以外的任何东西的指针。
关于c++ - 编译器关于此指针、虚函数和多重继承的详细信息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30747633/
03-25 05:52:15.329 8029-8042/com.mgh.radio W/MediaPlayerNative: info/warning (703, 0) 03-25 05:52:15
我一直在 Internet 上到处寻找关于 FrameworkElementFactory 类的适当文档,但我似乎找不到有关它的适当教程或有用信息。 请问对这个问题了解更多的人可以给我更多的信息吗?这
我需要知道一个线程在进入等待状态之前如何将其ID发送到另一个线程。我想传递一个带有其ID的变量,但我不知道该怎么做。 最佳答案 如果只有一个线程及其父线程,则可以使用全局变量,因为它们在所有线程之间共
我正在尝试制作一个程序,该程序可以读取命令行上的所有单词,然后将其打印在新行上,而我想要做的是这样的: Some text: hello 但是相反,我得到了这样的东西: Some text: Hell
我有一个连接到rabbitmq服务器的python程序。当该程序启动时,它连接良好。但是当rabbitmq服务器重新启动时,我的程序无法重新连接到它,并留下错误“Socket已关闭”(由kombu产生
我正在设置CI / CD管道。部署步骤运行以下命令: kubectl apply -f manifest.yml --namespace kubectl rollout status Deploym
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 4 年前。 Improve this ques
这是我在文件上运行 svn info 时输出的一部分: Last Changed Author: [user] Last Changed Rev: 269612 Last Changed Date:
所以我正在构建这个音乐应用程序,到目前为止它只扫描 SD 卡内的特定文件夹。这将返回路径,然后播放它们。 几个小时前我得知android系统中有一个媒体文件数据库所以 我想知道这个媒体文件数据库是否存
我正在绘制树形图,并且想知道如何绘制树类的相对百分比,即 A组=100 B地=30 C地=50 D 地 =20 然后,在图中,应该添加: A 组“50%” B 组“15%” 等在其“Group X”标
我正在构建一个社交网站,我想知道如何在用户首次登录时显示交互式教程和信息。比如只有在第一次登录时,用户才会被要求在他们的个人资料中填写更多信息。我怎样才能通过 php 和 mysql 实现这一点?例子
我是 java servlet 的新手。我研究了一些关于 servlet 的代码,但我真的很想知道更多基本的东西以及它是如何工作的。我只是想知道什么类型的 Material /内容可以从 java s
我想知道是否有办法为 user_id、sender_user_id 和 recipient_user_id 提供 name 信息来自 this fiddle 中的模式. 我现在唯一能想到的办法就是做这
这是我存储2个大学生信息的源代码。我想从输入中获取每个人的姓名、姓氏、ID 和 5 分,然后在输出中显示它们。我在输出中显示分数时遇到问题。 请帮忙 #include using namespace
假设我有一张带有条形图的图像,如下所示: 我想提取条形图和标签的值,除了训练 ML 模型之外,还有其他方法吗? 我有一堆图像,我为其生成了图表和一些描述。我目前正尝试仅从我能够做到的描述中提取信息,但
有没有办法从 GKTurnBasedParticipant 对象中检索玩家的名字?似乎除了根据类引用的难看的 playerID 之外,没有办法显示有关游戏玩家的相关信息。还是我遗漏了什么? 谢谢...
我有一个随机抛出“KeyNotFoundException”的 C# Silverlight 应用程序。我不知道找不到什么 key 。这让我想到了两个问题: KeyNotFoundException
本文实例为大家分享了ios获取本地音频文件的具体代码,供大家参考,具体内容如下 获取本地音频文件地址: ?
下面为大家介绍利用SQL查询语句获取Mysql数据库中表的表名,表描述、字段ID、字段名、数据类型、长度、精度、是否可以为null、默认值、是否自增、是否是主键、列描述 1、查询表信息(表名/表
问题 有没有办法获取代码中使用属性的位置,或声明成员变量的位置? 我不是在寻找解决此问题的方法,只是寻求一个简单的答案,无论这在技术上是否可行。 一些背景信息 我已经定义了一个属性,该属性使用提供给属
我是一名优秀的程序员,十分优秀!