Методы класса увеличивают размер экземпляров класса? - PullRequest
28 голосов
/ 09 ноября 2011

Вопрос довольно прямой.Для ясности рассмотрим приведенный ниже пример:

// Note that none of the class have any data members
// Or if they do have data members, they're of equal size, type, and quantity
class Foo {
public:
    void foo1();
    void foo2();
    // 96 other methods ...
    void foo99();
};

class Bar {
public:
    // Only one method
    void bar();
};

class Derived1 : public Foo { };
class Derived2 : public Bar { };

int main() {
    Foo f;
    Bar b;
    Derived1 d1;
    Derived2 d2;
    return 0;
}

Все ли экземпляры f, b, d1 и d2 занимают одинаковое количество места в памяти?В качестве дополнения к этому вопросу, копирование экземпляров Foo при его передаче займет больше времени, чем Bar, теоретически?

Ответы [ 4 ]

25 голосов
/ 09 ноября 2011

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

Кроме того, как правильно сказал кто-то другой, минимальный размер класса составляет 1 байт.

Некоторые примеры:

// size 1 byte (at least)
class cls1
{
};

// size 1 byte (at least)
class cls2
{
    // no hit to the instance size, the function address is used directly by calling code.
    int instanceFunc();
};

// sizeof(void*) (at least, for the v-table)
class cls3
{
    // These functions are indirectly called via the v-table, a pointer to which must be stored in each instance.
    virtual int vFunc1();
    // ...
    virtual int vFunc99();
};

// sizeof(int) (minimum, but typical)
class cls4
{
    int data;
};

// sizeof(void*) for the v-table (typical) since the base class has virtual members.
class cls5 : public cls3
{
};

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

Наконец, параметры выравнивания данных элемента могут оказать влияние. Компилятор может иметь некоторую опцию или #pragma, чтобы указать, что данные элемента должны иметь начальный адрес, кратный указанному количеству байтов. Например, с выравниванием по 4-байтовым границам и предполагая sizeof(int) = 4:

// 12 bytes since the offset of c must be at least 4 bytes from the offset of b. (assuming sizeof(int) = 4, sizeof(bool) = 1)
class cls6
{
    int a;
    bool b;
    int c;
};
4 голосов
/ 09 ноября 2011

Строго говоря, это зависит от реализации. Но количество методов не должно изменять размер объектов класса. Для не виртуальных методов в памяти объекта нет ничего, что относится к указателям на методы. Если у вас есть виртуальные методы, то у каждого объекта есть один указатель на виртуальную таблицу. Таблица v увеличивается, когда вы добавляете больше методов, но размер указателя остается прежним.

Дополнительная информация: для не виртуальных методов компилятор отслеживает указатели методов для каждого класса. когда вы вызываете не виртуальный метод, компилятор передает указатель на метод, который указывает на объект, либо как скрытый параметр, либо в стеке. Вот как метод «знает» свой объект и имеет доступ к указателю this. Для виртуальных методов указатель метода на самом деле является индексом в vtable, поэтому компилятор передает this разыменованной записи в vtable.

3 голосов
/ 09 ноября 2011

Да, они будут. На самом деле в вашем случае размер будет равен 1. В C ++ класс даже без какого-либо члена данных будет иметь размер 1.

1 голос
/ 09 ноября 2011

Foo и Bar должны быть по одному байту. Derived1 и Derived2 могут быть одним или двумя байтами.

Причина в том, что компилятор хранит всю статическую информацию в исполняемом коде, включая все функции-члены. Когда ваш код вызывает foo1 в экземпляре Foo, он просто вызывает Foo::foo1(this), что одинаково для каждого Foo в программе. виртуальные функции являются исключением, но не добавляют дополнительный размер для каждой функции-члена, только разовый дополнительный размер (обычно 4/8 байт), если вообще есть какие-либо виртуальные функции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...