Поля доступа - полиморфные и неполиморфные типы в c ++ - PullRequest
0 голосов
/ 14 сентября 2018

Когда в классе есть виртуальная функция, компилятор создает для него виртуальную таблицу. Предположим, у нас есть код выше:

class A {
public: 
int x;
};

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

теперь у B есть vtable, а у A нет. если у нас есть функция, которая возвращает указатель на A, который может быть A или B, и мы получаем доступ к полю x объекта, который вернула функция. как компилятор выполняет настройку для доступа к x, это должно быть сделано во время выполнения, но как?

Ответы [ 2 ]

0 голосов
/ 14 сентября 2018

Используя указатель A*, возвращаемый упомянутой вами функцией, никаких настроек нет: это уже A*, он указывает непосредственно на объект A, который может быть подобъектом базового класса AB объект.

Однако в логике возврата функции, о которой вы упоминаете, может и обычно будет корректировка значения указателя , которая выдает A*, указывающий на B object.

Это потому, что B обычно будет иметь указатель vtable в начале, так что подобъект базового класса A не имеет смещения 0. Необходимая регулировка позволяет испортитьэффективно делая reinterpret_cast, который не корректируется.И это может произойти с простым умом для удаления для unique_ptr (a 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";
}

Результат с MinGW g ++ 7.3.0 в Windows 10:

&b_object  = 0x512030.
As A* it's = 0x512038.
42 in B, is 42 in A.

По адресам видно, что дополнительная информация в начале B составляет 8 байт, что соответствует 8-значение байтового указателя для этого 64-битного компилятора.

0 голосов
/ 14 сентября 2018

Когда функция возвращает указатель на A, тогда вся информация стирается, если это какой-то автономный экземпляр A базового подобъекта экземпляра B или некоторый член данных класса C или элементмассива D.Во всех таких случаях указатель указывает на соответствующий объект типа A, который имеет член x.

Ничего особенного нет, когда он является базовым подобъектом экземпляра B, потому что B (и его возможный указатель на vtable) находится за пределами A.Сам A не имеет никаких виртуальных функций, поэтому он не может быть идентифицирован как базовый подобъект B.

.
...