Количество созданных vptr, если производный класс также имеет виртуальную функцию, которой нет в базовом классе

#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. Как очищается карта?