Existe-t-il des langages OO qui prennent en charge un mécanisme garantissant qu'une méthode remplacée appellera la base?


12

Je pense que cela pourrait être une fonctionnalité de langue utile et je me demandais si des langues le prenaient déjà en charge.

L'idée est que si vous avez:

class C
  virtual F
     statement1
     statement2

et

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

Il y aurait un mot-clé appliqué à CF () tel que la suppression de la dernière ligne de code ci-dessus provoquerait une erreur de compilation car il dit "Cette méthode peut être surchargée mais l'implémentation ici doit être exécutée quoi qu'il arrive".


Réponses:


14

Oui, ils le font. Il est appelé modèle scandinave d'OO, il est utilisé par exemple dans Simula (l'autre modèle OO qui est largement répandu et pris pour acquis maintenant, est le modèle américain). Dans le modèle scandinave, vous ne remplacez pas, mais fournissez un sous-comportement.

dans la méthode foo de Superclass:

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

dans la méthode de la sous-classe foo:

some-code-in-subclass

Si vous appelez la méthode foo des instances de Superclass, uniquement some-code-beforeet some-code-afterse produit ( INNERne fait rien), mais si vous appelez foo des instances de la sous-classe, c'est le cas some-code-before, some-code-in-subclasspuis some-code-after.


9

Aucune langue que je connais n'appelle la méthode surchargée. En effet, certains langages permettent de surcharger les méthodes qui ne sont pas redéfinissables (comme l'utilisation du newmot clé en C #). Cependant, il existe deux façons d'aborder cela.

La première consiste à créer une méthode non effaçable (par exemple, celle qui n'a pas le virtualmot - clé en C # ou celle qui a le finalmot - clé en Java) qui appelle une méthode remplaçable qui ne peut pas être appelée de l'extérieur de la classe (par exemple protecteden C #, Java ou C ++).

class C
  A
     statement1
     F
     statement3

  protected virtual F
     statement2

et

class D inherits C

  protected override F
     statement4
     C.F()

Les classes surchargées Csont libres de remplacer Fet de modifier son comportement, mais les appelants de l'extérieur de la classe y accèdent uniquement A.

Edit: Comme d'autres l'ont souligné, cela s'appelle le modèle de méthode Template .

La deuxième façon consiste à utiliser un langage qui applique les préconditions et postconditions spécifiées dans la classe de base, comme Eiffel ou C # avec les contrats de code. Cela ne forcera pas l'appel de la classe de base mais la méthode substituée peut être forcée d'exécuter les mêmes instructions. L'utilisation d' aspects peut également aider si le langage permet d'hériter d'aspects.


2
Vous pouvez même modifier la méthode privateen C ++ :) Herb Sutter l'explique ici en détail.
fredoverflow

Le modèle de modèle n'a qu'un inconvénient: vous devez le réimplémenter à chaque fois tout en approfondissant la hiérarchie d'héritage. L'exemple avec Simula est plus élégant et permet toujours un modèle de modèle.
Pavel Voronin

7

Ne fait pas vraiment partie du langage, mais l'analyseur de code statique FindBugs pour Java a une annotation OverrideMustInvokequ'un développeur peut ajouter à une méthode, et qui provoquera une erreur de FindBugs s'il trouve une méthode prioritaire qui n'appelle pas la super implémentation . Il permet même de spécifier si l'appel doit être premier ou dernier dans la méthode prioritaire.


6

Exiger d'appeler une méthode de superclasse est un anti-modèle . S'il n'est pas appliqué au moment de la compilation, il est sujet aux erreurs, c'est pourquoi vous recherchez une construction de langage qui le vérifie.

Il existe un moyen pris en charge dans tous les langages OO: le modèle de méthode de modèle . Ici, vous rendez la méthode superclasse non remplaçable et vous y appelez une méthode surchargeable. La sous-classe peut alors remplacer cette méthode pour ajouter des fonctionnalités:

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

En fonction de l'emplacement de l'appel à la méthode redéfinie, il permet même de déterminer l'ordre d'exécution, qui avec le super appel ordinaire est à volonté de l'implémentateur de la sous-classe.


1

Le schéma le plus proche auquel je pense est celui des événements auto-souscrits. C'est un peu lourd, et pas du tout intuitif pour le codeur, mais atteint l'objectif.

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

    protected event OnF
}

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

    private void F
    {
        ...
    }
}

1
Il s'agit d'un modèle de conception assez courant, parfois avec des remplacements pro et post, par exemple. ViewWillAppear (), ViewDidAppear (). Idéal lorsque vous souhaitez autoriser les sous-classes à étendre (au lieu de modifier) ​​le comportement par défaut.
Kris Van Bael

1

Les "saveurs" de la machine Lisp autorisaient les méthodes de type "avant" "après" et "autour" de la méthode principale héritée.


0

Bien que ce ne soit pas une mauvaise idée en théorie, cela a pour effet secondaire négatif de contraindre mes options lors de la mise en œuvre D. Par exemple, que faire si (pour une raison insondable), il est plus pratique d'appeler l'implémentation de la superclasse à Fpartir d'une autre méthode:

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

Dans votre scénario, j'imagine que le compilateur marquerait l'implémentation de Fin D, même s'il appelle (indirectement) C.F().

Fondamentalement, ce que vous avez décrit est un mécanisme possible pour aider le compilateur à reconnaître quand un contrat sur les classes héritées Cest violé. Mon point est que, bien que ce soit une bonne chose, cela ne devrait pas se faire au détriment de la façon dont je peux implémenter ma sous-classe.


1
-1: être capable de penser à une situation où vous ne voudriez pas utiliser ce n'est pas une réponse à la question "est-ce que n'importe quelle langue le permet".

@GrahamLee: très vrai. Mon but était d'essayer d'expliquer une raison pour laquelle aucun langage (à ma connaissance) n'implémente une telle fonctionnalité. Je suppose que je me suis tellement pris à expliquer cela, que j'ai oublié de mentionner pourquoi je l'expliquais. -1 heureusement accepté. :)
Mac
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.