в статье с этого сайта: С/C++ -> Вопрос новичка про виртуальный деструктор
упоминаются базы. К сожалению я не знаю такого термина
Просвятите плизз что это такое.
ЗЫ Плизз ткните меня в место, где можно прочесть про то, как формируется таблица виртуальной функции и где она хранится.
так если сделать:
class c
{
public:
virtual void v() {};
c();
~c();
};
c obj_c;
size_t sz = sizeof(obj_c);
c* pc = (c*)malloc(sz);
memcpy(pc, &obj_c, sz);
pc->v(); // корректен ли вызов?
Здравствуйте, Аноним, Вы писали:
А>в статье с этого сайта: С/C++ -> Вопрос новичка про виртуальный деструктор упоминаются базы. К сожалению я не знаю такого термина Просвятите плизз что это такое.
База — это базовый класс данного класса, или подобъект базового класса в составе данного объекта.
class Base { ..... };
class Base1 : public Base { ..... };
class Base2 { ..... };
class Derived : public Base1, public Base2 { ..... };
// Структура объектов класса Derived выглядит так:
// <----------------------------------------------- объект Derived ----------------------------------------------->
// <------------------ подобъект Base1 -----------------> <- подобъект Base2 -> <- данные, объявленные в Derived ->
// <- подобъект Base -> <- данные, объявленные в Base1 ->
Derived object; // object, помимо собственных членов-данных, содержит подобъект класса Base
// доступ к которому можно получить, например, так:
Base& subobject = static_cast<Base&>(object); // или просто ... = object, т.к. это преобразование неявное.
А>ЗЫ Плизз ткните меня в место, где можно прочесть про то, как формируется таблица виртуальной функции и где она хранится.
Таблица виртуальн
ых функци
й (vmt, vtable, vtbl) — это скрытый массив указателей на реализации виртуальных функций данного класса. Он формируется компилятором, хранится где-то в сегменте данных, а указатель на таблицу (vptr, vfptr) хранится в объекте.
Естественно, что если Base имеет виртуальные функции, то vptr является его потайным членом, а все наследники пользуются этим же самым членом — записывая в него адрес соответствующей vtable.
Настройка vptr происходит в конструкторе, перед самым его началом работы. Причём, поскольку конструирование объекта начинается с конструирования его базового подобъекта, vptr последовательно принимает адрес vtable самой первой базы, затем vtable промежуточной базы... и наконец vtable полного объекта.
COM-совместимые компиляторы заполняют vtable в том порядке, в каком эти функции объявлены — естественно, начиная с базового класса (а не для каждого потомка как попало).
Это позволяет от указателя на подобъект базового класса обращаться к элементам vtable по индексу, будучи уверенными, что даже если vptr указывает на vtable класса-потомка, в данном элементе находится указатель на (унаследованную или новую) реализацию нужного же метода.
Derived obj;
Base& base = obj;
obj .virtfunc(); // vptr - скрытый член базового класса, в obj он указывает на vtable класса Derived
base.virtfunc(); // В обоих случаях будет вызвана Derived::virtfunc()
Ну и кроме того, это позволяет формировать vtable COM-объектов вручную — например, если COM-сервер пишется не на С++ а на голом Си. Единый формат vtable обеспечивает совместимость между языками и компиляторами.
А>так если сделать:
А>class c
А>{
А>public:
А>virtual void v() {};
А>c();
А>~c();
А>};
А>c obj_c;
А>size_t sz = sizeof(obj_c);
А>c* pc = (c*)malloc(sz);
А>memcpy(pc, &obj_c, sz);
А>pc->v(); // корректен ли вызов?
В данном конкретном случае корректен (во всяком случае, для подавляющего большинства платформ).
Но вообще это хак, который может очень плохо закончиться.
Дело в том, что новый объект (размещённый в блоке, выделенном через malloc) не выполнил свой конструктор. А если там что-то важное?!