Domanda

Aggiornamento: ha sventrato la domanda con un esempio più semplice, a cui non è stata data risposta dalla risposta originariamente accettata

Data la seguente classe e il suo antenato:

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;

Proprio adesso TCellPhone ha 3 costruttori visibili:

  • Tazza:Numero intero
  • Tazza:Numero intero;Teiera:corda
  • Teiera:stringa = ''

Cosa devo fare? TCellPhone in modo che il costruttore antenato (Teapot: string = '') non è visibile, lasciando solo i costruttori dichiarati:

  • Tazza:Numero intero
  • Tazza:Numero intero;Teiera:corda

Nota:Di solito il semplice atto di avendo un costruttore discendente nasconde l'antenato:

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

E se tu ricercato Per mantenere sia il costruttore antenato che il discendente, segneresti il ​​discendente come un overload:

TCellPhone = class(TComputer)
public
   constructor Create(Cup: Integer); overload; virtual;
end;
  • Tazza:Numero intero
  • Teiera:stringa = ''

Nel codice di esempio di questa domanda, Delphi sbaglia my overload parole chiave:

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

pensare che:

  • voglio sovraccaricare i miei costruttori con il antenato,
  • quando davvero voglio sovraccaricarlo con il fratello

Come posso nascondere il costruttore antenato?

Nota: Potrebbe essere impossibile nascondere il costruttore antenato, non virtuale, utilizzando il linguaggio Delphi come è attualmente definito. "Non possibile" è una risposta valida.


Tentativo di risposta (non riuscito)

io provato contrassegnando i costruttori discendenti con reintroduce (ritornando alla mia modalità di aggiunta casuale di parole chiave finché non funziona):

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

Ma non ha funzionato, tutti e tre i costruttori sono ancora visibili.:(


Domanda originale

ho un oggetto che discende da una classe i cui costruttori non vogliono vedere:

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)

Nota: Questo è un esempio ipotetico.Come nel mondo reale, gli oggetti antenati non possono essere modificati senza infrangere il codice esistente.

Ora, quando qualcuno lo usa TiPhone non voglio nemmeno che siano in grado di farlo Vedere il costruttore da TEniac:

iphone := TiPhone.Create(powerCord);

Ancora peggio:se chiamano quel costruttore, perdono completamente il mio costruttore e tutto ciò che viene fatto nel mezzo.È abbastanza facile chiamare il costruttore sbagliato, tutti sono visibili nel completamento del codice IDE e compileranno:

TiPhone.Create;

e ottengono un oggetto completamente non valido.

potrei cambiare TCellPhone per lanciare un'eccezione in quei costruttori:

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

Ma gli sviluppatori non si renderanno conto che stanno chiamando il costruttore sbagliato finché un giorno il cliente non troverà l'errore e ci multerà per miliardi di dollari.In effetti, lo sono provando per trovare ovunque chiamo il costruttore sbagliato, ma non riesco a capire come farmelo dire da Delphi!

È stato utile?

Soluzione

È impossibile rendere inaccessibile un costruttore introdotto in un antenato per la creazione di una classe derivata in Delphi perché puoi sempre farlo:

type
  TComputerClass = class of TComputer;

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

Niente di ciò che potresti fare nel codice di una classe derivata sarebbe mai in grado di impedire a qualcuno di chiamare il costruttore TComputer.Create per creare un'istanza della classe derivata.

La cosa migliore che potresti fare è:

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 tal caso il codice sopra almeno chiamerebbe TCellPhone.Create(Teapot: string='') invece di TComputer.Create(Teapot: string='')

Altri suggerimenti

Se ricordo bene, allora reintroduce dovrebbe aiutare per virtuale metodi.

IL reintrodurre La direttiva sopprime gli avvisi del compilatore relativi all'occultamento dei metodi virtuali precedentemente dichiarati.Utilizzare reintrodurre quando si desidera nascondere un metodo virtuale ereditato con uno nuovo.

Per rispondere alla tua domanda aggiornata: penso che non sia possibile nascondere a non virtuale costruttore con sovraccarico in una classe derivata direttamente, ma ho provato con successo quanto segue:

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;

Non puoi nascondere il costruttore della classe genitore a meno che non sia stato dichiarato virtuale o dinamico.Puoi tuttavia impedire che venga chiamato dalla classe figlia.Considera il tuo esempio:

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 sarà sempre visibile da TCellPhone.Puoi prevenire TComputer.Create dall'essere chiamato inavvertitamente dichiarando a TCellPhone.Create con la stessa firma.

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

Allora finché non hai una chiamata inherited nel corpo di TCellPhone.Create(Teapot: string='') puoi prevenire TComputer.Create dall'essere chiamato TCellPhone e i suoi discendenti.Il seguente:

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

Risolverà l'implementazione di TCellPhone.

Inoltre:

TiPhone = class(TCellPhone)
    constructor Create;
end;

constructor TiPhone.Create;
begin
  inherited;
end;

Invocherà TCellPhone.Create e non TComputer.Create.

Invece di sollevare solo un'eccezione "Non utilizzare" nei costruttori non validi sovrascritti, valuta la possibilità di contrassegnarli deprecato nella classe in cui diventano invalidi.Ciò dovrebbe produrre avvisi piacevoli del compilatore quando questi costruttori non validi vengono utilizzati in modo errato.

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

Inoltre, utilizzare l'override o la reintroduzione secondo necessità.

Vuoi reintrodurre il costruttore:

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

Vedere TComponent.Create nel codice sorgente Delphi per un esempio reale di ciò.

So che questo è un argomento vecchio di 5 anni, ma potrebbe comunque aiutare qualcuno.L'unico modo per nascondere il costruttore dell'antenato è rinominare uno dei due metodi Create in qualcos'altro ed eliminare la necessità di sovraccarico direttiva.Sembra strano ma è l'unico modo.Almeno nelle versioni precedenti di Delphi.Non so se sia possibile ora nelle versioni XE xxx.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top