Как выглядят полиморфные объекты в памяти
Когда-то, я интересовался тем, как объекты С++ располагаются в памяти но быстрый гуглеж ничего не нашел. Недавно, я набрел на статью по теме и, думаю, она может помочь таким как я. Это — ее свободный перевод.

Способы представления абстрактных и не абстрактных объектов в памяти немного отличаются. Давайте, для примера, напишем несколько классов двумерных фигур: круг, прямоугольник и треугольник. Все они будут унаследованы от базового класса-фигуры «shape», который определяет общие для всех фигур свойства — положение, цвет границы и цвет заливки.
Каждый наследник добавляет дополнительные свойства для того, чтобы описать свою геометрию. К примеру, у круга это — радиус, а у треугольника — две стороны и угол между ними.
Код базового класса:
Если бы класс shape не содержал виртуальных методов, то память, отведенная под объекты этого типа содержала бы только данные:

В нашем-же примере есть виртуальные методы. Для реализации полиморфизма, компилятор C++ добавляет указатель на таблицу виртуальных функций, которую называют vtbl. Такой указатель называют vptr. Естественно, компилятор C++ создает vtbl и vptr только когда они нужны.
К примеру, класс «shape» содержит два виртуальных метода — area и perimeter. Соответственно, vtbl объектов этого класса содержит два указателя.

Когда происходит наследование, данные наследника добавляются к базовому классу, а vtbl заменяется на таблицу методов, переопределенных наследником:
Для примера, рассмотрим такой вот класс:
В памяти объект типа «circle» будет выглядеть вот так:

Как видно, расположение данных базового класса внутри дочернего такое-же, как будто дочернего класса и нет вовсе — это нужно для того, чтобы с наследником можно было обращаться как с базовым классом.
Вот так, никакой магии и довольно все просто под капотом у C++.
Небольшое дополнение: Интересно стало — сколько команд занимает вызвать виртуальный метод. Вот что получилось:

Не так уж и страшно, можно совершенно свободно пользоваться.

Способы представления абстрактных и не абстрактных объектов в памяти немного отличаются. Давайте, для примера, напишем несколько классов двумерных фигур: круг, прямоугольник и треугольник. Все они будут унаследованы от базового класса-фигуры «shape», который определяет общие для всех фигур свойства — положение, цвет границы и цвет заливки.
Каждый наследник добавляет дополнительные свойства для того, чтобы описать свою геометрию. К примеру, у круга это — радиус, а у треугольника — две стороны и угол между ними.
Код базового класса:
class shape {
public:
shape();
virtual double area() const;
virtual double perimeter() const;
~~~
private:
coordinates position;
color outline, fill;
};
Если бы класс shape не содержал виртуальных методов, то память, отведенная под объекты этого типа содержала бы только данные:

В нашем-же примере есть виртуальные методы. Для реализации полиморфизма, компилятор C++ добавляет указатель на таблицу виртуальных функций, которую называют vtbl. Такой указатель называют vptr. Естественно, компилятор C++ создает vtbl и vptr только когда они нужны.
К примеру, класс «shape» содержит два виртуальных метода — area и perimeter. Соответственно, vtbl объектов этого класса содержит два указателя.

Когда происходит наследование, данные наследника добавляются к базовому классу, а vtbl заменяется на таблицу методов, переопределенных наследником:
Для примера, рассмотрим такой вот класс:
class circle: public shape {
public:
circle(double r); // constructor
virtual double area() const;
virtual double perimeter() const;
~~~
private:
double radius;
};
В памяти объект типа «circle» будет выглядеть вот так:

Как видно, расположение данных базового класса внутри дочернего такое-же, как будто дочернего класса и нет вовсе — это нужно для того, чтобы с наследником можно было обращаться как с базовым классом.
Вот так, никакой магии и довольно все просто под капотом у C++.
Небольшое дополнение: Интересно стало — сколько команд занимает вызвать виртуальный метод. Вот что получилось:

Не так уж и страшно, можно совершенно свободно пользоваться.
6 комментариев
На микроконтроллере создание объекта (если еще тем более в куче) может ухудшить скорость работы кода.
Как правильно, если использую C++ на мк, стараюсь обходится static-only классами.
Имеет смысл использовать статичный класс, чтобы юзать модификаторы доступа к полям и методам. А как Вы создаете объекты в микроконтроллерных приложениях, статически или динамически? (имеется в виду в более серьезных uc, типо ARM).
Если выбор стоит только между стеком и кучей (static-only классы, кстати нельзя создать на стеке или в куче — вот и потеря гибкости), то стек не порвет — просто стек нужно больше сделать и все. По использованию памяти будет — абсолютно тоже самое, что и выделить память для статического объекта. Кроме того, стек можно еще и в других местах использовать.
Лично я объекты создаю только статически. Иногда использую allocate-only кучу.