Производный полиморфный класс C ++ - содержит ли он весь экземпляр Base, включая vptr? - PullRequest
2 голосов
/ 23 сентября 2011

Скажем, у нас есть

Class A
{
   public:
   int _i;
   virtual int getI();
};
class B : public A
{  
   public:
   int _j;
   virtual int getI();
};

Итак, если предположить, что размер класса в памяти является суммой его членов (т. Е. Игнорирование заполнения или того, что может на самом деле произойти), каков размер экземпляра B? Это sizeof (A) + sizeof (int) + sizeof (vptr)? Или экземпляр B не содержит A vptr в своем личном экземпляре A, так что sizeof (b) будет sizeof (int) + sizeof (int) + sizeof (vptr)?

Ответы [ 4 ]

3 голосов
/ 23 сентября 2011

Это то, что нужно реализации, чтобы код работал.Все, что вы можете сказать, это то, что это как минимум 2 * sizeof(int), потому что объекты типа B содержат два int s (и, возможно, другие вещи).В типичной реализации A и B будут совместно использовать vptr, а общий размер будет на один указатель больше, чем на два целых числа (по модулю заполнения для выравнивания, но в большинстве реализаций я не думаю, чтобыть любым).Но это просто типичная реализация;Вы не можете рассчитывать на это.

1 голос
/ 23 сентября 2011

Любой разговор о vtable будет специфичным для определенной реализации, поскольку даже существование vtable не определено стандартом C ++ - это детали реализации.

Обычно объект будет толькоиметь один указатель на vtable, и этот vtable будет использоваться всеми объектами этого типа.Производный класс будет содержать указатели в таблице для каждой виртуальной функции базовых классов плюс каждую новую виртуальную функцию, которую он не унаследовал, но опять-таки это статическая таблица, и она является , а не частью объекта..

Чтобы ответить на вопрос, наиболее вероятным результатом является sizeof (B) == sizeof (A :: _ i) + sizeof (B :: _ j) + sizeof (vptr).

0 голосов
/ 23 сентября 2011

Почему вы хотите знать? Если вы собираетесь использовать это в своей программе, я постараюсь найти более переносимый способ, чем вычислять его, и либо добавить виртуальную функцию, которая возвращает размер, либо, возможно, использовать информацию типа времени выполнения, чтобы получить правильный тип, а затем вернуть размер.

(если вы проголосуете или добавите комментарий, я начну украшать ответ)

0 голосов
/ 23 сентября 2011

В дополнение к тому, что сказал Джеймс Канзе, возможно, стоит упомянуть, что (в типичной реализации) виртуальная таблица B будет содержать виртуальную таблицу A. в ее начале.

Например:

class A {
    virtual void x();
    virtual void y();
};

class B : A {
    virtual void y();
    virtual void z();
};

Виртуальная таблица A:

  • A: x ()
  • A: y ()

Виртуальная таблица B:

  • A: x ()
  • B : y ()
  • B: z ()

Вот почемуэкземпляр B может обойтись только одним указателем виртуальной таблицы.

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

Всегда помните, что всеэто деталь реализации, и вы никогда не должны писать код, который от нее зависит.

...