web-dev-qa-db-fra.com

Méthode abstraite dans une classe non abstraite

Je veux connaître la raison derrière la conception de restreindre les méthodes abstraites dans la classe non abstraite (en C #).

Je comprends que l'instance de classe n'aura pas la définition et donc ils ne seront pas appelables, mais lorsque des méthodes statiques sont définies, elles sont également exclues de l'instance. Pourquoi les méthodes abstraites ne sont-elles pas traitées de cette façon, pour une raison spécifique?

Ils peuvent être autorisés dans une classe concrète et la classe dérivée peut être forcée d'implémenter des méthodes, c'est essentiellement ce qui est fait dans le cas de méthodes abstraites dans une classe abstraite.

40
Ashish Jain

Tout d'abord, je pense que ce que vous demandez n'a pas de sens logique. Si vous avez la méthode abstract, cela signifie essentiellement que la méthode n'est pas terminée (comme l'a souligné @ChrisSinclair). Mais cela signifie également que la classe entière n'est pas terminée, elle doit donc également être abstract.

Ou une autre façon de le dire: si vous aviez la méthode abstract sur une classe qui n'était pas abstract, cela signifierait que vous aviez une méthode qui ne peut pas être appelée. Mais cela signifie que la méthode n'est pas utile, vous pouvez la supprimer et tout fonctionnerait de la même manière.

Maintenant, je vais essayer d'être plus concret en utilisant un exemple: imaginez le code suivant:

Animal[] Zoo = new Animal[] { new Monkey(), new Fish(), new Animal() };

foreach (Animal animal in Zoo)
    animal.MakeSound();

Ici, Animal est la classe de base non_abstract (c'est pourquoi je peux la mettre directement dans le tableau), Monkey et Fish sont dérivées de Animal et MakeSound() est la méthode abstract. Que doit faire ce code? Vous ne l'avez pas dit clairement, mais je peux imaginer peu d'options:

  1. Vous ne pouvez pas appeler MakeSound() sur une variable de type Animal, vous ne pouvez l'appeler qu'en utilisant une variable de type comme l'une des classes dérivées, il s'agit donc d'une erreur de compilation.

    Ce n'est pas une bonne solution, car tout l'intérêt de abstract est de pouvoir traiter les instances de classes dérivées comme la classe de base, tout en obtenant un comportement spécifique à la classe dérivée. Si vous le souhaitez, placez simplement une méthode normale (pas de abstract, virtual ou override) dans chaque classe dérivée et ne faites rien avec la classe de base.

  2. Vous ne pouvez pas appeler MakeSound() sur un objet dont le type d'exécution est en fait Animal, il s'agit donc d'une erreur d'exécution (une exception).

    Ce n'est pas non plus une bonne solution. C # est un langage typé statiquement et il essaie donc de détecter des erreurs comme "vous ne pouvez pas appeler cette méthode" au moment de la compilation (avec des exceptions évidentes comme la réflexion et dynamic), donc en faire une erreur d'exécution ne serait pas " ne correspond pas au reste de la langue. En outre, vous pouvez le faire facilement en créant une méthode virtual dans la classe de base qui lève une exception.

Pour résumer, vous voulez quelque chose qui n'a pas beaucoup de sens, qui a une mauvaise conception (classe de base qui se comporte différemment de ses classes dérivées) et qui peut être contourné assez facilement. Ce sont tous des chants d'une fonctionnalité qui devraient pas être implémentés.

44
svick

Donc, vous voulez autoriser

class C { abstract void M(); }

compiler. Supposons que ce soit le cas. Que voulez-vous alors arriver quand quelqu'un fait

new C().M();

? Vous voulez une erreur de temps d'exécution? Eh bien, en général, C # préfère les erreurs au moment de la compilation aux erreurs au moment de l'exécution. Si vous n'aimez pas cette philosophie, il existe d'autres langues disponibles ...

12
AakashM

Je pense que vous avez répondu à votre propre question, une méthode abstraite n'est pas définie au départ. Par conséquent, la classe ne peut pas être instanciée. Vous dites qu'elle doit l'ignorer, mais par définition, lorsque vous ajoutez une méthode abstraite, vous dites que "chaque classe créée à partir de cela doit implémenter cette {méthode abstraite}", donc la classe dans laquelle vous définissez la classe abstraite doit également être abstraite car la la méthode abstraite n'est pas encore définie à ce stade.

4
Dale Burrell

La classe abstraite peut contenir un membre abstrait. Il y a la seule déclaration de méthode si une méthode a un mot-clé abstrait que nous ne pouvons pas implémenter dans la même classe. La classe abstraite est donc incomplète. C'est pourquoi l'objet n'est pas créé pour une classe abstraite.

La classe non abstraite ne peut pas contenir de membre abstrait.

Exemple:

namespace InterviewPreparation
{
   public abstract class baseclass
    {
        public abstract void method1(); //abstract method
        public abstract void method2(); //abstract method
        public void method3() { }  //Non- abstract method----->It is necessary to implement here.
    }
    class childclass : baseclass
    {
        public override void method1() { }
        public override void method2() { }
    }
    public class Program    //Non Abstract Class
    {
        public static void Main()
        {
            baseclass b = new childclass(); //create instance
            b.method1();
            b.method2();
            b.method3();
        }
    }

}
2
vikas Chaturvedi

Vous pouvez obtenir ce que vous voulez en utilisant des méthodes "virtuelles" mais l'utilisation de méthodes virtuelles peut entraîner davantage d'erreurs de logique métier d'exécution car un développement n'est pas "forcé" d'implémenter la logique dans la classe enfant.

Je pense qu'il y a un point valable ici. Une méthode abstraite est la solution parfaite car elle "imposerait" l'exigence de définir le corps de la méthode chez les enfants.

Je suis tombé sur de nombreuses situations où la classe parente devait (ou il serait plus efficace) implémenter une logique mais "Seuls" les enfants pouvaient implémenter le reste de la logique "

Donc, si l'occasion était là, je mélangerais volontiers des méthodes abstraites avec des méthodes complètes.

@AakashM, j'apprécie que C # préfère les erreurs de temps de compilation. Moi aussi. Et tout le monde aussi. Il s'agit de penser hors de la boîte.

Et soutenir cela n'affectera pas cela.

Pensons hors de la boîte ici, plutôt que de dire "hourra" aux décisions de grand garçon.

Le compilateur C # peut détecter et refuser à quelqu'un d'utiliser directement une classe abstraite car il utilise le mot clé "abstrait".

C # sait également forcer toute classe enfant à implémenter des méthodes abstraites. Comment? en raison de l'utilisation du mot-clé "abstrait".

C'est assez simple à comprendre pour quiconque a étudié les composants internes d'un langage de programmation.

Alors, pourquoi C # ne peut-il pas détecter un mot-clé "abstrait" à côté d'une méthode dans une classe normale et le gérer au moment de la compilation.

La raison en est qu'il faut "retravailler" et l'effort ne vaut pas la peine de soutenir la petite demande.

Surtout dans une industrie qui manque de gens qui pensent hors des boîtes que les grands garçons leur ont données.

1
Menol

Les réponses ci-dessus sont donc correctes: avoir des méthodes abstraites rend la classe intrinsèquement abstraite. Si vous ne pouvez pas instancier une partie d'une classe, vous ne pouvez pas instancier la classe elle-même. Cependant, les réponses ci-dessus n'ont pas vraiment discuté de vos options ici.

Tout d'abord, c'est principalement un problème pour les méthodes statiques public. Si les méthodes ne sont pas destinées à être publiques, vous pouvez avoir des méthodes non abstraites protégées, qui sont autorisées dans une déclaration de classe abstraite. Ainsi, vous pouvez simplement déplacer ces méthodes statiques vers une classe statique distincte sans trop de problème.

Comme alternative, vous pouvez conserver ces méthodes dans la classe, mais au lieu d'avoir des méthodes abstraites, déclarez une interface. Essentiellement, vous avez un problème d'héritage multiple car vous voulez que la classe dérivée hérite de deux objets conceptuellement différents: un parent non abstrait avec des membres statiques publics et un parent abstrait avec des méthodes abstraites. Contrairement à certains autres frameworks, C # permet l'héritage multiple. Au lieu de cela, C # propose une déclaration d'interface formelle destinée à remplir cet objectif. De plus, tout l'intérêt des méthodes abstraites est justement d'imposer une certaine interface conceptuelle.

0
Matthew

On ne sait toujours pas pourquoi vous le souhaitez, mais une autre approche pourrait être de forcer les classes dérivées à fournir une instance déléguée. Quelque chose comme ça

class MyConcreteClass
{
  readonly Func<int, DateTime, string> methodImpl;

  // constructor requires a delegate instance
  public MyConcreteClass(Func<int, DateTime, string> methodImpl)
  {
    if (methodImpl == null)
      throw new ArgumentNullException();

    this.methodImpl = methodImpl;
  }

  ...
}

(La signature string MethodImpl(int, DateTime) n'est qu'un exemple, bien sûr.)

Sinon, je peux recommander les autres réponses pour expliquer pourquoi votre souhait n'est probablement pas quelque chose qui rendrait le monde meilleur.

0
Jeppe Stig Nielsen