Как осуществляется вызов функции для подтипа?

В настоящее время я разрабатываю язык программирования, и мне интересно, как решить эту проблему:

Предположим, что у меня есть класс (или интерфейс) A, который выглядит следующим образом:

class A { // size is 4 bytes
int32 a = 0;
}

и второй класс B, который расширяет его и выглядит так:

class B extends A { // size is 8 bytes
int32 b = 0;
}

и что у меня есть функция f, которая выглядит так:

int32 f(A first, A second) {
return first.a + second.a;
}

Однако, если я вызываю его с двумя B, second.a не будет находиться в том же месте, как если бы он вызывался с двумя As, поскольку первый параметр сместит его. Мои текущие мысли для решения этого:

  1. Запрещение параметров неизвестного размера и принудительная передача его в качестве указателя или ссылки (я думаю, что именно это делает Rust)
  2. Запись всей следующей информации в стек вызовов: указатель на секунду, указатель на секунду, параметры не переменного размера, первая, вторая
  3. Создание функции для каждого возможного размера first и second и определение, какую из них вызывать во время компиляции, если она известна, или во время выполнения с использованием vtables.

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

Третья идея потребует создания большого количества функций (функция, которая принимает 5 параметров, которые могут иметь 20 различных подтипов, потребует, чтобы было сгенерировано 100 одинаковых фрагментов кода, если он вызывается только с параметрами неизвестного типа), и потребуется vtable для каждого класса, который использует только одну функцию. Кроме того, функция в уже скомпилированной библиотеке не может использоваться с новым подтипом.

Комбинация 2 и 3 и создание двух версий одних и тех же функций, одна из которых принимает только тип, а другая тоже принимает подтипы, может решить некоторые из этих проблем.

Мне интересно, есть ли лучшие решения для этого, и как другие языки, такие как C ++, реализуют это.

1

Решение

В C ++ вызов f(A) с параметром подтипа B по значению эквивалентно

f(static_cast<const A&>(b));

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

Динамический полиморфизм нуждается в ссылке или указателе, во многом по причинам, которые вы обрисовали. Но если вы хотите передать «ссылку по значению», простейшим решением, вероятно, будет передача ссылки на копию объекта. Обратите внимание, что в таком случае каждому объекту необходимо «знать», какой тип он должен назвать правильным конструктором копирования, или быть производным от общего суперкласса и реализовывать некоторую форму clone(),

3

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]