9
votes

Comment forcer les classes descendantes à mettre en œuvre une fonction abstraite?

J'ai une classe abstraite de base dans laquelle j'ai défini une fonction abstraite virtuelle.

GetClass('TMyDescendantClass').Create


3 commentaires

@RBA: Je ne connais pas vraiment les interfaces, mais je pense qu'une interface me forcerait à définir "mysculose" pour Tmybaseclass, au lieu de forcer qui écrit des descendants de TmyBaseclass pour la définir. C'est vrai?


Les méthodes abstraites virtuelles sont la solution. Vous verrez des avertissements si vous instaniez un objet avec des méthodes abstraites non programmées. L'utilisation d'une interface ajoutera probablement simplement une complication. Même si vous ne voyez pas les avertissements, votre programme ne fonctionnera pas et échouera avec une erreur d'exécution si quelqu'un ne parvient pas à mettre en œuvre les méthodes abstraites. Puisque vous n'allez pas expédier votre code sans l'exécuter en premier, il n'y a rien à craindre.


Cela pourrait devenir ennuyeux s'ils veulent que leur classe de béton hérite de leur propre classe de base abstraite. (C'est-à-dire TCONCCLASS -> TabsClass -> TmyBaseclass)


4 Réponses :


3
votes

Une solution quelque peu laidly déclencherait une exception forte> d'exécution forte> tôt, excluant toute utilisation de leurs classes descendantes à moins qu'elles ont fait la mise en œuvre:

  TmpClass := GetClass('TMyDescendantClass');
  if not TmpClass.InheritsFrom( TMyBaseForm ) then 
     raise EPluginSystemMisconfiguration.Create(.....); 
  MyPluginFormClass := TMyBaseForm( TmpClass ); 
  VerifyPluginClass( MyPluginFormClass ); // immediately raises exception if class is not valid
  MyPluginForm := MyPluginFormClass.create(Application);


10 commentaires

Souhaitez-vous y inclure cela dans votre code? Je sais que je ne le ferais pas. Pire que laide, c'est épouvantable. 5 UPVOTES! Étonnant. Je souhaite que les gens voteraient en fonction de la qualité des postes plutôt que de la sympathie et de la pitié.


Eh bien, si ce serait ma décision, je dirais simplement que l'échec des autres à mettre en œuvre correctement une classe est leur échec, n'est pas la mienne. Cependant, si le patron dirait «le réparer à tout prix et le faire à vos côtés» - alors je ferais un choix entre «laid hack» et démissionner. Je suppose que chaque programmeur pratique disposait de cas lorsqu'il est retourné aux Hacks laids, ne trouvant aucun moyen de mettre en œuvre une solution élégante et de la haute couture.


Je pense que je démissionnerais!


Cette solution est laid - et c'est ce que j'ai commencé avec. Ce n'est pas non plus vraiment une solution, cela ne manque pas de temps de compilation. Ce n'est pas non plus des tests d'unité d'exécution. Toujours cela donne au moins quelque chose. Le générique "Supprimez la classe problématique et écrivez votre programme de manière différente qui ne nécessiterait pas que la classe du tout" n'est pas non plus une solution, il est trop abstrait pour être un.


Ce choix appartient au Topicstarter. Nous avons tous nos seuils personnels quand et où cela devient "trop". Mais ils sont exactement ça - personnel.


Vous n'avez pas suggéré de supprimer la classe problématique, alors ne savez pas ce que cela fait référence.


La deuxième partie de votre réponse. "Changer la tâche complètement"


Je parlais de cette réponse, pas d'autres. Peut-être que l'astucieux est contraint à un design spécifique, peut-être pas. Aucun de nous n'a jamais connu vraiment. Ce que je ne comprends pas, c'est le vote ici. Était-ce généré par vos plaintes concernant la réception de quelques bowvotes au cours du dernier mois? Cela n'a aucun sens pour qu'une telle idée épouvantable soit si populaire.


Eh bien, ce qui se plaint a peut-être fait de certaines personnes à aller à mon profil et à vérifier mes deux dernières réponses. Qu'ils m'ont donné des upvotes pour une simple sympathie ou leur consternation des bowvotes non fondus, ou ont-ils fait une attention particulière à moi et à mes réponses, mais ils les ont véritablement évoqués sur leurs propres mérites - que je ne peux pas savoir. Je préférerais ce dernier, bien sûr. /// aussi, vivre dans le monde pratique, nous faisons parfois recourir à des hacks laids lors de leur découverte dans une impasse. Donc, si une solution laidée est offerte et franchement et ouvertement marquée comme laide - je le vois plus comme un mal nécessaire qu'un piège.


Personnellement, j'ai une suspicion le cas réel ici prolonge la classe de base avec de nouvelles méthodes abstraites. Ensuite, les impléments de classe dérivés négligent simplement ce changement (était-il même documenté comme un changement de rupture?) Et continuez à compiler leurs anciennes implémentations, faites contre l'ancienne version de la classe de base, qui manquait ces méthodes à l'époque. Simplement spéculer, bien sûr.



2
votes

déclarer une classe contenant des méthodes abstraites n'est pas un problème et aucun avertissement n'est émis ici; Un problème mon apparaît si vous créez une instance d'une classe abstraite et Delphi compilateur émet un avertissement correspondant. Par exemple, xxx

conduit à l'avertissement

[AVERTISSEMENT DCC]: W1020 Construction de la construction de 'TmyDescendantClass' contenant la méthode abstraite 'tmybaseclass.myfunction'


4 commentaires

Cet avertissement peut également être converti en une erreur s'il a le contrôle de ses collègues Delphi Paramètres. Mais il semble ne pas avoir. Et puis ces collègues peuvent simplement interdire cet avertissement.


Dans le scénario réel, les classes sont des formes définies dans des packages dynamiques. Ces classes sont obtenues en appelant la fonction "getclass" (c'est-à-dire getclass ('TmyDescendantClass'). Créer). Ainsi, la création d'instances ne provoque pas d'avertissements.


Si ce détail compte, cela devrait être dans la question. Sinon c'est votre problème et pas le nôtre.


@DavidHeffernan: Vous avez raison, ça compte. J'ai mis à jour la question en ajoutant ce détail.



7
votes

Si vous vous tenez à votre design actuel, vous ne pouvez rien faire au-delà d'attendre une erreur au moment de l'exécution.

Si vous faisiez référence aux classes statiquement, vous verriez des avertissements si vous avez instancié des classes contenant des méthodes abstraites. Mais parce que vous obtenez les classes de manière dynamique, le compilateur ne peut pas vous aider. P>

Ajout d'une interface à la classe ne serait pas très utile. Supposons que vous ayez changé votre classe afin de mettre en œuvre une interface? Vous devriez mettre en œuvre cela dans la classe de base. Comment le feriez-vous? En utilisant des méthodes virtuelles? Vous seriez de retour où vous avez commencé. P>

Supposons que vous puissiez forcer les metteurs de la mise en œuvre de classes dérivées pour mettre en œuvre toutes ces méthodes abstraites. Ce qui les arrête de le faire comme ça comme ça: p>

type
  TMyDescendantClass = class(TMyBaseClass)
  public
    function MyFunction: string; override;
  end;

function TMyDescendantClass.MyFunction: string;
begin
  // TODO: implement this method
end;


0 commentaires

2
votes

Si les classes descendantes sont déclarées telles que scellées, le compilateur soulève des erreurs pour toutes les procédures et fonctions abstraites qui restent malimumées. Donc, ce qui suit augmentera une erreur au moment de la compilation:

TMyBaseClass = class abstract(TForm)
public
  function MyFunction : string; virtual; abstract;
end;

TMyDescendantClass = class sealed(TMyBaseClass);


0 commentaires