Как компиляторы реализуют C++ наследование?

C++ поддерживает наследование.

Но как это реализовано в компиляторе?

Компилятор копирует и вставляет всю реализацию от родителя к дочернему?

2 ответа

Чрезвычайно упрощен, если мы говорим о чем-то вроде этого:

class A 
{
 public:
 int func1() { do something; }
 int func2() { do something; }
 };

class B : public A
{
 public:
 int func2() { do somethign else; }
};

B b;

b.func1();

то то, что происходит внутри компилятора, будет таким (помните, что это ОЧЕНЬ упрощено, а реальный код компилятора будет намного сложнее, я уверен):

... fname = "func1" from the source code ... 
 ... object = "b"; 
function fn;
while (!(fn = find_func(object, fname))) 
 object = parent_object(object);
if (fn)
 produce_call(fn); 
else
 print_error_not_found(fname);

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

[В приведенном выше, я проигнорировал тот факт, что один класс может иметь более одного "родительского" класса - он не изменяет того, как все работает, просто чтобы код поддерживал список или массив "больше классов на тот же уровень"]


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

Компилятор знает, где этот подобъект находится относительно полного объекта, и будет вставлять арифметику указателя во всем мире, где есть листинг (возможно, неявный) между указателем (или ссылкой) на производный и базовый. Это включает в себя скрытый this -pointer аргументы, передаваемые функции - члены базового типа.

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

licensed under cc by-sa 3.0 with attribution.