Вопрос о sizeof и функции члена класса - PullRequest
3 голосов
/ 18 февраля 2009
 class B
{
   public:
     int a;
     void fn();
}

Если я создаю объект B, используя

B* pb = new B;

Где находится память fn ()?

Есть ли в объекте указатель, указывающий на выделение памяти функцией fn ()?

Если да, почему sizeof (B) возвращает значение, как будто в объекте вообще нет указателя?

Ответы [ 4 ]

15 голосов
/ 18 февраля 2009

Где находится память fn ()?

Так как это нормальная функция, где-то в разделе кода вашей программы. Это местоположение одинаково для всех экземпляров класса. Фактически, это не имеет ничего общего с созданием B через pb.

Есть ли в объекте указатель, указывающий на выделение памяти функцией fn ()?

Нет. Для обычной функции-члена это не требуется, поскольку адрес известен во время компиляции (или, самое позднее, во время компоновки); поэтому его не нужно хранить отдельно во время выполнения.

Для виртуальных функций ситуация иная. Указатели виртуальных функций хранятся в массиве (для краткости называемом «таблица указателей виртуальных функций» или «vtable»). Каждый класс имеет одну такую ​​vtable, и каждый экземпляр класса хранит указатель на эту vtable. Это необходимо, потому что если указатель / ссылка типа Base указывает на подкласс Derived, компилятор не может узнать, какую функцию вызывать; скорее, правильная функция вычисляется во время выполнения путем поиска в соответствующей таблице. Указатель vtable также очевиден в sizeof объекте.

6 голосов
/ 18 февраля 2009

Это:

class B
{
   public:
     int a;
     void fn();
};

Для всех практических целей эквивалентно коду C:

struct B
{
   int a;
};

void fn(B* bInstance);

За исключением версии C ++, bInstance заменяется указателем this. Память обеих функций существует в стеке. Итак, если вы перейдете к struct equivelant, как вы думаете, каков будет размер (B)?

2 голосов
/ 18 февраля 2009

Там будет только указатель, сохраненный для виртуальной функции (в vtable), но не для не виртуальных функций.

1 голос
/ 18 февраля 2009

1) B * pb = new B выделит память в куче. Это означает, среди прочего, что вам нужно будет очистить его самостоятельно с помощью оператора удаления. Кроме того, вы можете поместить указатель внутри интеллектуального указателя (shared_ptr, auto_ptr. Scope_ptr) и позволить ему выполнить очистку.

2) Поскольку указатель является типом, указывающим на объект или ноль, имеет определенный размер, обычно равный int.

3) fn () НЕ является виртуальной функцией, поэтому в объекте vtable не выделяется память.

...