Zeiger und abgeleitete klassen

  • Original von rml
    In der spezialisierten Klasse Auto könnte es z.B. eine Methode oeffneFahrerTuer geben, welche in der spezialisierten Klasse Motorrad natürlich keinen Sinn mach, wenn man mal von einem Standard Motorrad ohne Türen ausgeht. Ich würde daher nie auf die Idee kommen die Methode oeffneFahrerTuer in der gemeinsamen Basisklasse zu definieren, da man diese Methode in der Spezialisierung für Motorad einfach nicht benötigt. Diese Methode hätte dort keinen Inhalt ausser vielleicht eine Fehlermeldung zu produzieren, dass dieses Motorad keine Fahrertür hat.


    genau das ist wohl das problem.

    da ich aber von id besser keinen gebrauch machen sollte, wie ich hier höre, hab ich eine "dirty" variante genommen, die mir zwar üerhaupt nicht gefällt, aber scheinbar die einzige lösung zu sein scheint.

    ich habe in die containerklasse zeiger von allen klassen, die es gibt eingefügt und einen wert, der anzeigt, welchen inhalt dieser container nun hat.

    ich frage diesen wert ab und weiss, dass nur der entsprechende zeiger/referenz belegt ist und alle aneren 0.

    leider scheint es wohl tatsächlich nicht anders zu gehen ;( ;(


    Natürlich geht es auch anders. Dass habe ich ja schon hier beschrieben.
    Original von MCDan
    Damit der Compiler keine Warnungen mehr ausspuckt hilft nur eine Typumwandlung (cast) auf die spezialisiert Klasse, also hier z.B. auf Auto, oder die Änderung der Referenzierung, also die Verwendung einer Referenz auf die Klasse Auto.

    Konket würde dies dann in etwa so aussehen.

    Quellcode

    1. @interface MCVContainer : NSView {
    2. //Type of the Container Content -> entfällt, da dies über isKindOfClass: ermittelt werden kann!
    3. MeineBasisklasse *referenz;
    4. // alternativ würde auch
    5. id referenz; // funktionieren
    6. }
    Die Verarbeitung könnte dann in etwa so aussehen.

    Quellcode

    1. - (void)meineVerarbeitungsmethode
    2. {
    3. if ([referenz isKindOfClass:[Auto class]])
    4. {
    5. Autoklasse *autoReferenz = (Auto *)referenz;
    6. // Du kannst jetzt alle Methoden der Autoklasse ohne Warnings beim Compile verwenden, also z.B.
    7. [autoReferenz oeffenFahrerTuer];
    8. // alternativ kannst Du Dir die "Zwischenreferenz" sparen und z.B.
    9. [(Auto *)referenz oeffneFahrerTuer]; // verwenden
    10. }
    11. else if ([referenz isKindOfClass:[Motorrad class]])
    12. {
    13. // wie oben...
    14. }
    15. else if ... // für alle weiteren Klassen
    16. }
    Alles anzeigen
    Mir ist jedoch noch nicht klar, warum Du innerhalb der MCVContainer Klasse die einzelnen Klassen unterschiedlich aber dennoch über den selben Methodenaufruf der MCVContainer Klasse verarbeiten möchtest. Die Frage die sich hier stellt ist also, warum Du die Verarbeitung nicht gleich in die speziellen Klassen packst, also dass Du nur noch folgenden Code hast:

    Quellcode

    1. - (void)meineVerarbeitungsmethode
    2. {
    3. [referenz meineVerarbeitungsmethode];
    4. }
    In den speziellen Klassen hast Du dann die jeweils dafür erforderliche Verarbeitung implementiert.

    Was machst Du genau in der Verarbeitung, dass diese zwar gleich, also über den Aufruf der selben Methode in MCVContainer getriggert wird, jedoch jede Klasse dann unterschiedlich verarbeitet wird?
  • [Blockierte Grafik: http://www.amanda3d.de/kram/schema.jpg]

    also folgendermassen:

    ich habe den contentview eines fensters.

    als subview des contentviews habe ich eine abgeleitete klasse von NSView, welche die Container verwaltet (anzahl, größe, anordnung, aussehen usw.) diese container sind in einem mutable array untergebracht.

    der container macht nichts anderes, als ein paar funktionen zur verfügung zu stellen und eine weitere klasse, die von NSView abgeleitet ist, aufzunehmen (Container Inhalt).

    da ich nicht weiss, was für eine abgeleitete klasse als inhalt aufgenommen werden soll (beispiel, auto, motorrad, toastbrot), wollte ich ursprünglich eine universelle referenz verwenden (also Id oder NSView).

    in der praxis sind diese container inhalte dialoge, bilder usw.

    ihr habt geschrieben, ich solle nach möglichkeit kein id verwenden, weil hier keine typüberprüfung möglich ist und das unsauberer programmierstil wäre.

    vom hauptprogramm möchte ich via containerverwaltung-> container an den containerinhalt, da der containerinhalt nichts anderes machen soll, als messages ans hauptprogramm weiterleiten und spezielle funktionen ausführen, die aber so spezifisch sind, dass sie nur in einer bestimmten inhaltsklasse vorkommen....
  • Wenn ich das richtig sehe, dann ist dein einziges Problem, die richtige Subklasse für das Container-View zu erstellen?

    a) Wieso macht das dann der Container-View selbst und nicht der Controller deines Programmes (Meinetwegen Hauptprogramm)?

    b) Wenn das so sein soll, wieso gibst du nicht einfach dem Container-View ein Dictionary mit dem jeweiligen Subklassenobjekt als Key und dem speziellen View als Object. Der Container-Viiew sucht sich das dann heraus.
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • Wenn eine Methode nur in einer bestimmten Subklasse sinnvoll ist (offneTür), dann muss freilich der Objektnutzer wissen, dass es sich um eine Subklasse handelt. Es bringt ja nichts, dann eine Idee zu nehmen und den Nutzer raten zu lassen, ob die Methode nun gerade im konkreten Objekt ist.


    Ich habe hier schwer den Eindruck, dass ein massiver Design-Fehler vorliegt und man mit Tricks versucht, den zu kaschieren.
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • naja, da dieser teil noch nicht programmiert ist, kann ich da auch nichts kaschieren ;)
    ich suche nach einer lösung für die art der verwaltung, wie ich sie mir vorstelle...

    wichtig ist noch, dass die container inhalte auch unabhängig vom kontainer laufen können, da sie ggf. auch noch in seperaten fenstern zum einsatz kommen sollen.
  • Original von Tom9811
    Und Casting würde das nur "dumm verdecken".

    Stimmt alles, was Du da schreibst - nur mit dem hier bin ich nicht ganz einverstanden. Wenn man etwas aus einem Container holt und nicht in ein id-Variable packt, castest Du immer (und zwar von id auf den Typ, denn die Accessoren der Containerklassen sind ja generisch). Durch diesen impliziten Typecast entsteht die Warnung, denn bei id würde der Compiler mit Sicherheit nicht meckern. Dann verdeckt der explizite Typecast aber nichts - im Gegenteil macht er etwas sichtbar. Das kann kein schlechter Stil sein. Wenn man sich später den Code anschaut, sieht man den expliziten Typecast und kann nachvollziehen, dass das absichtlich gemacht wurde - ist doch nicht schlecht, oder?
    Multigrad - 360°-Produktfotografie für den Mac
  • Das ist nicht das Problem, sondern die Lösung:

    Nur die Inhalts-Views wissen, mit welcher Klasse sie es zu tun haben. Sie werden spezialisiert. Dein Container macht nichts, als diese Views anzulegen und den Verweis auf dein konkretes Objekt zu transportieren.

    Bleibt diie Frage, wier der Container wissen soll, welchen Inhaltsview er anlegen muss. Doch auch das ist ganz einfach. Entweder du vermittelst unmittelb in dem Container-View dieses Wissen, also durch Code
    if( [[myArray objectAtIndex:0] isKindOfClass:Auto] )
    NSView* newView = [Auto auto];
    usw. usf.

    Man kann das freilich noch eleganter machen. Aber so geht es erst einmal.

    Derzeit habe ich einfach wenig Zeit. In einer Woche kann ich das ausführlicher darlegen.
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?