база класса
От: Аноним  
Дата: 04.10.05 20:58
Оценка:
в статье с этого сайта: С/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();             // корректен ли вызов?
Re: база класса
От: Кодт Россия  
Дата: 04.10.05 21:57
Оценка: 16 (3)
Здравствуйте, Аноним, Вы писали:

А>в статье с этого сайта: С/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) не выполнил свой конструктор. А если там что-то важное?!
Перекуём баги на фичи!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.