OO言語は、オーバーライドされたメソッドがベースを呼び出すことを保証するメカニズムをサポートしていますか?


12

これは便利な言語機能である可能性があり、すでにサポートされている言語があるのではないかと考えていました。

あなたが持っている場合のアイデアは次のとおりです。

class C
  virtual F
     statement1
     statement2

そして

class D inherits C
  override F
     statement1
     statement2
     C.F()

上記のコードの最後の行を削除するとコンパイラエラーが発生するようにCF()に適用されるキーワードがあります。「このメソッドはオーバーライドできますが、ここの実装は何でも実行する必要がある」ということです。


回答:


14

はい、彼らはやる。これはOOのスカンジナビアモデルと呼ばれ、たとえばSimulaで使用されています(現在普及している他のOOモデルはアメリカのモデルです)。スカンジナビアモデルでは、オーバーライドするのではなく、サブ動作を提供します。

スーパークラスのメソッドfoo:

some-code-before
INNER // this is the actual Simula keyword
some-code-after

サブクラスのメソッドfoo:

some-code-in-subclass

あなたはスーパークラスのインスタンスメソッドfooを呼び出す場合、のみsome-code-beforesome-code-after(たまたまINNER何もしない)が、あなたはサブクラスインスタンスFOOを呼び出す場合、それはありませんsome-code-beforesome-code-in-subclassそして、その後some-code-after


9

私が知っている言語は、オーバーライドされたメソッドの呼び出しを強制しません。実際、一部の言語では、オーバーライドできないメソッドをオーバーライドできます(newC#でキーワードを使用するなど)。ただし、これにアプローチする方法は2つあります。

1つ目は、クラス外(C#、Java、C ++など)から呼び出すことができないオーバーライド可能なメソッドを呼び出す、オーバーライドできないメソッド(virtualC#のキーワードを持たないメソッドやfinalJava のキーワードを持つメソッドなど)を作成することprotectedです。

class C
  A
     statement1
     F
     statement3

  protected virtual F
     statement2

そして

class D inherits C

  protected override F
     statement4
     C.F()

オーバーライドCするクラスは、自由にオーバーライドしてFその動作を変更できますが、クラスの外部からの呼び出し元はを介してのみアクセスしますA

編集:他の人が指摘したように、これはテンプレートメソッドパターンと呼ばれます

2番目の方法は、EiffelやC#with Code Contractsなど、基本クラスで指定された前提条件と事後条件を強制する言語を使用することです。基本クラスが強制的に呼び出されることはありませんが、オーバーライドされたメソッドは同じステートメントを強制的に実行できます。言語がアスペクトの継承を許可している場合、アスペクトの使用も役立ちます。


2
privateC ++でメソッドをオーバーライドすることもできます:) Herb Sutterがここで詳細に説明します。
fredoverflow

テンプレートパターンには、継承階層を深く掘り下げながら、毎回再実装する必要があるという欠点が1つだけあります。Simulaの例はよりエレガントで、テンプレートパターンを使用できます。
パベル・ボロニン

7

実際には言語の一部ではありませんが、Java用のFindBugs静的コードアナライザーには、OverrideMustInvoke開発者がメソッドに追加できる注釈があり、スーパー実装を呼び出さないオーバーライドメソッドが見つかった場合にFindBugsにエラーを表示させます。オーバーライドメソッドで呼び出しが最初か最後かを指定することもできます。


6

スーパークラスメソッドを呼び出す必要があるのはアンチパターンです。コンパイル時に強制されない場合、エラーが発生しやすいため、それをチェックする言語構造を探しています。

すべてのオブジェクト指向言語でサポートされている方法があります:テンプレートメソッドパターン。ここでは、スーパークラスメソッドをオーバーライド不可にし、その中でオーバーライド可能なメソッドを呼び出します。サブクラスは、このメソッドをオーバーライドして機能を追加できます。

class super {
  public final void doSomething() {
    doSpecialthing();
    doMore();
  }
  public void doSpecialthing() {
  }
}

オーバーライドされたメソッドの呼び出しの場所に応じて、通常のスーパーコールではサブクラスの実装者が自由に実行できる実行順序を決定することもできます。


1

私が考えることができる最も近いパターンは、自己購読イベントです。それは少し面倒で、コーダーにとってまったく直感的ではありませんが、目標を達成します。

class C
{
    public void F()
    {
        ...
        OnF()
    }

    protected event OnF
}

class D : C
{
    public D()
    {
        base.OnF += this.F
    }

    private void F
    {
        ...
    }
}

1
これはかなり一般的なデザインパターンであり、プロとポストの両方のオーバーライドを伴う場合もあります。ViewWillAppear()、ViewDidAppear()。サブクラスが(変更の代わりに)デフォルトの動作を拡張できるようにする場合に理想的です。
クリスヴァンバエル

1

Lispマシンの「フレーバー」では、継承されたメインメソッドのタイプが「前」、「後」、「周辺」のメソッドが許可されていました。


0

理論的には悪い考えではありませんが、を実装するときにオプションを制限するというマイナスの副作用がありますD。たとえば、もし(何らかの計り知れない理由で)ifの場合、F他のメソッドからのスーパークラス実装を呼び出す方が便利です:

class D inherits C
    override F
        statement1
        statement2
        G()
    G
        statement3
        C.F()
        statement4

あなたのシナリオでは、コンパイラは(間接的に)を呼び出しますが、Fin の実装にフラグを立てると思いDますC.F()

基本的に、あなたが説明したのは、継承するクラスの規約にC違反したことをコンパイラが認識できるようにするための可能なメカニズムです。私のポイントは、それは素晴らしいことですが、サブクラスの実装方法を制限することを犠牲にしてはならないということです。


1
-1:使用したくない状況を考えることができるということは、「それを許可する言語はありますか」という質問に対する答えではありません。

@GrahamLee:非常に本当です。私のポイントは、(私が知っている)どの言語もそのような機能を実装していない理由を説明することでした。私はそれを説明するのに夢中になったと思うので、なぜ私がそれを説明していたの言及するのを忘れました。-1は喜んで受け入れました。:)
Mac
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.