7

今日最近Stackoverflowで私はそれを学びました:

私はそれをすべて理解しようとしてきたので、コンストラクターを扱う私の主な質問をサポートする、別の非常に具体的な質問があります。


更新:質問全体を置き換えました:

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つのコンストラクターを使用できます。

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

質問:なぜconstructor(Teapot: string='')隠されていないのですか?


今私は3番目の子孫を追加しました:

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;

TiPhone = class(TCellPhone)
public
   constructor Create(Cup: Integer); override;
end;

TiPhone 4つのコンストラクターを作成する場合は、次のようにします。

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

なぜコンストラクターが4つあるのですか?既存の3つのうちの1つを上書きしました。編集:これはコードインサイトのバグである可能性があり、4つ表示されますが、2つが同じである場合、どうすれば呼び出すことができますか?


元のコードを再度使用する:

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;

TCellPhone3つのコンストラクターがあることはすでに知られています。

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

TCellPhoneの宣言を変更して祖先コンストラクターを非表示にするにはどうすればよいですか?たとえば、次のようになります。

TNokia = class(TCellPhone)
end;

コンストラクターは2つだけです。

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

ここで、がreintroduce非仮想の祖先を非表示にするために使用される場合について説明します。前のケースでは、TiPhoneコンストラクターが4つあります(理想的には2つだけでTComputer、祖先が何らかの形で隠されています)。しかし、私が修正できない場合でも、私は1つだけを持つようにTComputer変更することができます:TiPhone

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;

TiPhone = class(TCellPhone)
public
    constructor Create(Cup: Integer); reintroduce;
end;

現在TiPhone、コンストラクターは1つだけです。

  • カップ:整数

Reintroduceは通常、仮想祖先の非表示に関する警告を抑制するためにのみ使用されます。この場合:

Create(Teapot: string = '')

仮想ではありません-それでも、reintroduceを使用して非表示にすることができます。


しかし、私が別のオーバーロードを追加した場合TiPhone

TiPhone = class(TCellPhone)
public
   constructor Create(Cup: Integer); reintroduce; overload;
   constructor Create(Handle: String); overload;
end;

その後、突然(以前は隠されていた)祖先が戻ってきます:

  • TiPhone.Create(7);
  • TiPhone.Create('ピンク');
  • TiPhone.Create(7、'ピンク');
  • TiPhone.Create();

ご覧のとおり、私はの論理を理解するのに苦労しています

  • 何かが隠されているとき
  • 何かを隠す方法
  • 何かが表示されたとき
  • 何かを示す方法
4

4 に答える 4

7

reintroduce祖先クラスのメソッドを非表示にするために使用することはありません。これを行うには、祖先クラスのメソッドと同じ名前のメソッドを、オーバーライドしたりオーバーロードしたりせずに宣言するだけです。祖先クラスのメソッド(非表示になっているメソッド)が仮想である場合にDelphiが発生する警告reintroduceを抑制するために使用します。

子孫のメソッドが祖先のメソッドをオーバーライドする場合、それは隠れていません。祖先のメソッドへの呼び出しは、代わりに子孫のメソッドにルーティングされます。

子孫のメソッドが祖先のメソッドをオーバーロードする場合、それも隠れていません。どちらもお電話いただけます。

于 2010-10-06T21:58:01.380 に答える
1

仮想ではないメソッドをオーバーライドすることはできないため、何も隠していません。そのため、警告はありません。

編集:「あなたは何も隠していない」という私の主張を撤回します。ここに隠れることの意味がよくわからないと思います。私はこれについて質問をしまし

更新:私が得た答え
に基づいて、私の答えを言い換えたいと思います:仮想として宣言されていないので、あなたはすでにそのメソッドを子孫クラスから隠しています。したがって、コンストラクターは、まったく表示されていないものを非表示にすることはできません。したがって、コンパイラーの警告はありません。TComputer.ConstructorTCellPhone

于 2010-10-06T21:58:44.857 に答える
1

そうですね、オーバーロードするクラスでもメソッド/コンストラクターを非表示にすることはできないようです。TComputerからコンストラクターを隠すために、この小さな「ハック」が付属しました

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

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

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

  TiPhone = class(TCellPhone)
  public
    constructor Create(Cup: Integer); reintroduce; virtual;
  end;

その例では、TiPhoneで使用できるコンストラクターは1つだけです。ただし、ポリモーフィズムは破られます(TCellPhoneから2番目のコンストラクターを非表示にするために支払う代償)。ポリモーフィズムを壊さずにそうする方法を誰かが見つけたかどうか知りたいです。

また、コードインサイトが4つの「コンストラクター」を示​​しているからではなく、実際に4つ使用できることに注意してください。コンストラクターの「オーバーライド」ごとに、コードインサイトに1つのコンストラクターがリストされることに注意しました。ただし、その状況では、子孫コンストラクターのみが呼び出されます。

この例では、TCellPhoneの2番目のコンストラクターがTHackComputerからのものを非表示にしていると文句を言いますが、THackComputerからのものがTCellPhoneでオーバーライドされるため、誤検知だと思います。(これはあまり一般的なコード構造ではないため、コーナーケースのバグだと思います)

于 2010-10-07T17:27:38.367 に答える
0

これをロブ・ケネディの答えへのコメントとして入れたかったのですが、できないのでここに行きます。

その間、祖先コンストラクターを非表示にすることについての警告はありません。

あなたがしないという理由だけで。

祖先を隠しているのに、なぜ警告がないのですか?再紹介はありません。

繰り返しますが、単に何も隠さないからです。

あなたは何も隠さなかったという証拠を見ました。あなたが調べたのは、利用可能な3つのコンストラクターです。

なぜ再導入を使用して祖先を隠すことができるのですか?

Robが述べたように、reintroduceは単にコンパイラのヒント/警告を抑制しているだけです。その言葉の背後にある本当の専門性はありません。したがって、reintroduceで何も非表示にすることはありません。

隠す方法について考えたいのですが、Sertacに同意します。まず、この場合の隠れの定義を知っておく必要があります。

編集:あなたが言及した投稿を読んだだけです。あなたは概念を誤解していると思います。ここに私の簡単な説明があります。

reintroduceは、祖先コンストラクターを非表示にするために使用されます

その投稿の答えはそれを示していません。祖先のコンストラクターを実際に隠しているのは、祖先と同じパラメーターを持つ子孫のNEWCONSTRUCTORです。キーワードreintroduceは、単にコンパイラの警告を抑制することです。

reintroduceは、祖先コンストラクターを表示するために使用されます

その投稿の回答では、祖先のコンストラクターを引き続き使用できるようにするのはOVERLOADキーワードです。

以下のコメントでのイアンの質問に対する追加:

混乱を解決するための最初のステップは、実際の問題を特定することです。あなたの投稿を注意深く調べると、あなたが実際に2つの問題を1つのステップで解決したかったことが明らかになります。2つの問題は次のとおりです。

  1. 特定の名前の祖先コンストラクターを非表示にするには
  2. 子孫に同じ特定の名前の複数のコンストラクターを含めること。

それらは単純な問題のように見えるかもしれませんが、注意深く調べると、それらの性質が互いに正反対であることがすぐに頭に浮かびます。問題1はメソッド/コンストラクターを非表示にし、問題2は1つだけでなく複数のメソッド/コンストラクターを表示したい。したがって、それらを1つのステップで混合すると、それらは確実に互いに打ち消し合います。彼らがあなたに頭痛を与えるのも不思議ではありません...:)

これら2つの問題を解決するための基本的なルールは、1つのステップでそれらを混合しないことです。これは、問題1を解決するために中間クラスが必要であり、その中間クラスの子孫でオーバーロードを実行することを意味します。このようなもの:

type
  TComputer = class(TObject)
  private
    FCaller: TConstructorCaller;
  public
     constructor Create(Teapot: string=''); virtual;

     property Caller: TConstructorCaller read FCaller;
  end;

  TBaseCellphone=class(TComputer)
    constructor Create(Cup: Integer); virtual;
  end;

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

  TiPhone = class(TCellPhone)
  public
    constructor Create(Cup: Integer); reintroduce; overload;
    constructor Create(Handle: String); reintroduce; overload;
  end;

上記のコードから、TBaseCellphoneは中間クラスです。このシナリオでは、そのタスクは、コンストラクターCreateofTComputerを非表示にすることだけです。ここではoverloadキーワードを使用しないでください。使用すると、非表示がキャンセルされます。非表示が完了したら、その子孫でオーバーロードキーワードを自由にスパムして、同じ名前の複数のコンストラクターを取得できます。

確認すると、次のコードがコンパイルされないことがわかります。

   TCellPhone.Create('My Teapot');
于 2010-10-07T09:30:43.080 に答える