Pertinente a esta pregunta, existen dos tipos de herencia: la herencia de la interfaz y la herencia de la implementación.
La herencia de la interfaz generalmente implica polimorfismo. Significa que si B se deriva de A, entonces B se puede almacenar en ubicaciones de tipo A. Esto es problemático para los tipos de valores (como los registros) en comparación con los tipos de referencia, debido a la división. Si B es más grande que A, entonces almacenarlo en una ubicación de tipo A truncará el valor; cualquier campo que B agregue en su definición por encima de A se perderá.
La herencia de implementación es menos problemática desde esta perspectiva. Si Delphi tuviera una herencia récord pero solo de la implementación, y no de la interfaz, las cosas no estarían tan mal. El único problema es que simplemente convertir un valor de tipo A en un campo de tipo B hace que la mayor parte de lo que desea fuera de la herencia de implementación.
El otro problema son los métodos virtuales. El envío de métodos virtuales requiere algún tipo de etiqueta por valor para indicar el tipo de tiempo de ejecución del valor, de modo que se pueda descubrir el método correcto anulado. Pero los registros no tienen ningún lugar para almacenar este tipo: los campos del registro son todos los campos que tiene. Los objetos (el antiguo tipo de Turbo Pascal) pueden tener métodos virtuales porque tienen un VMT: el primer objeto en la jerarquía para definir un método virtual agrega implícitamente un VMT al final de la definición del objeto, haciéndolo crecer. Pero los objetos de Turbo Pascal tienen el mismo problema de corte descrito anteriormente, lo que los hace problemáticos. Los métodos virtuales en los tipos de valor requieren de manera efectiva la herencia de la interfaz, lo que implica el problema de corte.
Para admitir adecuadamente la herencia de interfaz de grabación correctamente, necesitaríamos algún tipo de solución para el problema de corte. El boxeo sería un tipo de solución, pero generalmente requiere la recolección de basura para ser utilizable, e introduciría ambigüedad en el lenguaje, donde puede no estar claro si está trabajando con un valor o una referencia, un poco como Integer vs int en Java con autoboxing. Al menos en Java hay nombres separados para los "tipos" de tipos de valores en caja o no. Otra forma de hacer el boxeo es como Google Go con sus interfaces, que es un tipo de herencia de interfaz sin herencia de implementación, pero requiere que las interfaces se definan por separado, y todas las ubicaciones de la interfaz son referencias. Los tipos de valor (por ejemplo, registros) están encuadrados cuando se hace referencia a ellos mediante una referencia de interfaz. Y, por supuesto, Go también tiene recolección de basura.
Cuando dices * protoyping *, creo que el término que realmente quieres decir es * forward declarations *. –
Sí, lo siento, lapso de memoria momentáneo. : P Básicamente es lo mismo, simplemente deletreado de manera diferente entre el mundo Delphi y C++. Aunque prefiero el nombre Delphi, mucho más autoexplicativo. – Cloud737
En realidad, * prototype * solo se usa con respecto a funciones en C++, también. C++ usa * forward declaration * para tipos de clase, al igual que Delphi. –