C++ 派生类中的基指针地址是多少?
据我所知,我们可以使用基类指针来寻址并在派生类中调用虚拟函数,因为基类指针的指针范围更为有限。但我只想知道,基类指针如何知道在派生类中从何处开始 例如,对于记录A、B和C都有自己的数据成员,我们可以在两个不同的类别1中讨论这个问题。A、 B&C都有其虚拟功能;2.A、 B&C只有自己的数据成员,没有任何虚拟功能C++ 派生类中的基指针地址是多少?,c++,pointers,inheritance,memory,C++,Pointers,Inheritance,Memory,据我所知,我们可以使用基类指针来寻址并在派生类中调用虚拟函数,因为基类指针的指针范围更为有限。但我只想知道,基类指针如何知道在派生类中从何处开始 例如,对于记录A、B和C都有自己的数据成员,我们可以在两个不同的类别1中讨论这个问题。A、 B&C都有其虚拟功能;2.A、 B&C只有自己的数据成员,没有任何虚拟功能 A类{…}; B类{…}; C类:公共A、公共B{…}; C C; B*B=&c 在C中,A应该放在B的顶部,那么指针B如何知道在C中从哪里开始寻址呢?编译器知道布局,所以它将发出代码
A类{…};
B类{…};
C类:公共A、公共B{…};
C C;
B*B=&c
在C中,A应该放在B的顶部,那么指针B如何知道在C中从哪里开始寻址呢?编译器知道布局,所以它将发出代码,这将计算
C
中B
子对象的地址
让我们看一个简单的实际例子:
class A { int x; };
class B { int y; };
class C: public A, public B { };
B *get(C &c) {
return &c;
}
在get
中,编译器必须计算B
在C
中的位置。下面是编译代码()的示例:
这意味着编译器将向输入参数的地址(c
)添加4个字节,并返回该字节(它添加4,因为sizeof(A)
是4,编译器决定不添加任何额外的填充)
请注意,如果
A
为空,则B
的地址可能与C
相同。如果A
不是空的(具有非静态数据成员,或具有虚拟函数),则B
的地址可能会不同。但所有这些都是实现细节,取决于平台ABI(应用程序二进制接口)。因为编译器知道A的大小。如果输出两个指针,您将看到指针的值已更改。试试看,地址不会改变。他们应该打印同样的东西。编辑:哦,如果他们有虚拟的方法,你是说?是的,那么它们就不同了。它不是。基类定义指定了它有哪些虚拟函数。当指向的对象是派生类的实例时,实现(aka编译器)确保所有虚拟函数调用都解析为最派生类的重写。实际上,实现通常使用虚拟函数表(vtables),这些表以某种形式包含指向所有虚拟函数的指针。当构造派生类的实例时,基类的vtable中会填充派生类的条目(因为“派生”部分的构造发生在“基类”部分之后)@TEDLYNMO至少一个静态强制转换(&c)
和静态强制转换(&c)
必须与&c
不同,因为A
和B
子对象必须具有不同的地址。@如果它们具有虚拟方法,则为molbdnilo Yes。如果没有,它们都有相同的地址。最后一段是否受到某种影响?@Evg:是的,如果编译器将A
放在第一位(并且A
为空),那么EBO需要在相同的地址有B
和C
。
get(C&): # @get(C&)
lea rax, [rdi + 4]
ret