- 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/
#include using namespace std; class C{ private: int value; public: C(){ value = 0;
这个问题已经有答案了: What is the difference between char a[] = ?string?; and char *p = ?string?;? (8 个回答) 已关闭
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 7 年前。 此帖子已于 8 个月
除了调试之外,是否有任何针对 c、c++ 或 c# 的测试工具,其工作原理类似于将独立函数复制粘贴到某个文本框,然后在其他文本框中输入参数? 最佳答案 也许您会考虑单元测试。我推荐你谷歌测试和谷歌模拟
我想在第二台显示器中移动一个窗口 (HWND)。问题是我尝试了很多方法,例如将分辨率加倍或输入负值,但它永远无法将窗口放在我的第二台显示器上。 关于如何在 C/C++/c# 中执行此操作的任何线索 最
我正在寻找 C/C++/C## 中不同类型 DES 的现有实现。我的运行平台是Windows XP/Vista/7。 我正在尝试编写一个 C# 程序,它将使用 DES 算法进行加密和解密。我需要一些实
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
有没有办法强制将另一个 窗口置于顶部? 不是应用程序的窗口,而是另一个已经在系统上运行的窗口。 (Windows, C/C++/C#) 最佳答案 SetWindowPos(that_window_ha
假设您可以在 C/C++ 或 Csharp 之间做出选择,并且您打算在 Windows 和 Linux 服务器上运行同一服务器的多个实例,那么构建套接字服务器应用程序的最明智选择是什么? 最佳答案 如
你们能告诉我它们之间的区别吗? 顺便问一下,有什么叫C++库或C库的吗? 最佳答案 C++ 标准库 和 C 标准库 是 C++ 和 C 标准定义的库,提供给 C++ 和 C 程序使用。那是那些词的共同
下面的测试代码,我将输出信息放在注释中。我使用的是 gcc 4.8.5 和 Centos 7.2。 #include #include class C { public:
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我的客户将使用名为 annoucement 的结构/类与客户通信。我想我会用 C++ 编写服务器。会有很多不同的类继承annoucement。我的问题是通过网络将这些类发送给客户端 我想也许我应该使用
我在 C# 中有以下函数: public Matrix ConcatDescriptors(IList> descriptors) { int cols = descriptors[0].Co
我有一个项目要编写一个函数来对某些数据执行某些操作。我可以用 C/C++ 编写代码,但我不想与雇主共享该函数的代码。相反,我只想让他有权在他自己的代码中调用该函数。是否可以?我想到了这两种方法 - 在
我使用的是编写糟糕的第 3 方 (C/C++) Api。我从托管代码(C++/CLI)中使用它。有时会出现“访问冲突错误”。这使整个应用程序崩溃。我知道我无法处理这些错误[如果指针访问非法内存位置等,
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。 关闭 7 年前。
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是偏离主题的,因为
我有一些 C 代码,将使用 P/Invoke 从 C# 调用。我正在尝试为这个 C 函数定义一个 C# 等效项。 SomeData* DoSomething(); struct SomeData {
这个问题已经有答案了: Why are these constructs using pre and post-increment undefined behavior? (14 个回答) 已关闭 6
我是一名优秀的程序员,十分优秀!