Почему указатель на производный и указатель на базовый не указывают на один и тот же адрес, если задействованы абстрактные классы? - PullRequest
0 голосов
/ 24 апреля 2020

Я столкнулся с проблемой, которую можно свести к следующему примеру:

#include "iostream"

struct A {
    char a;
};
struct B : A {
    virtual void f() = 0;
};
struct C : B {
    void f() override {}
};

void f(A* fpa) {
    std::cout << fpa << '\n' << reinterpret_cast<C*>(fpa) << std::endl;
}

int main() {
    C c {};
    A* pa {&c};
    std::cout << &c << '\n' << pa << '\n' << reinterpret_cast<C*>(pa) << std::endl;
    f(&c);
}

Ни pa, ни fpa не указывают на адрес c, хотя оба они инициализируются с &c. Все адреса, напечатанные после адреса &c, смещаются на +8 (протестировано с g ++ и clang ++). Удаление A :: a или B :: f () и C :: f () или инициализация pa и fpa с помощью reinterpret_cast<A*>(&c) вместо просто &c исправляет адреса.

Но почему я должен это делать? Разве любой A* не может содержать адрес для любого A, B или C в этом случае, поскольку все наследование публикуется c? Почему значение изменяется неявно? И есть ли флаги предупреждений, которые я могу передать g ++ или clang ++, которые предупреждают о таком поведении?

1 Ответ

3 голосов
/ 24 апреля 2020

или инициализация pa и fpa с помощью reinterpret_cast<A*>(&c) вместо просто &c исправляет адреса.

Это не "исправляет" адрес. Это ломает адрес. Это дает неверный указатель.

Но почему я должен это делать?

Вам не нужно это делать. Адрес смещения является правильным адресом базового подобъекта.

Почему указатель на производный и указатель на базовую точку не указываются на тот же адрес, если задействованы абстрактные классы?

Поскольку в объекте перед базовым субобъектом что-то хранится.

Разве ни один А * не может удерживать адрес любого А, В или C

Нет. Адрес действительного указателя на A всегда является адресом объекта A. Если тип dynamici c является производным, то этот объект A является базовым подобъектом. База может храниться со смещением относительно начала производного класса.

, поскольку все наследование является публичным c

Доступность Наследования в этом случае не имеет значения рассмотреть.

И есть ли флаги предупреждений, которые я могу передать g ++ или clang ++, которые предупреждают о таком поведении?

Я очень сомневаюсь, что так и будет. Я также не понимаю, почему вы хотите предупреждение в таком случае.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...