12

更新:最初に受け入れられた回答では回答されない、より単純な例で質問を根絶しました

次のクラスとその祖先が与えられます。

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;

現在TCellPhone、3つのコンストラクターが表示されています。

  • カップ:整数
  • カップ:整数; ティーポット:文字列
  • ティーポット:文字列=''

TCellPhone祖先コンストラクター(Teapot: string = '')が表示されず、宣言されたコンストラクターのみが残るようにするにはどうすればよいですか?

  • カップ:整数
  • カップ:整数; ティーポット:文字列

:通常、子孫コンストラクターを持つという単純な行為は、祖先を非表示にします。

TCellPhone = class(TComputer)
public
   constructor Create(Cup: Integer); virtual;
end;
  • カップ:整数

また、祖先コンストラクターと子孫の両方を保持したい場合は、子孫をoverload:としてマークします。

TCellPhone = class(TComputer)
public
   constructor Create(Cup: Integer); overload; virtual;
end;
  • カップ:整数
  • ティーポット:文字列=''

この質問のサンプルコードでは、Delphiが私のoverloadキーワードを間違えています。

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

それを考える:

  • コンストラクターを祖先でオーバーロードしたい、
  • 本当に兄弟でオーバーロードしたいとき

祖先コンストラクターを非表示にするにはどうすればよいですか?

注:現在定義されているDelphi言語を使用して、祖先の非仮想コンストラクターを非表示にすることは不可能な場合があります。「不可能」は有効な答えです。


試行された回答(失敗)

子孫コンストラクターに次のマークを付けてreintroduceました(機能するまでキーワードをランダムに追加するモードにフォールバックします):

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

しかし、それは機能しませんでした。3つのコンストラクターはすべて表示されたままです。:(


元の質問

コンストラクターが見たくないクラスの子孫であるオブジェクトがあります。

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)

注:これは架空の例です。現実の世界と同様に、祖先オブジェクトは既存のコードを壊さずに変更することはできません。

今、誰かが使用しているとき、私は彼らがコンストラクターを見るTiPhoneことができることさえ望んでいません:TEniac

iphone := TiPhone.Create(powerCord);

さらに悪いことに、彼らがそのコンストラクターを呼び出すと、私のコンストラクターを完全に見逃し、その間にすべてが行われます。間違ったコンストラクターを呼び出すのは非常に簡単です。それらはすべてIDEコード補完に表示され、コンパイルされます。

TiPhone.Create;

そして、それらは完全に無効なオブジェクトを取得します。

TCellPhoneこれらのコンストラクターで例外をスローするように変更できます。

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

しかし、開発者は、顧客がいつかエラーを見つけて数十億ドルの罰金を科すまで、間違ったコンストラクターを呼び出していることに気づきません。実際、私はどこでも間違ったコンストラクターを呼び出そうとしていますが、Delphiに教えてもらう方法がわかりません!

4

6 に答える 6

8

私が正しく覚えていれば、仮想メソッドreintroduceに役立つはずです。

reintroduceディレクティブは、以前に宣言された仮想メソッドを非表示にすることに関するコンパイラの警告を抑制します。継承された仮想メソッドを新しいもので非表示にする場合は、reintroduceを使用します。

更新された質問に答えるために-直接派生クラスでオーバーロードを使用して非仮想コンストラクターを非表示にすることはできないと思いますが、次のことを正常に試しました。

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;
于 2010-10-06T15:52:44.497 に答える
7

Delphiで派生クラスを作成するために、祖先に導入されたコンストラクターにアクセスできないようにすることは不可能です。これは、いつでも実行できるためです。

type
  TComputerClass = class of TComputer;

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

派生クラスのコードでできることは、派生クラスのインスタンスを作成するためにTComputer.Createコンストラクターを呼び出すことを妨げることはできません。

あなたができる最善のことは:

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;

その場合、上記のコードは少なくともTCellPhone.Create(Teapot: string='')代わりに呼び出しますTComputer.Create(Teapot: string='')

于 2010-11-02T05:00:43.097 に答える
5

オーバーライドされた無効なコンストラクターで「使用しない」例外を発生させるだけでなく、無効になるクラスで非推奨としてマークすることを検討してください。これらの無効なコンストラクターが誤って使用された場合、それは素晴らしいコンパイラー警告を生成するはずです。

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

さらに、必要に応じてオーバーライドまたは再導入を使用します。

于 2010-10-06T18:43:15.603 に答える
4

仮想または動的に宣言されていない限り、親クラスのコンストラクターを非表示にすることはできません。ただし、子クラスから呼び出されないようにすることはできます。あなたの例を考えてみましょう:

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から常に表示されTCellPhoneます。同じ署名でをTComputer.Create宣言することにより、誤って呼び出されるのを防ぐことができます。TCellPhone.Create

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

inheritedそうすれば、あなたの体に呼びかけがない限り、あなたとその子孫に呼びかけられるのTCellPhone.Create(Teapot: string='')を防ぐことができます。以下:TComputer.CreateTCellPhone

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

TCellPhoneの実装に解決されます。

さらに:

TiPhone = class(TCellPhone)
    constructor Create;
end;

constructor TiPhone.Create;
begin
  inherited;
end;

呼び出すTCellPhone.Createのではなく、呼び出しTComputer.Createます。

于 2010-10-08T04:39:52.467 に答える
1

コンストラクターを再導入したい:

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

TComponent.Createこの実際の例については、Delphiのソースコードを参照してください。

于 2010-10-06T15:53:33.267 に答える
1

これは5年前のトピックですが、それでも誰かに役立つ可能性があります。祖先のコンストラクターを非表示にする唯一の方法は、2つのCreateメソッドの1つを別の名前に変更し、オーバーロードディレクティブの必要性を取り除くことです。奇妙に見えますが、それが唯一の方法です。少なくとも古いバージョンのDelphiでは。XExxxバージョンで今それが可能かどうかはわかりません。

于 2015-11-30T13:49:45.420 に答える