字段访问 - c ++中的多态而非多态类型
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了字段访问 - c ++中的多态而非多态类型相关的知识,希望对你有一定的参考价值。
当一个类中包含虚函数时,编译器会为其创建一个虚拟表。假设我们有上面的代码:
class A {
public:
int x;
};
class B : public A {
virtual void foo(){}
};
现在B有一个vtable,而A没有。如果我们有一个函数返回一个指向A的指针,它可以是A或B,我们访问该函数返回的对象的x字段。编译器如何进行调整以访问x,它必须在运行时完成,但如何?
使用你提到的函数返回的A*
指针,没有调整:它已经是A*
,它直接指向一个A
对象,它可以是A
对象的B
基类子对象。
但是,在你提到的函数的返回逻辑中可以并且通常会有一个指针值调整,它会产生一个指向A*
对象的B
。
这是因为B
通常在开始时会有一个vtable指针,因此A
基类子对象不在偏移0处。必要的调整可以通过有效地执行不调整的reinterpret_cast
来搞砸。这可能发生在unique_ptr
的一个简单的删除器(shared_ptr
更聪明,但需要付出一些代价)。
例:
struct A
{
int x;
};
struct B: A
{
virtual void foo(){}
B( const int value ): A{ value } {}
};
B b_object( 42 );
auto ptr()
-> A*
{
return &b_object;
}
#include <iostream>
auto main()
-> int
{
using namespace std;
cout << "&b_object = " << &b_object << ".
";
cout << "As A* it's = " << ptr() << ".
";
cout << b_object.x << " in B, is " << ptr()->x << " in A.
";
}
在Windows 10中使用MinGW g ++ 7.3.0的结果:
&b_object = 0x512030. As A* it's = 0x512038. 42 in B, is 42 in A.
您可以从地址中看到,对于这个64位编译器,B
开头的额外信息是8个字节,与该信息是8字节指针值一致。
当函数返回指向A
的指针时,如果它是A
实例的基础子对象的B
或类C
的某个数据成员或数组D
的元素的某个独立实例,则擦除所有信息。在所有这些情况下,指针指向具有成员A
的x
类型的正确对象。
当它是B
实例的基础子对象时没有什么特别的,因为B
(及其可能的vtable指针)在A
之外。 A
本身没有任何虚函数,所以它不能被运行时识别为B
的基础子对象。
以上是关于字段访问 - c ++中的多态而非多态类型的主要内容,如果未能解决你的问题,请参考以下文章