#c #vtable #vptr #run-time-polymorphism
#c #vtable #vptr #полиморфизм во время выполнения
Вопрос:
class Base
{
public:
virtual void func1()
{
std::cout<<"Base func1"<<std::endl;
}
//virtual destructor
};
class Derived : public Base
{
public:
virtual void func1()
{
std::cout<<"Derived Base func1"<<std::endl;
}
virtual void func2()
{
std::cout<<"Derived func2"<<std::endl;
}
};
int main()
{
Derived *d = new Derived;
delete d;
}
Я хочу знать, будут ли созданы два «vptr» для разрешения виртуальных функций, один в Base
классе, который будет унаследован в Derived
class object for func1
, а другой в Derived
object for func2
.
Комментарии:
1. Вы проверили размеры обоих классов? wandbox.org/permlink/6znTdbKbkv5Yn6IB . Это не даст общего ответа, но может помочь. В связанной реализации существует только один vptr в
Derived
.2. Я проверил размер объекта базового класса и объекта производного класса, в моей системе он выглядит одинаково «8 байт». Но, по моему мнению, 2 vptr должны быть созданы в объекте производного класса и один в объекте базового класса.
3. Почему вы так думаете? Если GCC создает только один vptr в
Derived
, и мы предполагаем, что он совместим с Stdndard, то Стандарт не может требовать 2 vptr.4. Кстати, термины «vptr», «vtable» и «виртуальная таблица» вообще не упоминаются в Стандарте. Механизм виртуальной таблицы, по-видимому, является проблемой реализации.
5. @Naresh » должно быть создано » почему?
Ответ №1:
В моем GCC:
std::cout << sizeof(void*) << ' ' << sizeof(Derived) << 'n';
// Prints 8 8
Таким образом, одного указателя vtable достаточно. Я бы ожидал, что большинство других компиляторов будут вести себя таким же образом.
производный класс также имеет виртуальную функцию, которой нет в базовом классе
Виртуальные функции, добавленные в Derived
, вероятно, просто помещаются в конец Derived
vtable, после функций, унаследованных от Base
.
Ответ №2:
проблемы с vtable / vptr связаны с особенностями реализации платформы, обычно не охватываемыми std. Я могу представить реализации без vptr в объекте вообще. Но на большинстве платформ, которые я знаю, ровно одна запись vptr служит всем целям для одиночного наследования и виртуального наследования. Однако нет гарантии, что это поведение будет переносимым.
Комментарии:
1. » Я могу представить , как будет работать такая реализация? Приведет ли это к утечке памяти в целом?
2. @curiousguy Почему она должна протекать? Одной из возможных реализаций является статический ассоциативный массив, который хранит запись пар <объект, тип> (статическая карта<void*,type_info*> rtti;).
3. Это приведет к утечке, если объекты не будут уничтожены должным образом.
4. @curiousguy это не имеет отношения к vt. Механизм mgmt памяти отвечает за надлежащее уничтожение и освобождение; является ли тип полиморфным или нет, не имеет значения.
5. Как очищается карта?