10
votes

C # - Interfaces explicites avec héritage?

sortie:
B-> Bonjour! d'explicite.

ne devrait-il pas être:?
A-> Bonjour! d'explicite.

Pourquoi ne peut-il pas lancer explicitement (ihello) un appel ihello.hello () de la classe A? xxx


0 commentaires

4 Réponses :


21
votes

Non, ça ne devrait pas.

L'appel à Hello est équivalent à celui de commenté - l'itinéraire pour obtenir un ihello n'a pas d'importance (sauf s'il ne nécessite que la vérification ou la conversion d'exécution ); Le type de compilation est juste ihello de chaque sens et le mappage d'interface est identique mais vous y arrivez.

Lorsqu'une interface est explicitement implémentée plus d'une fois dans la hiérarchie de type, la mise en œuvre du type le plus dérivé est utilisée. (Lorsque cela est appelé via l'interface.)

à partir de la section 13.4.4 de la spécification C # 3.0:

Cartographie de l'interface pour une classe ou structure C localise une implémentation pour chaque membre de chaque interface spécifié dans la liste des classes de base de C. La mise en œuvre d'un particulier Membre d'interface I.M, où je suis le interface dans laquelle le membre m est déclaré, est déterminé en examinant chaque classe ou structure S, commençant par C et répéter pour chaque successive classe de base de c, jusqu'à ce qu'un match soit Situé:

  • si s contient une déclaration d'un membre d'interface explicite Mise en œuvre qui correspond à i et m, alors ce membre est la mise en œuvre de I.m.
  • Sinon, si S contient une déclaration d'un membre du public non statique qui correspond à M, ce membre est la mise en œuvre de la messagerie instantanée IM si plusieurs matchs membres, il est indéterminé à quel membre est la mise en œuvre de la messagerie instantanée possible. Se produire si S est un type construit où les deux membres déclarés dans le type générique ont des signatures différentes, mais les arguments de type rendent leurs signatures identiques.

4 commentaires

+1. À partir d'une perspective de niveau inférieure, il y a un seul emplacement de méthode pour ihello.hello dans la machine à livrer pour la classe B, où la mise en œuvre va être levée.


Merci pour la réponse rapide! Bien que, selon les règles de l'OOP, une référence d'un point de classement de base à un objet d'ombres de classe dérivées sur les champs et les méthodes de la classe dérivée ne présente pas dans la classe de base. Est-ce alors une exception à cette règle?


@Naximus Le système de type sait toujours exactement ce que le type de l'objet est. Affectation d'une instance B à un champ A indique "laisse mon code Accédez à l'instance référencée par ce champ comme s'il s'agissait de Tapez A ". Casting ultérieurement le champ vers ihello dit "Temporairement Mon code Accédez à l'instance référencée par ce champ comme s'il s'agissait de type ihello iHello ". L'instance référencée toujours est et sera toujours de type B . Cela seul détermine le résultat. Seule la fois que de telles actions font quelque chose d'autre que «de la perspective de changement» d'une instance, c'est quand il y a des opérateurs de distribution définis pour cela.


(suite ...) Pour faire une métaphore géométrique visuelle semi-correcte très abstraite: pensez à l'objet comme étant multi-dimensionnelle, et votre code regarde l'objet avec un spectateur capable de visualiser l'objet à travers toutes les dimensions différentes. L'objet mon aspect très différent en fonction de la dimension de votre code à partir de (par exemple, Tesseract ) , mais c'est toujours le même objet, et les opérateurs d'affectation et de distribution changent simplement dans quelles dimensions le visualiseur voit l'objet. ... Mais peut-être que cette explication est TOO Résumé pour être utile? Je ne sais pas.



0
votes

Non, lorsque vous créez une méthode nouvelle neuve (tostring), ce n'est pas virtuel. NOUVEAU signifie simplement que cela ne vous dérange pas de "cacher" la version de la classe de base - donc si vous l'appelez avec une référence que vous avez lancée à un type spécifique (A), il exécute la méthode en classe A, quel que soit leur le type réel de l'objet que vous appelez. (c'est-à-dire que vous avez appelé A.Tostring () de sorte qu'il a exécuté A.Tostring ())

Lorsque vous créez une méthode virtuelle , alors quel que soit le type que vous lancez la référence à, la mise en œuvre du type réel de l'objet est utilisée (c'est-à-dire que vous avez créé un B, donc lorsque vous avez appelé. (Quel que soit l'objet) .hello, appelé B.Hello)

La différence cruciale est qu'un appel est virtuel et l'autre n'est pas.


1 commentaires

(Note aux lecteurs: La question a été modifiée après la rédaction de cette réponse. La première version de la question ajoutée nouvelle chaîne tostring () dans le mélange, augmentant la confusion. Pour plus de détails, voir révisions des interfaces explicites avec héritage? - Overflow de pile .)



3
votes

(a) A ne fait rien. La référence est déjà déclarée sous la forme d'un tel casting à une volonté n'a aucun effet.

Même si votre référence est déclarée comme un, l'objet qu'il fait référence est de type B. Si vous lancez cet objet à Ihello, un appel à Hello () appellera la mise en œuvre explicite de l'objet B de Hello.

La sortie est exactement comme prévu.


1 commentaires

(Note aux lecteurs: La question a été modifiée après la rédaction de cette réponse. La première version de la question ajoutée nouvelle chaîne tostring () dans le mélange, augmentant la confusion. Pour plus de détails, voir révisions des interfaces explicites avec héritage? - Overflow de pile .)



0
votes

Non, ça ne devrait pas.

Lorsque vous appelez une méthode virtuelle, peu importe le type de référence. La méthode appelée est déterminée par le type réel de l'objet, pas le type de référence.

Lorsque vous créez une instance de la classe B , le type réel de l'objet est B . La raison pour laquelle il imprime "c'est la classe A." est que vous n'avez pas remplacé la méthode tostring dans la classe B , vous avez ombragé Utilisant le mot-clé nouveau . Par conséquent, la classe B a deux méthodes tostring , une héritée à partir de la classe A et celle qui les ombres. Si vous utilisez une référence A pour appeler la méthode tostring , la méthode héritée est appelée, mais si vous auriez utilisé un B référence à appeler La méthode d'ombrage serait appelée, imprimant "c'est la classe b." .

Également si vous remplacez la méthode tostring dans la classe B au lieu de l'ourdler, il imprimerait "C'est la classe b." Quel que soit le type de référence.


1 commentaires

(Note aux lecteurs: La question a été modifiée après la rédaction de cette réponse. La première version de la question ajoutée nouvelle chaîne tostring () dans le mélange, augmentant la confusion. Pour plus de détails, voir révisions des interfaces explicites avec héritage? - Overflow de pile .)