Как определить размер класса с виртуальными функциями? - PullRequest
6 голосов
/ 22 января 2011

это вопрос домашнего задания.Для следующего кода:

#include <iostream>
using namespace std;

class A
{
public:
    virtual void f(){}
};

class B
{
public:
    virtual void f2(){}
};

class C: public A, public B
{
public: 
    virtual void f3(){}
};

class D: public C
{
public:
    virtual void f4(){}
};

int main()
{
    cout<<sizeof(D)<<endl;
}

Вывод: 8

Может кто-нибудь объяснить, как это 8 байтов?Если реализация vtable зависит от компилятора, что я должен ответить на этот вопрос в интервью?Как насчет виртуальных базовых классов?

РЕДАКТИРОВАТЬ: я работаю на 32-разрядной платформе.

Ответы [ 4 ]

13 голосов
/ 22 января 2011

Это, конечно, зависит от реализации. И это сделало бы ужасный вопрос интервью. Хороший программист на C ++ может просто поверить sizeof в правильность и позволить компилятору беспокоиться об этих жизнеспособных вещах.

Но что здесь происходит, так это то, что типичная реализация на основе vtable требует двух vtables в объектах класса C или D. Каждый базовый класс нуждается в своем собственном vtable. Новые виртуальные методы, добавленные C и D, могут быть обработаны путем расширения формата vtable из одного базового класса, но таблицы vtables, используемые A и B, не могут быть объединены.

В псевдо-C-коде вот как выглядит наиболее производный объект типа D в моей реализации (g ++ 4.4.5 Linux x86):

void* D_vtable_part1[] = { (void*) 0, &D_typeinfo, &A::f1, &C::f3, &D::f4 };
void* D_vtable_part2[] = { (void*) -4, &D_typeinfo, &B::f2 };

struct D {
  void** vtable_A;
  void** vtable_B;
};

D d = { D_vtable_part1 + 1, D_vtable_part2 + 1 };
2 голосов
/ 31 августа 2012

В этом вопросе, если вы попытаетесь получить Sizeof класса A, он даст вам ответ «4», потому что A имеет только одну виртуальную функцию, поэтому его __vptr будет иметь значение «4».

Точно так же, если вы попытаетесь получить Sizeof класса B, он даст вам ответ «4», потому что B также имеет только одну виртуальную функцию, поэтому его __vptr будет иметь байт «4».

Но класс C наследует оба класса A и B, а сам C имеет виртуальную функцию. Таким образом, C получит 2 указателя __vptr, а для своей собственной виртуальной функции C будет использовать унаследованный __vptr. Поэтому, если вы попытаетесь получить Sizeof класса C, он даст вам ответ «8», потому что C имеет два виртуальных указателя.

И, наконец, класс D наследует класс C, поэтому D будет использовать унаследованный __vptr для своей собственной виртуальной функции, и поскольку класс C имеет размер байта '8', поэтому sizeof D даст ответный байт '8'.

0 голосов
/ 22 января 2011

Размер объекта не имеет ничего общего ни с тем, сколько у него методов , ни с тем, являются ли эти методы виртуальными или нет.Размер объекта определяется исключительно его переменными-членами.

Я не могу точно сказать, почему вы получаете размер 8 байт.Поскольку в вашем классе нет элементов данных, компилятор C ++ может в принципе генерировать класс, который не занимает места вообще [1]!Я предполагаю, что 8 байтов - это минимум, необходимый для предоставления указателя на vtbl, плюс, возможно, некоторые отступы.

[1] Я думаю.Нет времени проверять спецификацию, чтобы узнать, может ли sizeof когда-либо вернуть 0.

0 голосов
/ 22 января 2011

Простите за расплывчатость, но вы говорите, что это домашнее задание в природе.

Посмотрите, что sizeof () возвращает для других классов. Ваш ответ будет зависеть от вашего компилятора и от того, находитесь ли вы в 32- или 64-битной среде.

Счастливого сна!

...