Нет Стандартно-совместимого решения
То, что вы пытаетесь сделать , невозможно при использовании поведения, гарантированного стандартом C ++ .
Если вы действительно ДОЛЖНЫ это сделатьэто как краткосрочная мера, чтобы помочь вашей миграции, не зависеть от нее в процессе производства и может адекватно проверить поведение, вы можете эксперимент , как показано ниже.
Обсуждение вашейпопытка
Я показываю, что вы используете неправильный подход : простое приведение указателя к основанию к указателю на производное не изменяет vtable объектауказатель.
Получение вероятного взлома
Обращаясь к этому, наивный подход состоит в том, чтобы реконструировать объект на месте как производный объект («размещение» new
), но это не тоже не работает - он инициализирует членов базового класса.
Что вы можете возможно сделать, это создать непроизводный объект, который не имеет членов данных, кроме те же записи таблицы виртуальной отправки (т. Е. Те же виртуальные функции, тот же доступ, частный / защищенный / общедоступный, тот же порядок).
Дополнительные предупреждения и предостережения
Это может работать (как и намой Linux box), но используйте его на свой страх и риск (я предлагаю не в производственных системах).
Дальнейшее предупреждение: это может только перехватить виртуальную диспетчеризацию , ииногда виртуальные функции могут отправляться статически, когда компилятор знает типы во время компиляции.
~/dev cat hack_vtable.cc
// change vtable of existing object to intercept virtual dispatch...
#include <iostream>
struct B
{
virtual void f() { std::cout << "B::f()\n"; }
std::string s_;
};
struct D : B
{
virtual void f() { std::cout << "D::f()\n"; }
};
struct E
{
virtual void f() { std::cout << "E::f()\n"; }
};
int main()
{
B* p = new B();
p->s_ = "hello";
new (p) D(); // WARNING: reconstructs B members
p->f();
std::cout << '\'' << p->s_ << "'\n"; // no longer "hello"
p->s_ = "world";
new (p) E();
p->f(); // correctly calls E::f()
std::cout << '\'' << p->s_ << "'\n"; // still "world"
}
~/dev try hack_vtable
make: `hack_vtable' is up to date.
D::f()
''
E::f()
'world'