Delphi: comment cacher les constructeurs d'ancêtres?

mise à jour: vidé la question avec un exemple plus simple, qui n'est pas répondu par la réponse initialement acceptée

étant donné la classe suivante, et son ancêtre:

TComputer = class(TObject)
public
   constructor Create(Teapot: string='');
end;

TCellPhone = class(TComputer)
public
   constructor Create(Cup: Integer); overload; virtual;
   constructor Create(Cup: Integer; Teapot: string); overload; virtual;
end;

en ce moment TCellPhone a 3 constructeurs visibles:

  • Cup: Integer
  • tasse: entier; théière: corde
  • Théière: string = "

Que dois-je faire pour TCellPhone de sorte que le constructeur ancêtre ( Teapot: string = '' ) n'est pas visible, ne laissant que les constructeurs déclarés:

  • Cup: Integer
  • tasse: entier; théière: corde

Note : habituellement le simple fait de ayant un constructeur descendant se cache l'ancêtre:

TCellPhone = class(TComputer)
public
   constructor Create(Cup: Integer); virtual;
end;
  • Cup: Integer

et si vous voulu de garder à la fois les le constructeur ancêtre et le descendant, vous marqueriez le descendant comme un overload :

TCellPhone = class(TComputer)
public
   constructor Create(Cup: Integer); overload; virtual;
end;
  • Cup: Integer
  • théière: string = "

dans cette question exemple de code, Delphi se trompe sur mes mots-clés overload :

TCellPhone = class(TComputer)
public
   constructor Create(Cup: Integer); overload; virtual;
   constructor Create(Cup: Integer; Teapot: string); overload; virtual;
end;

penser que:

  • je veux surcharger mes constructeurs avec le ancêtre ,
  • quand vraiment je veux le surcharger avec le frère

Comment cacher le constructeur ancêtre?

Note: Il pourrait être impossible de cacher l'ancêtre, non-virtuelle, constructeur en utilisant le langage Delphi, tel qu'il est actuellement défini. "impossible" est une réponse valide.


tentative de réponse (échec)

I essayé marquage des constructeurs descendants avec reintroduce (retombant à mon mode d'ajouter des mots-clés au hasard jusqu'à ce qu'il fonctionne):

TCellPhone = class(TComputer)
public
   constructor Create(Cup: Integer); reintroduce; overload; virtual;
   constructor Create(Cup: Integer; Teapot: string); reintroduce; overload; virtual;
end;

mais ça n'a pas marché, les trois constructeurs sont encore visibles. : (


Question Initiale

j'ai un objet qui descend d'une classe qui possède les constructeurs ne veulent pas voir:

TEniac = class(TObject)
   constructor Create(PowerCord: TPowerCord=nil); //calls inherited Create

TComputer = class(TEniac) ...
   constructor Create(PowerCord: TPowerCord=nil); //calls inherited Create(nil)

TCellPhone = class(TComputer)
   constructor Create(sim: TSimChip; UnlockCode: Integer); //calls inherited Create(nil)

TiPhone = class(TCellPhone)
   constructor Create(sim: TSimChip); //calls inherited Create(sim, 0)

Note: il s'agit d'un exemple hypothétique. Comme dans le monde réel, les objets ancêtre ne peuvent pas être changés sans briser le code existant.

Maintenant, quand quelqu'un est à l'aide de TiPhone je ne veux pas encore être en mesure de voir le constructeur de TEniac :

iphone := TiPhone.Create(powerCord);

pire encore: s'ils appellent ce constructeur, ils ratent complètement mon constructeur, et tout ce qui se fait entre les deux. Il est assez facile d'appeler le mauvais constructeur, Tous sont visibles dans le code IDE-completion, et vont compiler:

TiPhone.Create;

et ils obtiennent un objet complètement invalide.

je pouvais changer TCellPhone pour lancer une exception dans ces constructeurs:

TCellPhone.Create(PowerCord: TPowercord)
begin
   raise Exception.Create('Don''t use.');
end;

mais les développeurs ne réaliseront pas qu'ils appellent le mauvais constructeur jusqu'à ce que le client trouve l'erreur Un jour et nous amende des milliards de dollars. En fait, je suis essayer pour trouver partout j'appelle le mauvais constructeur - mais je ne peux pas comprendre comment faire Delphi me dire!

10
demandé sur Ian Boyd 2010-10-06 19:46:49

6 réponses

il est impossible de rendre un constructeur introduit dans un ancêtre inaccessible pour la création d'une classe dérivée dans Delphi parce que vous pouvez toujours faire ceci:

type
  TComputerClass = class of TComputer;

var
  CellPhoneClass: TComputerClass = TCellPhone;
  CellPhone : TCellPhone;
begin
  CellPhone := CellPhoneClass.Create('FUBAR') as TCellPhone;
end;

rien de ce que vous pourriez faire dans le code d'une classe dérivée ne pourrait jamais empêcher quiconque d'appeler L'ordinateur.Créer constructeur pour créer une instance de la classe dérivée.

Le meilleur que vous pourriez faire est:

TComputer = class(TObject)
public
   constructor Create(Teapot: string=''); virtual;
end;

TCellPhone = class(TComputer)
public
   constructor Create(Teapot: string=''); overload; override;
   constructor Create(Cup: Integer); overload; virtual;
   constructor Create(Cup: Integer; Teapot: string); overload; virtual;
end;

In dans ce cas, le code ci-dessus appellerait au moins TCellPhone.Create(Teapot: string='') au lieu de TComputer.Create(Teapot: string='')

6
répondu Thorsten Engler 2010-11-02 05:00:43

si je me souviens bien, alors reintroduce devrait aider pour méthodes virtuelles .

la directive réintroduit la directive supprime les avertissements du compilateur concernant la dissimulation de méthodes virtuelles déclarées précédemment. Utilisez réintroduire lorsque vous voulez cacher une méthode virtuelle héritée avec une nouvelle.

pour répondre à votre question mise à jour - je pense que ce n'est pas possbile pour masquer un non virtuelle constructeur avec la surcharge dans un directement dérivée de la classe, mais j'ai essayé les succès:

TComputer = class(TObject)
public
  constructor Create(Teapot: string='');
end;

TIndermediateComputer = class(TComputer)
protected
  // hide the constructor
  constructor Create;
end;

TCellPhone = class(TIndermediateComputer)
public
   constructor Create(Cup: Integer); overload; virtual;
   constructor Create(Cup: Integer; Teapot: string); overload; virtual;
end;
6
répondu splash 2010-10-08 13:44:27

vous ne pouvez pas cacher le constructeur de la classe parent à moins qu'il ne soit déclaré virtuel ou dynamique. Vous pouvez toutefois l'empêcher d'être appelé à partir de la classe enfant. Considérez votre exemple:

TComputer = class(TObject)
public
   constructor Create(Teapot: string='');
end;

TCellPhone = class(TComputer)
public
   constructor Create(Cup: Integer); overload; virtual;
   constructor Create(Cup: Integer; Teapot: string); overload; virtual;
end;

TComputer.Create sera toujours visible à partir de TCellPhone . Vous pouvez empêcher TComputer.Create d'être appelé par inadvertance en déclarant un TCellPhone.Create avec la même signature.

TCellPhone = class(TComputer)
public
   constructor Create(Teapot: string='');
   constructor Create(Cup: Integer); overload; virtual;
   constructor Create(Cup: Integer; Teapot: string); overload; virtual;
end;

, Puis aussi longtemps que vous n'avez pas un appel à inherited dans le corps de TCellPhone.Create(Teapot: string='') vous pouvez empêcher TComputer.Create d'être appelé dans TCellPhone et ses descendants. Ce qui suit:

TCellphone.Create;
TCellphone.Create('MyPhone');

résoudra la mise en œuvre de TCellPhone.

en outre:

TiPhone = class(TCellPhone)
    constructor Create;
end;

constructor TiPhone.Create;
begin
  inherited;
end;

invoquera TCellPhone.Create et non TComputer.Create .

4
répondu Kenneth Cochran 2010-10-08 04:39:52

au lieu de seulement soulever une exception" N'utilisez pas "dans les constructeurs invalides dépassés, envisagez de les marquer déprécié dans la classe où ils deviennent invalides. Cela devrait produire de beaux avertissements de compilateur lorsque ces constructeurs invalides sont utilisés par erreur.

TCellPhone = class(TComputer)
   constructor Create(PowerCord: TPowerCord=nil); deprecated;
   constructor Create(sim: TSimChip; UnlockCode: Integer); //calls inherited Create(nil)

de plus, utilisez la commande outrepasser ou réintroduire au besoin.

3
répondu Marjan Venema 2010-10-06 18:48:54

Vous voulez réintroduire le constructeur:

TiPhone = class(TCellPhone)
    constructor Create(sim: TSimChip); reintroduce;

Voir TComponent.Create dans le code source Delphi pour un exemple du monde réel de cette.

1
répondu Craig Stuntz 2010-10-06 15:53:33

je sais que c'est 5 ans vieux sujet, mais encore il peut aider quelqu'un. La seule façon de cacher le constructeur de l'ancêtre est de renommer l'une des deux méthodes Create en quelque chose d'autre et de supprimer le besoin de la directive overload . Il semble bizarre, mais c'est le seul moyen. Au moins dans les versions plus anciennes de Delphi. Je ne sais pas si c'est possible maintenant dans les versions XE xxx.

1
répondu Krul 2015-11-30 13:49:45