Почему размер этого подкласса такой же, как у базового класса, хотя он добавляет переменную-член?

Почему в следующем коде размер Parent совпадает с размером Child (даже если Child добавляет переменную-член)? Еще одно странное поведение: если я закомментирую строку, в которой определен b, размер Child останется прежним, но если я добавлю еще одну переменную (int b, c;), то sizeof даст 24. Объяснение того, почему это происходит, было бы очень признательно (:

#include <iostream>

class Parent {
    int a = 0;
public:
    virtual void foo() {}
};

class Child : public Parent {
    int b; // this line doesn't affect the output
};

int main() {
    std::cout << sizeof(Parent) << ", " << sizeof(Child);
    return 0;
}
// Output is : 16, 16

Примечание: я впервые задаю здесь вопросы, поэтому не стесняйтесь просить меня отредактировать их, если они неясны или плохо сформулированы.

🤔 А знаете ли вы, что...
C++ был разработан в начале 1980-х годов Бьярном Страуструпом в Bell Labs.


1
106
2

Ответы:

Это связано с наличием виртуальной функции foo:

virtual void foo() {}

Компилятор генерирует указатель на таблицу адресов виртуальных функций, который, похоже, в вашей системе равен 8, а sizeof( int ) равен 4. Таким образом, из-за распределения адреса по 8 байтам родительского класса его размер равен 16.

Если вы удалите виртуальную функцию в родительском классе или хотя бы объявите член данных a родительского класса с типом sizeof которого равен sizeof указателя на таблицу адресов виртуальных функций, то размеры классов будут равны другой

Вот две демонстрационные программы.

#include <iostream>

class Parent
{
    int a = 0;
public:
//    virtual void foo() {}
};

class Child : public Parent
{
    int b;
};

int main()
{
    std::cout << sizeof( Parent ) << ", " << sizeof( Child ) << '\n';
}

Вывод программы

4, 8

И

#include <iostream>

class Parent
{
    long long int a = 0;
public:
    virtual void foo() {}
};

class Child : public Parent
{
    int b;
};

int main()
{
    std::cout << sizeof( Parent ) << ", " << sizeof( Child ) << '\n';
}

Вывод программы

16, 24

Решено

Спасибо всем за ваши ответы/комментарии, я думаю, что ответ @Peter хорошо это объясняет: это связано с выравниванием 8 байтов, требуемым виртуальной функцией (по крайней мере, в моей системе). Так интересно, без виртуальной функции:

class Parent 
{
    int a = 0;
public:
    // virtual void foo() {}
};

Результатом alignof(Parent) является 4, поэтому любая отдельная переменная int будет влиять на результат sizeof, но с помощью виртуальной функции:

class Parent 
{
    int a = 0;
public:
    virtual void foo() {}
};

alignof(Parent) теперь дает 8, поэтому для изменения результата int потребуются еще две переменные sizeof.