【问题标题】:Fields access - polymorphic and not polymorphic types in c++字段访问 - C++ 中的多态和非多态类型
【发布时间】:2019-02-18 17:12:03
【问题描述】:

当一个类中有虚函数时,编译器会为它创建一个虚表。 假设我们有上面的代码:

class A {
public: 
int x;
};

class B : public A {
virtual void foo(){}
};

现在 B 有一个 vtable 而 A 没有。 如果我们有一个函数返回指向 A 的指针,该指针可以是 A 或 B,并且我们访问函数返回的对象的 x 字段。 编译器如何调整访问 x,它必须在运行时完成,但是如何?

【问题讨论】:

  • 快速编译为 asm 可能会回答您的问题,但访问 x 不是运行时决定的。在您呈现的层次结构中,成员 variables 没有任何虚拟内容。它与 B(或 A)的实例有一个确定的偏移量,并且不会因为 foo 是虚拟的而改变。
  • 请注意,C++ 标准不需要使用 vtable。更多动态方案是可能的。此外,使用 vtables 的编译器,我相信所有现存的常用编译器都不需要在 B 的开头添加 vtable 指针。如何做到这一点完全取决于每个编译器。除非编译器必须符合系统要求。
  • @Cheersandhth.-Alf 但是没有其他方案能比得上 vtables 的效率,以及单继承情况下的简单性。

标签: c++ inheritance polymorphism virtual vtable


【解决方案1】:

使用你提到的函数返回的A*指针,没有调整:已经是A*,直接指向A对象,可以是A的基类子对象B 对象。

但是,在您提到的函数的返回逻辑中可以并且通常会有一个指针值调整,它会产生一个指向B 对象的A*

那是因为B 通常会在开头有一个 vtable 指针,因此 A 基类子对象不在偏移量 0 处。必要的调整使得通过有效地执行 @987654330 来搞砸是可能的@ 没有调整。对于 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 << ".\n";
    cout << "As A* it's = " << ptr() << ".\n";
    cout << b_object.x << " in B, is " << ptr()->x << " in A.\n";
}

在 Windows 10 中使用 MinGW g++ 7.3.0 的结果:

&b_object = 0x512030。 作为 A*,它 = 0x512038。 B 中的 42 是 A 中的 42。

您可以从地址中看到,B 开头的额外信息是 8 个字节,与该信息是一个 8 字节指针值一致,对于这个 64 位编译器。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-09-07
    • 1970-01-01
    • 2019-02-09
    • 1970-01-01
    • 1970-01-01
    • 2017-08-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多