Delphi: la Compréhension des constructeurs
je suis à la recherche de comprendre
- virtuel
- remplacer
- surcharge
- réintroduire
lorsqu'il est appliqué à l'objet des constructeurs. Chaque fois que j'ajoutez des mots-clés jusqu'à ce que le compilateur s'arrête et (après 12 ans de développement de Delphi), je préfère savoir ce que je fais, plutôt que de tenter des choses au hasard.
Donné un hypothétique ensemble d'objets:
TComputer = class(TObject)
public
constructor Create(Cup: Integer); virtual;
end;
TCellPhone = class(TComputer)
public
constructor Create(Cup: Integer; Teapot: string); virtual;
end;
TiPhone = class(TCellPhone)
public
constructor Create(Cup: Integer); override;
constructor Create(Cup: Integer; Teapot: string); override;
end;
La façon dont je veux qu'ils se comportent est probablement évident, à partir des déclarations, mais:
TComputer
a la simple constructeur, et les descendants pouvez la remplacerTCellPhone
a un autre constructeur, et les descendants pouvez la remplacerTiPhone
remplace les deux constructeurs, l'appel de la version héritée de chaque
Maintenant que le code ne compile pas. je veux comprendre pourquoi il ne fonctionne pas. je tiens également à comprendre la bonne façon de remplacer les constructeurs. Ou peut-être que vous ne pourrait jamais remplacer les constructeurs? Ou peut-être qu'il est parfaitement acceptable de remplacer les constructeurs? Peut-être que vous ne devriez jamais avoir plusieurs constructeurs, peut-être qu'il est parfaitement acceptable d'avoir plusieurs constructeurs.
je veux comprendre la pourquoi. Fixation il serait alors évident.
Voir aussi
- Delphi: Comment masquer ancêtre des constructeurs?
- La réintroduction de fonctions en Delphi
- Delphi: Comment ajouter un constructeur différent à un descendant?
Edit: je suis également à la recherche pour obtenir un certain raisonnement sur l'ordre de virtual
, override
, overload
, reintroduce
. Parce que lorsque l'on essaie toutes les combinaisons de mots-clés, le nombre de combinaisons explose:
- virtuel; surcharge;
- virtuel; override;
- remplacer; surcharge;
- remplacer; virtual;
- virtuel; override; surcharge;
- virtuel; surcharge; override;
- surcharge; virtual; override;
- remplacer; virtual; surcharge;
- remplacer; surcharge; virtual;
- surcharge; override; virtual;
- etc
Edit 2: je suppose que nous devrions commencer par "est la hiérarchie de l'objet même possible?" Si non, pourquoi pas? Par exemple, est-il fondamentalement incorrect d'avoir un constructeur à partir d'un ancêtre?
TComputer = class(TObject)
public
constructor Create(Cup: Integer); virtual;
end;
TCellPhone = class(TComputer)
public
constructor Create(Cup: Integer; Teapot: string); virtual;
end;
je m'attends à ce que TCellPhone
a maintenant deux constructeurs. Mais je ne trouve pas la combinaison de mots-clés dans Delphi pour vous, il pense que c'est une bonne chose à faire. Je suis fondamentalement tort de penser que je peux avoir deux constructeurs ici dans TCellPhone
?
Remarque: Tout en dessous de cette ligne n'est pas strictement nécessaire pour répondre à la
question - mais peut aider à expliquer
ma pensée. Peut-être vous pouvez le voir,
basé sur mon processus de pensée, ce qui
pièce essentielle, je suis absent que
tout devient clair.
Maintenant ces déclarations ne compile pas:
//Method Create hides virtual method of base type TComputer:
TCellPhone = class(TComputer)
constructor Create(Cup: Integer; Teapot: string); virtual;
//Method Create hides virtual method of base type TCellPhone:
TiPhone = class(TCellPhone)
public
constructor Create(Cup: Integer); override;
constructor Create(Cup: Integer; Teapot: string); overload; <--------
end;
Alors d'abord je vais essayer de fixation TCellPhone
. je vais commencer par hasard ajout de la overload
mot-clé (je sais que je ne veux pas reintroduce
parce que ce serait de masquer les autres constructeurs, je ne veux pas):
TCellPhone = class(TComputer)
public
constructor Create(Cup: Integer; Teapot: string); virtual; overload;
end;
Mais qui échoue: Field definition not allowed after methods or properties
.
je sais par expérience que, même si je n'ai pas un champ après une méthode ou une propriété, si j'inverse l'ordre des virtual
et overload
mots-clés: Delphi taire:
TCellPhone = class(TComputer)
public
constructor Create(Cup: Integer; Teapot: string); overload; virtual;
end;
Mais j'ai toujours l'erreur:
Méthode de "Créer" des peaux de méthode virtuelle de la base type 'TComputer'
Donc j'ai essayer d'enlever les deux mots clés:
TCellPhone = class(TComputer)
public
constructor Create(Cup: Integer; Teapot: string);
end;
Mais j'ai toujours l'erreur:
Méthode de "Créer" des peaux de méthode virtuelle de la base type 'TComputer'
Donc je me résigne à maintenant essayer reintroduce
:
TCellPhone = class(TComputer)
public
constructor Create(Cup: Integer; Teapot: string); reintroduce;
end;
Et maintenant TCellPhone compile, mais il a fait des choses bien pire pour TiPhone:
TiPhone = class(TCellPhone)
public
constructor Create(Cup: Integer); override; <-----cannot override a static method
constructor Create(Cup: Integer; Teapot: string); override; <-----cannot override a static method
end;
Les deux sont à se plaindre que je ne peut pas les remplacer, j'ai donc supprimer le override
mot-clé:
TiPhone = class(TCellPhone)
public
constructor Create(Cup: Integer);
constructor Create(Cup: Integer; Teapot: string);
end;
Mais maintenant le 2ème créer, dit-il, doivent être marqués avec la surcharge, ce que je fais (en fait, je vais le marquer à la fois que la surcharge de travail, car je sais ce qui va arriver si je n'ai pas):
TiPhone = class(TCellPhone)
public
constructor Create(Cup: Integer); overload;
constructor Create(Cup: Integer; Teapot: string); overload;
end;
Tous tout est bon dans le interface
section. Malheureusement, mon implémentations ne fonctionne pas. Mon seul paramètre du constructeur de TiPhone ne peut pas appeler le constructeur hérité:
constructor TiPhone.Create(Cup: Integer);
begin
inherited Create(Cup); <---- Not enough actual parameters
end;
- À partir de Delphi 9 de l'aide: les déclarations de Méthode peuvent inclure des directives spéciales qui ne sont pas utilisés avec d'autres fonctions ou procédures. Les Directives devraient apparaître dans la déclaration de classe, pas dans la définition de la déclaration, et doit toujours être énumérés dans l'ordre suivant:
reintroduce
;overload
; reliure; convention d'appel;abstract
; avertissement, où la liaison estvirtual
,dynamic
, ouoverride
; convention d'appel estregister
,pascal
,cdecl
,stdcall
, ousafecall
; et d'avertissement estplatform
,deprecated
, oulibrary
. - Delphi 5 encore est venu avec un excellent niveau de Langue écrite Guide expliquant ces déclarations dans les détails.
- Essayez TCellPhone.Créer(Cup); au lieu de l'héritage de Créer(Cup);
Vous devez vous connecter pour publier un commentaire.
Je vois deux raisons, la première série de déclarations ne devrait pas compiler proprement:
Il devrait y avoir un avertissement dans
TCellPhone
que son constructeur cache la méthode de la classe de base. C'est parce que la base de la méthode de classe est virtuel, et le compilateur soucis que vous êtes l'introduction d'un nouveau méthode avec le même nom sans écraser la base de la méthode de classe. Il n'importe pas que les signatures diffèrent. Si votre intention est en effet de cacher la méthode de la classe de base, alors vous devez utiliserreintroduce
sur le descendant de la déclaration, comme l'un de vos angles devine a montré. Le seul but de cette directive est d'étouffer l'avertissement; il n'a pas d'effet sur le temps d'exécution de comportement.En ignorant ce qui se passe avec
TIPhone
plus tard, à la suite deTCellPhone
déclaration est ce que vous voulez. Il cache l'ancêtre de la méthode, mais vous voulez qu'il soit aussi bien virtuelles. Il ne sera pas hérité de la virtualness de l'ancêtre de la méthode parce qu'ils sont deux choses complètement distinctes des méthodes qui venez d'arriver à avoir le même nom. Par conséquent, vous devez utiliservirtual
sur la nouvelle déclaration.La base le constructeur de la classe,
TComputer.Create
, est également cacher une méthode de son ancêtre,TObject.Create
, mais puisque la méthode dansTObject
n'est pas du virtuel, le compilateur n'a pas prévenu à ce sujet. Cacher non-méthodes virtuelles arrive tout le temps et est généralement normaux.Vous devriez obtenir un erreur dans
TIPhone
car il n'y a plus d'un argument du constructeur de remplacement. Vous vous êtes caché dansTCellPhone
. Puisque vous voulez avoir deux constructeurs,reintroduce
clairement n'était pas le bon choix pour une utilisation antérieure. Vous ne voulez pas masquer la base le constructeur de la classe; vous voulez l'augmenter avec un autre constructeur.Puisque vous voulez les deux constructeurs ont le même nom, vous devez utiliser le
overload
directive. Cette directive doit être utilisé surtous les originaux des déclarations — la première fois à chaque signature est introduitedéclarations subséquentes dans les descendants. Je pensais qu'il était nécessaire sur tous déclarations (même la classe de base), et il ne fait pas de mal de le faire, mais je suppose qu'il n'est pas nécessaire. Donc, vos déclarations devrait ressembler à ceci:Moderne de la documentation dit quel ordre, tout devrait aller dans:
Ces six catégories distinctes, mais dans mon expérience, il est rare d'avoir plus de trois sur toute déclaration. (Par exemple, les fonctions qui ont besoin de conventions d'appel spécifié ne sont probablement pas de méthodes, de sorte qu'ils ne peuvent pas être virtuel.) Je ne me souviens jamais de l'ordre; je ne l'ai jamais vu documenté jusqu'à aujourd'hui. Au lieu de cela, je pense qu'il est plus utile de se souvenir de chaque directive but. Lorsque vous vous souvenez de directives qui vous avez besoin pour les différentes tâches, vous vous retrouverez avec seulement deux ou trois, et ensuite c'est assez simple de faire des essais pour obtenir une commande valide. Le compilateur peut accepter plusieurs commandes, mais ne vous inquiétez pas — ordre n'est pas important dans la détermination du sens. Toute commande du compilateur accepte auront le même sens que tous les autres (sauf pour les conventions d'appel; si vous parlez plus d'un de ceux-ci, seul le dernier compte, afin de ne pas le faire).
Oui, alors vous avez juste à vous rappeler le but de chaque directive, et de penser à ceux qui ne font pas de sens ensemble. Par exemple, vous ne pouvez pas utiliser
reintroduce
etoverride
en même temps, parce qu'ils ont des sens opposés. Et vous ne pouvez pas utiliservirtual
etoverride
ensemble parce que l'un implique l'autre.Si vous avez beaucoup de directives accumulent, vous pouvez toujours couper
overload
hors de l'image pendant que vous travaillez le reste des directives dont vous avez besoin. Donnez à vos méthodes de noms différents, savoir qui de la autres directives dont ils ont besoin par eux-mêmes, puis ajouteroverload
dos pendant que vous leur donnez tous les mêmes noms.Noter que je n'ai pas de Delphi 5, je vais donc me baser mes réponses au large de la nouvelle version de Delphi XE. Je ne pense pas que cela va vraiment faire une différence ici, mais si c'est le cas, vous avez été prévenu. 🙂
C'est principalement basée sur http://docwiki.embarcadero.com/RADStudio/en/Methods, qui est le courant de la documentation de la façon dont les méthodes de travail. Votre Delphi 5 fichier d'aide a probablement quelque chose de similaire à ce que bien.
Tout d'abord, un constructeur virtuel ne peut pas faire beaucoup de sens ici. Il ya quelques cas où vous ne voulez pas cela, mais ce n'est probablement pas une. Jetez un oeil à http://docwiki.embarcadero.com/RADStudio/en/Class_References pour une situtation où vous avez besoin d'un constructeur virtuel - si vous savez toujours le type de vos objets lors du codage, cependant, vous n'avez pas.
Le problème que vous obtenez alors votre de 1 constructeur de paramètre, c'est que votre classe parent n'est pas de 1 constructeur de paramètre lui-même héréditaire, les constructeurs ne sont pas exposés. Vous ne pouvez pas utiliser
inherited
aller jusqu'à plusieurs niveaux dans la hiérarchie, vous pouvez uniquement appeler votre parent immédiat. Vous aurez besoin d'appeler le 2-paramètre de constructeur avec une certaine valeur par défaut, ou ajouter de 1 constructeur de paramètre à TCellPhone ainsi.En général, les quatre mots-clés ont les significations suivantes:
virtual
Marque ce comme une fonction de l'endroit où vous voulez le temps d'exécution de dispatching (permet le comportement polymorphique). Ce n'est que pour la définition initiale, et non pas lors de la substitution dans les sous-classes.override
- Fournir une nouvelle mise en œuvre d'une méthode virtuelle.overload
Marque une fonction avec le même nom qu'une autre fonction, mais d'une autre liste de paramètres.reintroduce
- Dire au compilateur vous fait prévu pour masquer une méthode virtuelle, au lieu de simplement oublier d'approvisionnementoverride
.De la commande demandée est détaillée dans la documentation:
Create(int, string)
cache de la base deCreate(int)
. Il a une signature différente, comment est-il le cacher?virtual
le compilateur ne doit pas émettre de l'avertissement à propos de cacher quoi que ce soit - les constructeurs sont associés directement avec leur classe.overload
directive? (Comme je l'ai dit, j'ai essayé à tout hasard de la combinaison de mots - clés, et je ne peux pas le faire se plaignent pas). Une autre réponse serait parfait - permettant à un code lisible.C'est un travail de mise en œuvre de l'définitions voulais:
avec les résultats:
La première partie est en conformité avec cette. La définition de la
TiPhone
deux constructeurs se déroule alors comme suit:overload; override
surcharger leTCellPhone
un tout en substituant les autres constructeur.override
afin de remplacer son frère.utiliser la surcharge sur les deux, c'est la façon dont je le fais, et ça marche.
constructor Create; Overload
; <-- utiliser la surcharge iciconstructor Values; Overload;
<-- et icirappelez-vous de ne pas utiliser le même nom pour les deux constructeurs