Question

Quelque chose que je me suis demandé depuis longtemps: pourquoi ne sont pas des documents Delphi en mesure d'avoir l'héritage (et donc toutes les autres caractéristiques importantes de la POO)

Ceci essentiellement faire des disques de la version de la pile allouée des classes, tout comme les classes C ++, et viderait « objets » (note: pas d'instances) obsolètes. Je ne vois rien un problème avec elle. Ce serait aussi une bonne occasion de mettre en œuvre des déclarations prévisionnelles pour les documents (que je suis toujours déconcerté la raison pour laquelle il manque encore).

Voyez-vous des problèmes avec cela?

Était-ce utile?

La solution

pertinente à cette question, il existe deux types d'héritage:. Héritage d'interface et l'héritage d'implémentation

héritage d'interface implique généralement polymorphisme. Cela signifie que si B est dérivé de A, alors les valeurs de type B peuvent être stockés dans des endroits de type A. Cette situation est problématique pour les types de valeur (comme les dossiers) par opposition aux types de référence, en raison de trancher. Si B est plus grand que A, puis le stocker dans un emplacement de type A tronquera la valeur -. Tous les champs B ajouté dans sa définition par rapport à celles de A seront perdus

héritage de mise en œuvre est moins problématique dans cette perspective. Si Delphi avait l'héritage record, mais seulement de la mise en œuvre, et non de l'interface, les choses ne seraient pas trop mauvais. Le seul problème est que le simple fait d'une valeur de type A un champ de type B ne plus de ce que vous voulez sur l'héritage de mise en œuvre.

L'autre question est des méthodes virtuelles. envoi de méthode virtuelle nécessite une sorte de balise par valeur pour indiquer le type de la valeur d'exécution, de sorte que la méthode surchargée correcte peut être découvert. Mais les dossiers n'ont pas de place pour stocker ce type: les champs de l'enregistrement est tous les champs dont il dispose. Les objets (l'ancien Turbo Pascal type) peuvent avoir des méthodes virtuelles parce qu'ils ont un VMT: le premier objet dans la hiérarchie pour définir une méthode virtuelle ajoute implicitement un VMT à la fin de la définition de l'objet, de plus en plus il. Mais les objets Turbo Pascal ont le même problème à trancher décrit ci-dessus, ce qui les rend problématique. Les méthodes virtuelles sur les types de valeur nécessite effectivement l'héritage d'interface, ce qui implique le problème de découpage en tranches.

Ainsi, afin de soutenir correctement l'héritage d'interface d'enregistrement correctement, nous avions besoin d'une sorte de solution au problème de découpage en tranches. Boxe serait une sorte de solution, mais il faut généralement la collecte des ordures pour être utilisable, et il introduirait une ambiguïté dans la langue, où il ne peut pas être certain que vous travaillez avec une valeur ou une référence - un peu comme Integer vs int en Java avec autoboxing. Au moins en Java il y a des noms séparés pour la boîte vs unboxed « types » de types de valeur. Une autre façon de faire de la boxe est comme Google Go avec ses interfaces, qui est une sorte d'héritage d'interface sans héritage d'implémentation, mais exige que les interfaces à définir séparément et tous les emplacements d'interface sont des références. Les types de valeur (par exemple, des enregistrements) sont mis en boîte quand on se réfère par une référence d'interface. Et bien sûr, Go a également la collecte des ordures.

Autres conseils

Dossiers et classes / objets sont deux choses très différentes dans Delphi. Fondamentalement, un dossier Delphi est une struct C - Delphi supporte même la syntaxe pour faire des choses comme avoir un dossier qui est accessible soit comme 4 entiers de 16 bits ou un 2 entiers 32bits. Comme struct, record remonte avant entré dans la langue la programmation orientée objet (ère Pascal).

Comme un struct un disque est aussi un morceau en ligne de la mémoire, pas un pointeur sur un morceau de mémoire. Cela signifie que lorsque vous passez un enregistrement dans une fonction, vous passez une copie, pas un pointeur / référence. Cela signifie également que lorsque vous déclarez une variable de type d'enregistrement dans votre code, il est déterminé au moment de la compilation de la taille, il est - des variables de type d'enregistrement utilisés dans une fonction sera allouée sur la pile (non pas comme un pointeur sur la pile, mais un 4, 10, 16, etc structure d'octet). Cette taille fixe ne joue pas bien avec le polymorphisme.

Le seul problème que je vois (et je ne pouvais être myope ou mal) est fin. Les enregistrements sont pour stocker des données tandis que les objets sont pour la manipulation et l'utilisation desdites données. Pourquoi un casier de stockage ont besoin des routines de manipulation?

Vous avez raison, l'ajout d'héritage aux dossiers seraient essentiellement les transformer en classes C ++. Et c'est votre réponse là: il ne se fait pas parce que ce serait une chose horrible à faire. Vous pouvez avoir des types de valeur attribuée pile, ou vous pouvez avoir des classes et des objets, mais le mélange des deux est une très mauvaise idée. Une fois que vous faites, vous vous retrouvez avec toutes sortes de problèmes à vie de gestion et finissent par avoir à construire hacks laid comme modèle de RAII C ++ dans la langue afin de les traiter.

Bottom line: Si vous voulez un type de données qui peut être héritée et étendu, des cours d'utilisation. C'est ce qu'ils sont là pour cela.

EDIT: En réponse à la question de Cloud, ce n'est pas vraiment quelque chose qui peut être démontré par un exemple simple. Le modèle objet entier C est une catastrophe de. Il ne peut pas ressembler à un près; vous devez comprendre plusieurs problèmes reliés entre eux pour saisir vraiment la grande image. RAII est juste le désordre au sommet de la pyramide. Peut-être que je vais écrire une explication plus détaillée sur mon blog cette semaine, si j'ai le temps.

Parce que les enregistrements ne sont VMT (table de méthode virtuelle).

Vous pouvez essayer d'utiliser Delphi objet mot-clé pour cela. Ce sont essentiellement héritable, mais se comportent beaucoup plus comme les dossiers que de classes.

Voir cette fil et ce Description

Dans le passé, j'ai objets utilisés (et non des classes!) Sous forme d'enregistrements avec l'héritage.

Contrairement à ce que certaines personnes ici disent qu'il ya des raisons légitimes pour cela. Le cas que je l'ai fait impliqué deux structures provenant de sources externes (API, rien de disque - je besoin du dossier entièrement formé en mémoire)., Dont la seconde étendue que la première

De tels cas sont très rares, cependant.

Ceci est sur le sujet de votre question et concerne l'extension des fonctionnalités d'enregistrement et de types de classe via les aides de classe et d'enregistrement. Selon la documentation de Embarcadero sur ce que vous pouvez étendre une classe ou d'enregistrement (mais pas la surcharge d'opérateur est pris en charge par des aides). Donc, fondamentalement, vous pouvez étendre la fonctionnalité en termes de méthodes membres, mais pas de données membres). Ils prennent en charge les champs de classe que vous pouvez accéder via des accesseurs de la manière habituelle mais je ne l'ai pas testé. Si vous voulez interfacer l'accès aux données de la classe ou l'enregistrement que vous ajoutez l'assistant, vous pourriez probablement y parvenir (à savoir le déclenchement d'un événement ou d'un signal lorsque les données membres de la classe d'origine ou enregistrement a été modifié). Vous ne pouviez pas mettre en œuvre les données cacher si mais il ne vous permet de passer outre une fonction de membre existant de la classe d'origine.

par exemple. Cet exemple fonctionne dans Delphi XE4. Créez une nouvelle application Forms VCL et remplacer le code de part1 avec le code suivant:

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
  Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, System.Types;

type

  TMyArray2D = array [0..1] of single;

  TMyVector2D = record
  public
    function Len: single;
    case Integer of
      0: (P: TMyArray2D);
      1: (X: single;
          Y: single;);
  end;

  TMyHelper = record helper for TMyVector2D
    function Len: single;
  end;


  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;


implementation

function TMyVector2D.Len: Single;
begin
  Result := X + Y;
end;

function TMyHelper.Len: single;
begin
  Result := Sqrt(Sqr(X) + Sqr(Y));
end;

procedure TestHelper;
var
  Vec: TMyVector2D;
begin
  Vec.X := 5;
  Vec.Y := 6;
  ShowMessage(Format('The Length of Vec is %2.4f',[Vec.Len]));
end;

procedure TForm1.Form1Create(Sender: TObject);
begin
  TestHelper;
end;

Notez que le résultat est 7,8102 au lieu de 11. Cela montre que vous pouvez masquer les méthodes membres de la classe d'origine ou l'enregistrement avec un assistant de classe ou un enregistrement.

D'une certaine manière vous simplement traiter l'accès aux membres de données d'origine la même chose que vous le feriez dans l'évolution des valeurs à partir de l'unité dans laquelle une classe est déclarée en changeant par les propriétés plutôt que les champs directement afin que les mesures appropriées sont prises par les accesseurs de ces données.

Merci d'avoir posé la question. Je certainement beaucoup appris en essayant de trouver la réponse et il m'a aidé beaucoup trop.

Brian Joseph Johns

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top