В настоящее время я разрабатываю язык программирования, и мне интересно, как решить эту проблему:
Предположим, что у меня есть класс (или интерфейс) 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, поскольку первый параметр сместит его. Мои текущие мысли для решения этого:
Вторая идея будет проблемой, потому что она должна поддерживаться всеми функциями, даже если они редко или никогда не вызываются с использованием подтипа, что неэффективно.
Третья идея потребует создания большого количества функций (функция, которая принимает 5 параметров, которые могут иметь 20 различных подтипов, потребует, чтобы было сгенерировано 100 одинаковых фрагментов кода, если он вызывается только с параметрами неизвестного типа), и потребуется vtable для каждого класса, который использует только одну функцию. Кроме того, функция в уже скомпилированной библиотеке не может использоваться с новым подтипом.
Комбинация 2 и 3 и создание двух версий одних и тех же функций, одна из которых принимает только тип, а другая тоже принимает подтипы, может решить некоторые из этих проблем.
Мне интересно, есть ли лучшие решения для этого, и как другие языки, такие как C ++, реализуют это.
В C ++ вызов f(A)
с параметром подтипа B
по значению эквивалентно
f(static_cast<const A&>(b));
static_cast
может привести к тому, что память по тому же адресу будет просто интерпретирована как начало более короткого блока данных, или к прозрачному добавлению некоторого смещения сначала (если A
не первый базовый класс или виртуальный). После этого, внутри, конструктор копирования A
называется. В любом случае информация, которая была добавлена B
полностью теряется вместе с переопределением виртуальных функций. Для всех целей то, что передано, больше не является B
,
Динамический полиморфизм нуждается в ссылке или указателе, во многом по причинам, которые вы обрисовали. Но если вы хотите передать «ссылку по значению», простейшим решением, вероятно, будет передача ссылки на копию объекта. Обратите внимание, что в таком случае каждому объекту необходимо «знать», какой тип он должен назвать правильным конструктором копирования, или быть производным от общего суперкласса и реализовывать некоторую форму clone()
,
Других решений пока нет …