Более 1 адрес для объекта производного класса?

В пункте 27 "Эффективный С++" (3-е издание, стр. 118) Скотт Мейерс сказал:

class Base { ... };
class Derived: public Base { ... };
Derived d;
Base *pb = &d;

Здесь мы просто создаем указатель базового класса на объект производного класса, но иногда два указателя не будут одинаковыми. Когда этот случай, смещение применяется во время выполнения к указателю Derived*, чтобы получить правильное значение указателя Base*.

Этот последний пример демонстрирует, что один объект (например, объект типа Derived) может иметь более одного адреса (например, его адрес при указании указателем Base* и его адресом при указании Derived*).

Вот немного сложно понять. Я знаю, что указатель на базовый класс может указывать на объект производного класса во время выполнения, это называется полиморфизмом или динамической привязкой. Но действительно ли у объекта производного класса в памяти больше 1 адреса?

Угадайте, у меня есть недоразумение. Может кто-нибудь дать некоторые разъяснения? Может быть, это имеет какое-то отношение к тому, как полиморфизм реализуется в компиляторе С++?

Ответ 1

Просто попробуйте:

class B1
{
    int i;
};

class B2
{
    int i;
};

class D : public B1, public B2
{
    int i;
};

int
main()
{
    D aD;
    std::cout << &aD << std::endl;
    std::cout << static_cast<B1*>( &aD ) << std::endl;
    std::cout << static_cast<B2*>( &aD ) << std::endl;
    return 0;
}

Невозможно, чтобы под-объект B1 имел одинаковый адрес как под-объект B2.

Ответ 2

Объект имеет ровно один адрес; что он находится в памяти. Когда вы создаете указатель на подобъект base, вы получаете адрес этого подобъекта, и это не должно быть таким же, как адрес объекта, который его содержит. Простой пример:

struct S {
    int i;
    int j;
};

S s;

Адрес s будет отличаться от адреса s.j.

Аналогично, адрес базового подобъекта не должен быть таким же, как адрес производного объекта. С единственным наследованием, как правило, является, но когда множественное наследование входит в игру и игнорирует пустые базовые классы, не более одного из базовых подобъектов может иметь тот же адрес, что и производный объект. Поэтому, когда вы конвертируете указатель на производный объект в указатель на одну из его баз, вы не обязательно получаете то же значение, что и адрес производного объекта.