Methode in einer abgeleiteten Klasse

  • Methode in einer abgeleiteten Klasse

    ##EDIT: Sorry - mir fiel echt kein besserer Titel ein ...

    Hallo!

    Ich habe, grob vereinfacht dargestellt, folgende Klassenhierarchie:

    Quellcode

    1. Klasse1 : NSObject
    2. ...
    3. Klasse2 : Klasse1
    4. ...
    5. Klasse3 : Klasse1
    6. ...
    7. Klasse4 : Klasse1
    8. ...
    Alles anzeigen

    Die Klassen 2,3 und 4 erweitern die Klasse 1 um Methoden und Properties.

    Meine Deklaration und die Initiatlisierung lauten vereinfacht:

    Quellcode

    1. Klasse1 *meineKlasse;
    2. ...
    3. meineKlasse = [[Klasse2 alloc] init];
    4. ...


    Ziel ist, dass ich mir in meinem Code im Standardfall keine Gedanken machen muss, ob meineKlasse vom Typ 2 oder 3 oder 4 ist - das kann sich zur Laufzeit ändern.

    Um abzusichern, dass ich an bestimmten Stellen, an denen ich eine Methode aufrufe, die z. B. nur in Klasse 2 und 4, aber vor allem nicht in Klasse 1 implementiert sind, kapsele ich den Aufruf in folgende Abfrage:

    Quellcode

    1. if( [meineKlasse respondsToSelector:@selector(methodeAusKlasse2und4:)] )
    2. [meineKlasse methodeAusKlasse2und4:wert]; <-- hier kommt die Warnung


    Verständlicherweise wirft Compiler nun aber Warnungen in der zweiten Zeile, denn die Methode "methodeAusKlasse2und4" ist (s. Deklaration von "meineKlase" oben) nicht in Klasse1 bekannt. Casten kann ich aber nicht, da ja zwei Klassen die Methode "methodeAusKlasse2und4" implementieren ...

    Wie kann ich dieses Problem wohl lösen? Nur auf "Klasse2" zu casten halte ich für denkbar, aber unelegant - gibt es einen besseren Weg?
  • Abstrakte Klasse, die die Methoden aufzeigt?
    Statt Klasse1* auf id?
    Protokoll zwischenklemmen?

    ich verstehe dein Problem nicht so genau...

    Ich denke aber,

    C-Quellcode

    1. Klasse1 <ProtokollMitImplementierungDerMethodenVonKlasse2Und4> *meineKlasse;

    should do the magic.

    Blöd natürlich, wenn du auch auf Klasse2Und3 sowie Klasse3Und4 prüfen willst.

    Insofern würde ich auf id casten und im Setter schauen, ob die übergebene ID von der Klasse Klasse1 ist oder zumindest davon erbt.
    Also -isKindOfClass oder -isMemberOfClass.
    «Applejack» "Don't you use your fancy mathematics to muddle the issue!"

    Iä-86! Iä-64! Awavauatsh fthagn!

    kmr schrieb:

    Ach, Du bist auch so ein leichtgläubiger Zeitgenosse, der alles glaubt, was irgendwelche Typen vor sich hin brabbeln. :-P
  • Hmm, ja, nee. :)

    Auf id casten bringt Fehlermeldungen, weil bestimmte Methoden (z. B. "start") auch in anderen Klassen der Frameworks (z. B. UITextPosition) vorkommen.

    Das mit dem Protokoll wäre eine Möglichkeit, aber dann könnte ich natürlich auch gleich auf die richtige Klasse einen Cast machen.

    Vermutlich gibt es für meine kruden Gedankengänge wieder keine Lösung ... :/
  • Dann caste halt auf eine der Klassen, die deine gewünschte Methode hat:

    PHP-Quellcode

    1. @interface Klasse3 {}
    2. -(id) fufu;
    3. @end
    4. #include"Foundation/Foundation.h"
    5. int main() {
    6. [NSAutoreleasePool new];
    7. NSString* x = @"Hallo Welt";
    8. if([x respondsToSelector:@selector(fufu)])
    9. NSLog(@"%@\n", [(Klasse3*)x fufu]);
    10. else
    11. NSLog(@"tralala\n");
    12. return 0;
    13. }
    Alles anzeigen


    Dann kann ich das Ganze ohne jegliche Warnungen so ausführen:

    Quellcode

    1. $ clang -framework Foundation x.m -o x && ./x
    2. 2010-09-02 23:37:13.029 x[11356:903] tralala
  • Aus meinem C++ Gefühl heraus frage ich mal, ob in so einer Situation Dein Klassendesign wirklich optimal ist. Kannst Du die Notwendigkeit noch einmal an einem Beispiel motivieren?

    Ich denke etwa wie folgt:
    Basisklasse "Figur"
    Figur hat Methode "flaecheninhalt()"
    Figur->Kreis (Methode "radius" kommt dazu)
    Figur->Rechteck (Methoden "kantenlaenge","anzahlEcken" kommen dazu)
    Figur->Polygon (Methode "kantenlaenge","anzahlEcken" kommen dazu)

    Wenn ich jetzt etwa den Flächeninhalt aller meiner Figuren addieren will, sind mir die Besonderheiten egal, ich arbeite also nur auf der Basisklasse. Wunderbar.
    In was für einer Situation muss ich jetzt unterschiedlich auf die verschiedenen Klassen reagieren, und kann das nicht global machen? Will ich den Umfang errechnen, bekommen alle eine Methode "umfang", anstelle if-else-gefrickel.
    Will ich alle Ecken zählen, sollte ich wahrscheinlich "Rechteck" nochmal "Polygon" unterordnen, und dann mit dynamic_cast bzw. respondsToSelector alle Polygone raussortieren und die Ecken zählen. Das ist dann aber nicht mehr so schön (Dein Problem?). Vielleicht habe ich dann lieber zwei Listen, wobei eine nur "Polygon"-Typen enthält. Kein Casting oder so notwendig. In den Listen stehen ja eh nur Pointer, da ist der Aufwand auch nicht gross.
    Hab ich jetzt eine Methode, die eine "Figur" bekommt, und unterschiedlich drauf reagieren soll, warum ist diese Methode dann nicht Teil der Klassen und implementiert in der Klasse selbst dieses spezifische Verhalten (soweit möglich)?
    Ansonsten gibs dafür auch noch das Visitor-Pattern, wenn eben das Spezifische nicht direkt in die Klassen gehört.

    Naja, hauptsächlich denke ich nur laut.
    Ich habe mal gelernt "dynamic_cast" wenn irgendwie nur möglich zu vermeiden. Ich denke, das sollte auf respondsToSelector in diesem Fall übertragbar sein.
    C++
  • fwtag schrieb:

    Das mit dem Protokoll wäre eine Möglichkeit, aber dann könnte ich natürlich auch gleich auf die richtige Klasse einen Cast machen.

    Wenn Du auf das Objekt mit einem id-Pointer verweist, brauchst Du keinen Cast. Zusammen mit dem Protokoll ist das dann eine saubere Sache, weil das Ganze dann unabhängig von der implementierenden Klasse ist:

    Quellcode

    1. @protocol MyProtocol
    2. - (void)foo:(int)inValue;
    3. @end
    4. ...
    5. - (void)bar:(id)inObject {
    6. if([inObject respondsToSelector:@selector(foo:)]) {
    7. [inObject foo:43];
    8. }
    9. }
    Alles anzeigen
    „Meine Komplikation hatte eine Komplikation.“
  • zerm schrieb:

    Aus meinem C++ Gefühl heraus frage ich mal, […]

    Und das ist hier genau falsch.

    Er fragt nach einer Methode (-respondsToSelector:). Wenn er nach einer Methode fragt, fragt er nach einer Fähigkeit, nicht nach einem Typen. Deshalb ist es in seinem Code fehlerhaft, überhaupt zu typisieren. Dass du das in C++ so fühlst, ist logisch, weil sich C++ auf Typen verlässt. Du würdest mutmaßlich auch in C++ nach dem Typen fragen und dann casten, was dannn auch in sich schlüssig wäre.

    Sein Einstellungsgespräch lautet in etwa:
    Frage: "Können Sie tippen?" (= Frage nach einer Methode -tippen)
    Antwort: "Ja!"
    Frage: "Gut,da Sie eine Sekretärin sind, können Sie auch Kaffee kochen." (= Fehlerhafte Unterstellung, dass daraus der Typ Sekretärin folgt)
    Antwort: "????"

    Aber fwtag weigert sich ja hartnäckig, Objective-C zu lernen …

    Wenn er es sich mal anders überlegt – die Hoffnung stirbt zuletzt –, wird er allerdings nur nach der Methode fragen und den Typen wegwerfen: id, wie Macmoonshine gesagt hat.
    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"?
  • @TE:
    Dein Beispiel ist falsch und wird zurecht vom Compiler bemängelt, denn Du hast einen Klasse1-typisierten Zeiger, ergo darfst Du auch nur Methoden aufrufen, die Klasse1 kennt.
    Gutes OO-Design ist nicht einfach, mit rumcasten, fragen nach Methoden wirst Du nicht weit kommen, wenn Du Dir über das grundlegende Design keine Gedanken gemacht hast.
    Einige Hinweise, wie der Rest der Welt so etwas für gewöhnlich macht, hast Du ja schon bekommen (abstrakte Basisklasse, Protokolle, id etc.). Wenn Klasse2, -3 und -4 Spezialisierungen von Klasse1 sein sollen (was die Vererbungshierarchie nahelegt), solltest Du nochmal über die Schnittstelle von Klasse1 nachdenken.

    Vielleicht auch was über Designpatterns und OO-Design lesen (Wikipedia, Google, Amazon...).
  • Amin Negm-Awad schrieb:


    Sein Einstellungsgespräch lautet in etwa:
    Frage: "Können Sie tippen?" (= Frage nach einer Methode -tippen)
    Antwort: "Ja!"
    Frage: "Gut,da Sie eine Sekretärin sind, können Sie auch Kaffee kochen." (= Fehlerhafte Unterstellung, dass daraus der Typ Sekretärin folgt)
    Antwort: "????"

    Amin, das ist Schwachsinn.

    Frage: "Können Sie tippen?"
    Antwort: "Ja!"
    Anweisung: "Dann tippen Sie!"
    Zwischenruf: "Kann die doch gar nicht!"

    Bleiben wir mal bei dem anschaulichen Beispiel.
    fwtag hat Mitarbeiter.
    Sekretärin ist ein Mitarbeiter.
    Hausmeister ist ein Mitarbeiter.
    Schriftführer ist ein Mitarbeiter.

    Jetzt sucht er sich einen Mitarbeiter und sagt ihm:
    "Wenn du tippen kannst, dann tippe."
    Da klopft ihm so ein neumalkluger Studierter auf die Schulter und sagt:
    "Nicht alle Mitarbeiter können tippen."

    C-Quellcode

    1. Mitarbeiter:Person
    2. NSString* abteilung;
    3. NSDecimal* gehalt;
    4. NSDate* einstellungsdatum;
    5. -(void)befördern;
    6. -(void)abmahnen;
    7. -(void)entlassen;
    8. Sekretärin:Person
    9. NSNumber *anschlägeProMinute;
    10. -(void)tippen;
    11. -(void)flachlegen;
    12. Hausmeister:Person
    13. -(void)anrufen;
    14. -(void)mobben;
    15. Schriftführer:Person
    16. NSString* tippUtensil;
    17. -(void)tippen;
    18. -(void)mobben
    Alles anzeigen


    fwtag möchte jetzt sinngemäß folgendes:

    C-Quellcode

    1. Mitarbeiter* mitarbeiterX = [Sekretärin];
    2. if([mitarbeiterX respondsToSelector:@selector(flachlegen)])
    3. {
    4. [mitarbeiterX flachlegen];
    5. }
    6. if([mitarbeiterX respondsToSelector:@selector(mobben)])
    7. {
    8. [mitarbeiterX mobben];
    9. }
    10. if([mitarbeiterX respondsToSelector:@selector(tippen)])
    11. {
    12. [mitarbeiterX tippen];
    13. }
    Alles anzeigen

    Und in jeder Zeile tippt ihm einer auf die Schulter und sacht:
    "Nicht jeder Mitarbeiter kann tippen / ist leicht zu mobben / lässt sich flachlegen."

    Dennoch verstehe ich das Grundproblem nicht.
    Schließlich fängt man immer(!) mit Klasse* member=[SpezifischeKlasse member] an.
    Dann kann man auch gleich richtig casten.

    Packt man die Leute natürlich erst in ein Array und holt sie anschließend einzeln raus, dann dürfte auch kein Compiler mehr meckern.
    Schließlich sagt man ihm ja nicht explizit, welchen Typ das Objekt hat.

    C-Quellcode

    1. [mitarbeiterArray addObjects:Sekretärin, Hausmeister, Schriftführer, nil];
    2. if([[mitarbeiterArray objectAtIndex:1] respondsToSelector:@selector(flachlegen)])
    3. {
    4. [[mitarbeiterArray objectAtIndex:1] flachlegen];
    5. }
    6. for(id mitarbeiter in mitarbeiterArray)
    7. {
    8. if([mitarbeiter respondsToSelector:@selector(flachlegen)])
    9. {
    10. [mitarbeiter flachlegen];
    11. }
    12. }
    Alles anzeigen


    Es wäre also hilfreich zu wissen, was genau du vorhast. :)
    «Applejack» "Don't you use your fancy mathematics to muddle the issue!"

    Iä-86! Iä-64! Awavauatsh fthagn!

    kmr schrieb:

    Ach, Du bist auch so ein leichtgläubiger Zeitgenosse, der alles glaubt, was irgendwelche Typen vor sich hin brabbeln. :-P
  • Lucas de Vil schrieb:

    Amin Negm-Awad schrieb:


    Sein Einstellungsgespräch lautet in etwa:
    Frage: "Können Sie tippen?" (= Frage nach einer Methode -tippen)
    Antwort: "Ja!"
    Frage: "Gut,da Sie eine Sekretärin sind, können Sie auch Kaffee kochen." (= Fehlerhafte Unterstellung, dass daraus der Typ Sekretärin folgt)
    Antwort: "????"

    Amin, das ist Schwachsinn.




    Lucas de Vil schrieb:

    Frage: "Können Sie tippen?"
    Antwort: "Ja!"
    Anweisung: "Dann tippen Sie!"
    Zwischenruf: "Kann die doch gar nicht!"

    Das ist falsch.
    Der Compiler zeigt die Warnung, weil der OP eine Klasse typisiert, nicht, weil er die Methode nicht kennt. Die kennt er. Das kann man sehr leicht daran erkennen, dass
    a) die Warnung bei id nicht kommt
    b) ein Import bei seiner Lösung nichts ändern würde.

    Der OP spricht die gesamte Zeit von Klassen.

    Da geht es also beides Mal um Klassen, nicht um Methoden.


    Lucas de Vil schrieb:

    Bleiben wir mal bei dem anschaulichen Beispiel.
    fwtag hat Mitarbeiter.
    Sekretärin ist ein Mitarbeiter.
    Hausmeister ist ein Mitarbeiter.
    Schriftführer ist ein Mitarbeiter.

    Jetzt sucht er sich einen Mitarbeiter und sagt ihm:
    "Wenn du tippen kannst, dann tippe."
    Da klopft ihm so ein neumalkluger Studierter auf die Schulter und sagt:
    "Nicht alle Mitarbeiter können tippen."

    Bis dahin ist das noch richtig.

    Lucas de Vil schrieb:

    C-Quellcode

    1. Mitarbeiter:Person
    2. NSString* abteilung;
    3. NSDecimal* gehalt;
    4. NSDate* einstellungsdatum;
    5. -(void)befördern;
    6. -(void)abmahnen;
    7. -(void)entlassen;
    8. Sekretärin:Person
    9. NSNumber *anschlägeProMinute;
    10. -(void)tippen;
    11. -(void)flachlegen;
    12. Hausmeister:Person
    13. -(void)anrufen;
    14. -(void)mobben;
    15. Schriftführer:Person
    16. NSString* tippUtensil;
    17. -(void)tippen;
    18. -(void)mobben
    Alles anzeigen


    fwtag möchte jetzt sinngemäß folgendes:

    C-Quellcode

    1. Mitarbeiter* mitarbeiterX = [Sekretärin];
    2. if([mitarbeiterX respondsToSelector:@selector(flachlegen)])
    3. {
    4. [mitarbeiterX flachlegen];
    5. }
    6. if([mitarbeiterX respondsToSelector:@selector(mobben)])
    7. {
    8. [mitarbeiterX mobben];
    9. }
    10. if([mitarbeiterX respondsToSelector:@selector(tippen)])
    11. {
    12. [mitarbeiterX tippen];
    13. }
    Alles anzeigen

    Und wieder die Abfrage auf eine Methode und die Verwendung von Klassen.

    Noch einmal: Die Nachfrage nach einer Methode hat nichts mit der Typisierung der Instanz zu tun.

    Lucas de Vil schrieb:

    Und in jeder Zeile tippt ihm einer auf die Schulter und sacht:
    "Nicht jeder Mitarbeiter kann tippen / ist leicht zu mobben / lässt sich flachlegen."

    Dennoch verstehe ich das Grundproblem nicht.

    Ja, das merkt man. Das ist der Grund, warum dein Beitrag Schwachsinn ist. :)

    Lucas de Vil schrieb:

    Schließlich fängt man immer(!) mit Klasse* member=[SpezifischeKlasse member] an.
    Dann kann man auch gleich richtig casten.

    Ja, kann man. Wenn man keine Ahnung von Objective-C hat. Das ist kein C++.

    Was willst du da überhaupt mit Klassen anfangen?

    Aber selbst, wenn du Klassen möchtest, dann musst du es eben durchziehen. Und das macht er nicht. Denn dann wäre seine erste Frage: "Haben Sie eine Ausbildung zur Sekretärin gemacht?" Die stellt er aber gerade nicht.

    Lucas de Vil schrieb:

    Packt man die Leute natürlich erst in ein Array und holt sie anschließend einzeln raus, dann dürfte auch kein Compiler mehr meckern.
    Schließlich sagt man ihm ja nicht explizit, welchen Typ das Objekt hat.

    Eben, weil das id-typisiert ist. Und liest du noch einmal in Ruhe meinen Beitrag.

    Lucas de Vil schrieb:

    C-Quellcode

    1. [mitarbeiterArray addObjects:Sekretärin, Hausmeister, Schriftführer, nil];
    2. if([[mitarbeiterArray objectAtIndex:1] respondsToSelector:@selector(flachlegen)])
    3. {
    4. [[mitarbeiterArray objectAtIndex:1] flachlegen];
    5. }
    6. for(id mitarbeiter in mitarbeiterArray)
    7. {
    8. if([mitarbeiter respondsToSelector:@selector(flachlegen)])
    9. {
    10. [mitarbeiter flachlegen];
    11. }
    12. }
    Alles anzeigen


    Du willst ihm jetzt allen ernstes raten, eine einzelne Instanz in ein Array zu legen? Damit man die id-Typisierung hat? Das ist doch bitte ein Scherz?

    Vielleicht solltest du das Array dann noch serialisieren, auf einem Server archivieren, den eine Antwortmail mit Attachment schicken lassen, aus dem Attachment wieder eine Instanz machen und dann die Nachricht schicken.


    Lucas de Vil schrieb:

    Es wäre also hilfreich zu wissen, was genau du vorhast. :)

    Es ist völlig klar, was er vorhat. Er hat eine Basisklasse auf de er typisiert (Subklasse sind gleichzeitig Basisklassen) und will dann eine subklassenspezifische Methode ausführen.

    In C++ löst man so etwas mit einem Downcast. Das kann man hier auch machen. Oder man macht es ohne Typisierung. Beides geht. Nur sein Gemisch geht nicht.
    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"?
  • Um zu verstehen, worauf ich hinaus will, betone es mal so:
    Können Sie tippen …
    Wenn Sie eine Sekretärin sind, …

    Du kannst für tippen und Sekretärin sonstwas einsetzen (kochen, trinken, flachlegen, Mitarbeiter Hausmeister, Schreibmaschine, Mensch). Das Problem der Verwechslung Fähigkeiten zu Typ bleibt bestehen. Und das löst du nur, indem du entweder beides typisiert machst oder beides untypisiert. Aber kein Mischmasch.
    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"?
  • Ach Amin... :rolleyes:

    Teilantwort 1:
    Dein Beitrag ist insofern Schwachsinn, als dass das, was du da behauptest, nicht passiert.
    In seinem Codeschnippsel, der die Warning produziert, meckert der Compiler, dass das Objekt die Nachricht eventuell nicht beantworten kann.
    Er fragt: 'Können Sie tippen?', Sie sagt "Jo.", er sagt 'Dann tippen Sie!', der Compiler meckert 'Die kann das vermutlich nicht.'
    Er sagt nicht "Weil Sie Sekretärin sind,...", er sagt "Tippen Sie!".

    Dass daran ausschließlich fwtags Typisierung Schuld ist, ist sowohl mir als auch ihm bekannt und steht in diesem Teilabschnitt auch überhaupt nicht zur Diskussion.
    Ende Teilantwort 1

    Teilantwort 2:
    fwtag weist darauf hin, dass das Typisieren auf id weitere Warnungen bringt, weil die Klassen Methoden beinhalten, die auch andere Klassen kennen.
    Der Compiler warnt also, dass er keine Ahnung hat worauf sich fwtag bezieht.
    Ende Teilantwort 2

    Teilantwort 3:
    Herrje, er möchte doch nur, dass der Compiler informiert ist, welcher (Basis)klasse die ausgewiesenen Objekte angehören, damit die in Teilantwort 2 erwähnte Warnung nicht mehr ausgespuckt wird.
    Am Liebsten wäre es ihm, der Compiler würde nicht meckern, wenn man Methoden einer Kindklasse aufrufen möchte, über deren Beantwortung man sich vorher informiert hat. Das ist alles.
    Ende Teilantwort 3

    Teilantwort 4:
    Mit Verlaub, da irrst du. Ich persönlich kenne einfach keinen spezifischen Anwendungsfall für das von mir gestrickte Konstrukt.
    Wenn ich auf Objekte typisieren möchte, die irgendwie tippen können, dann kann ich mir ein Zwischenobjekt 'Schreibkräfte' basteln, von denen Sekretärin und Schriftführer abgeleitet sind.
    Oder ich nutze das Decorator-Muster, um meinem speziellen Mitarbeiter neue Skills mitzugeben.
    Deshalb möchte ich ein konkretes Beispiel von fwtag darüber, wie genau jetzt Klasse1 bis Klasse4 aussehen sollen und was er mit diesem Design bezweckt.
    Ende Teilantwort 4

    Teilantwort 5:
    Zugegeben, 'man' war falsch. Für solche Fälle empfiehlt sich das Typisieren auf id. Wobei dann immer noch die in Teilantwort 2 angesprochenen Warnings ausgespuckt werden können.
    Warum sich fwtag jetzt an den Klassen fest hält weiß ich nicht. Dafür hätte ich gern ein konkretes Beispiel, um diese Wissenslücke zu schließen.
    Ende Teilantwort 5

    Teilantwort 6:
    Wozu? Nur weil du aus meinem Beitrag nicht erkennen kannst, wann ich die Vorgänge des OPs nachbilde und wann ich es richtig mache?
    Das ist nun bei Leibe nicht mein Problem.
    Ende Teilantwort 6

    Teilantwort 7:
    Nein, das will ich nicht raten. Ich versuche, einen Sinn hinter fwtags Einstiegscode und der Notwendigkeit der pseudodynamischen Methodenanalyse zu finden.
    Wenn er, wie in seinem Einstiegscode, typisiert und zuweist, kann er die Typisierung gleich auf die richtige Klasse machen.
    Es ergibt nur keinen Sinn, ein Objekt nach seiner Methodenunterstützung zu befragen, wenn ich genau weiß, ob es das kann.
    Also gehe ich davon aus, dass das Vorgehen darin besteht, dass aus einer Sammlung von Objekten einzelne abgerufen und analysiert werden sollen.
    Da erschließt sich mir das Problem allerdings ebenfalls nicht, weil der Zugriff auf Objekte aus Sammlungen wie Sets oder Arrays stets untypisiert erfolgt ([array objectAtIndex:index]) bzw. erfolgen sollte. (for(id object in array))

    Wie zerm denke auch ich gern laut, das ist alles.

    Dein überzogenes Rumgealbere und Szeneriekostruiere über Dinge, die du offenbar falsch verstanden und ohne nachzufragen als deine eigene Wahrheit angenommen hast, nervt im Übrigen gewaltig.
    Als wärest du als kleines Kind in den großen Bottich mit der unendlichen Weisheit gefallen. :rolleyes:
    Ende Teilantwort 7

    Teilantwort 1, Beitrag 2:
    Vielleicht verstehst du es jetzt: wenn fwtag dynamisches Typisieren via id nutzt, bekommt er an anderer Stelle andere Warnungen.

    fwtag schrieb:

    Auf id casten bringt Fehlermeldungen, weil bestimmte Methoden (z. B. "start") auch in anderen Klassen der Frameworks (z. B. UITextPosition) vorkommen.

    Auch deshalb möchte ich wissen, was genau er vor hat.
    Ende Teilantwort 1, Beitrag 2

    (Teilantworten, damit du nicht wieder irgendwelche Zusammenhänge in Dinge hineininterpretierst, in denen es keine Zusammenhänge gibt.)
    «Applejack» "Don't you use your fancy mathematics to muddle the issue!"

    Iä-86! Iä-64! Awavauatsh fthagn!

    kmr schrieb:

    Ach, Du bist auch so ein leichtgläubiger Zeitgenosse, der alles glaubt, was irgendwelche Typen vor sich hin brabbeln. :-P
  • Lucas de Vil schrieb:

    Ach Amin... :rolleyes:

    Teilantwort 1:
    Dein Beitrag ist insofern Schwachsinn, als dass das, was du da behauptest, nicht passiert.

    Doch, es passiert: Er stellt eine Frage nach der Fähigkeit und erwartet dann eine Annahme zur Klasse. fwtag glaubt, dass wenn er nur die Fähigket abfragt, der Compiler automatisch sieen müsste, dass es sich um eine passende Klasse handelt. Das weiß der Compiler aber nicht.

    Lucas de Vil schrieb:

    In seinem Codeschnippsel, der die Warning produziert, meckert der Compiler, dass das Objekt die Nachricht eventuell nicht beantworten kann.

    Nein, er sagt, dass diese Objekt als Instanz einer bestimmten Klasse die Nachricht eventuell nicht beantworten Kann. Der Compiler interessiert sich nämlich genau gar nicht für Instanzen, weil es die zur Übersetzungszeit noch nicht gibt. F+r ihn geht es immer und ewig um die Klasse, weshalb ein id hilft. Das würde aber am Objekt gar nichts ändern.


    Lucas de Vil schrieb:

    Er fragt: 'Können Sie tippen?', Sie sagt "Jo.", er sagt 'Dann tippen Sie!', der Compiler meckert 'Die kann das vermutlich nicht.'
    Er sagt nicht "Weil Sie Sekretärin sind,...", er sagt "Tippen Sie!".

    Er erwartet das aber. Er fragt ja die Fähigkeit ab, weil er diese in der Subklasse verortet hat.

    Kann man ganz einfach mit einer Gegenprobe überprüfen: Stünde da "$wassieauchimmersind (aka id) tippen Sie", dann gäbe es nämlich keine Warning. Der Compiler stört sich einzig und allein an der Klasse.

    Lucas de Vil schrieb:

    Dass daran ausschließlich fwtags Typisierung Schuld ist, ist sowohl mir als auch ihm bekannt und steht in diesem Teilabschnitt auch überhaupt nicht zur Diskussion.
    Ende Teilantwort 1

    Doch steht zur Diskussion. Und zwar schon in meinem ersten Beitrag. Einfach noch einmal lesen.

    Lucas de Vil schrieb:

    Teilantwort 2:
    fwtag weist darauf hin, dass das Typisieren auf id weitere Warnungen bringt, weil die Klassen Methoden beinhalten, die auch andere Klassen kennen.
    Der Compiler warnt also, dass er keine Ahnung hat worauf sich fwtag bezieht.
    Ende Teilantwort 2

    Dann soll er – wie jeder anständige Objective-C-Programmierer, die Methoden eindeutig benamen, etwa statt addAge: einfach addIntegerAge: oder addAgeAsFullYears: usw. Das sollte man ohnehin machen. Dass da auch Apple zuweilen sehr schludrig ist, muss ihm ja nicht als Vorbild dienen.

    Lucas de Vil schrieb:

    Teilantwort 3:
    Herrje, er möchte doch nur, dass der Compiler informiert ist, welcher (Basis)klasse die ausgewiesenen Objekte angehören, damit die in Teilantwort 2 erwähnte Warnung nicht mehr ausgespuckt wird.

    Und das ist aber der Fehler.

    Lucas de Vil schrieb:

    Am Liebsten wäre es ihm, der Compiler würde nicht meckern, wenn man Methoden einer Kindklasse aufrufen möchte, über deren Beantwortung man sich vorher informiert hat. Das ist alles.
    Ende Teilantwort 3

    Und dazu verwendet man
    entweder
    a) id-Typisierung und dynamische Methodenauflösung
    oder
    b) Downcasting.
    Merkst du es? Entweder – oder … Das ist das Zauberwort.

    Er verwendet beides gemischt.

    Lucas de Vil schrieb:

    Teilantwort 4:
    Mit Verlaub, da irrst du. Ich persönlich kenne einfach keinen spezifischen Anwendungsfall für das von mir gestrickte Konstrukt.
    Wenn ich auf Objekte typisieren möchte, die irgendwie tippen können, dann kann ich mir ein Zwischenobjekt 'Schreibkräfte' basteln, von denen Sekretärin und Schriftführer abgeleitet sind.
    Oder ich nutze das Decorator-Muster, um meinem speziellen Mitarbeiter neue Skills mitzugeben.
    Deshalb möchte ich ein konkretes Beispiel von fwtag darüber, wie genau jetzt Klasse1 bis Klasse4 aussehen sollen und was er mit diesem Design bezweckt.
    Ende Teilantwort 4

    Dass du den Anwendungsfall nicht kennst, sagt ja nichts darüber aus.

    Du kennst ihn aber, weil wir ihn nämlich im Kurs durchgenommen haben: Die Methode, die den Text von Menu-Items, Buttons und Textfeldern ausgeben sollte.

    Und nein, da macht man sich keine Zwischenklassen wie "Hat Text in title", "hat Text in stringValue", …

    Man typisiert weinfach nicht.

    Lucas de Vil schrieb:

    Teilantwort 5:
    Zugegeben, 'man' war falsch. Für solche Fälle empfiehlt sich das Typisieren auf id.

    Und das hatte ich bereits geschrieben. Aber ich will nicht einmal sagen, dass man das über id lösen muss. Man kann das auch über Downcast lösen. Aber dann muss man es eben über Downcast lösen. Was aber eben nicht geht, ist dass man einmal die Methode abfragt und man dann heimliche Annehmen über den Typen macht.

    Lucas de Vil schrieb:

    Wobei dann immer noch die in Teilantwort 2 angesprochenen Warnings ausgespuckt werden können.
    Warum sich fwtag jetzt an den Klassen fest hält weiß ich nicht. Dafür hätte ich gern ein konkretes Beispiel, um diese Wissenslücke zu schließen.
    Ende Teilantwort 5

    Weil es in seinen Augen Klassenhierarchie ist, siehe OP. Das ist auch nicht falsch. Es ist auch nicht falsch, dass über Klassen (Typisierung) zu lösen. Es ist nur falsch, es mal so oder so zu machen. Und extra für dich hatte ich in meinem ersten Posting auch schon erklärende Klammern hinzugefügt.

    Lucas de Vil schrieb:

    Teilantwort 6:
    Wozu? Nur weil du aus meinem Beitrag nicht erkennen kannst, wann ich die Vorgänge des OPs nachbilde und wann ich es richtig mache?
    Das ist nun bei Leibe nicht mein Problem.
    Ende Teilantwort 6

    Da du nicht zitiert hast, worauf sich das bezieht, weiß ich es nicht so genau.

    Lucas de Vil schrieb:

    Teilantwort 7:
    Nein, das will ich nicht raten. Ich versuche, einen Sinn hinter fwtags Einstiegscode und der Notwendigkeit der pseudodynamischen Methodenanalyse zu finden.

    Den gibt es zuhauf, siehe etwa oben. Aber man könnte auch nach Downcast googlen.

    Lucas de Vil schrieb:

    Wenn er, wie in seinem Einstiegscode, typisiert und zuweist, kann er die Typisierung gleich auf die richtige Klasse machen.Es ergibt nur keinen Sinn, ein Objekt nach seiner Methodenunterstützung zu befragen, wenn ich genau weiß, ob es das kann.

    Richtig. Das ist aber nicht sein Problem. Er weiß es nicht.

    Lucas de Vil schrieb:

    Das weiß er auch nicht.

    Gut erkannt.
    Fassen wir das mal zusammen: "Er kann die Typisierung gleich vornehmen, wenn er sie kennt", "Er kennt sie aber nicht." Und was wolltest du mir jetzt sagen, außer dass du eine Möglichkeit aufzeigst, die garantiert nicht funktioniert?

    Lucas de Vil schrieb:

    Also gehe ich davon aus, dass das Vorgehen darin besteht, dass aus einer Sammlung von Objekten einzelne abgerufen und analysiert werden sollen.

    Woher weißt du, ob die in einer Sammlung stecken?

    Lucas de Vil schrieb:

    Da erschließt sich mir das Problem allerdings ebenfalls nicht, weil der Zugriff auf Objekte aus Sammlungen wie Sets oder Arrays stets untypisiert erfolgt ([array objectAtIndex:index]) bzw. erfolgen sollte. (for(id object in array))

    Ah, dann darf er die Bearbeitung eines einzelnen Objektes nicht in eine eigene Methode schreiben? Er muss auch bei jedem Zugriff [collection object…] schreiben? Bloß nicht den Zeiger merken? Damit die Typisierung auf id bleibt?

    Schlaue Lösung!

    Noch schlauer wäre es aber, einfach auf id zu typisieren.


    Lucas de Vil schrieb:

    Wie zerm denke auch ich gern laut, das ist alles.

    Dein überzogenes Rumgealbere und Szeneriekostruiere über Dinge, die du offenbar falsch verstanden und ohne nachzufragen als deine eigene Wahrheit angenommen hast, nervt im Übrigen gewaltig.

    Ah, so.

    Lucas de Vil schrieb:

    Als wärest du als kleines Kind in den großen Bottich mit der unendlichen Weisheit gefallen. :rolleyes:
    Ende Teilantwort 7

    Ah, deshalb antwrte ich dir auch gleich mit Schwachsinn.

    Lucas de Vil schrieb:

    Teilantwort 1, Beitrag 2:
    Vielleicht verstehst du es jetzt: wenn fwtag dynamisches Typisieren via id nutzt, bekommt er an anderer Stelle andere Warnungen.

    fwtag schrieb:

    Auf id casten bringt Fehlermeldungen, weil bestimmte Methoden (z. B. "start") auch in anderen Klassen der Frameworks (z. B. UITextPosition) vorkommen.

    Auch deshalb möchte ich wissen, was genau er vor hat.
    Ende Teilantwort 1, Beitrag 2

    Siehe dazu oben.
    Übrigens bringt -start ganz gewiss keine Fehlermeldung, da diese keine Parameter nimmt. Und deshalb stört sich der Compiler auch nicht daran. Es muss mindestens -start: sein oder einen Rückgabewert haben. (Intern ist das dasselbe.) Und dann nennt man das Ding einfach anständig: -startMovie:, -startMusic:, startWasWeißIch:.

    Eine Eigenschaft start zu nennen, ist schon deshalb schlecht, weil man nicht wissen kann, ob das ein Kommando (Starte!) oder eine Eigenschaft (Startposititon) ist.

    Es ist indessen wenig hilfreich, einen Fehler mit einem weiteren Fehler zu beseitigen.


    Lucas de Vil schrieb:

    (Teilantworten, damit du nicht wieder irgendwelche Zusammenhänge in Dinge hineininterpretierst, in denen es keine Zusammenhänge gibt.)

    Wenn es dir darum gegangen wäre, hättest du einfach zitiert. Aber das war dir wohl zu heikel.
    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"?

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von Amin Negm-Awad ()

  • Die beiden Lösungsmöglichkeiten:

    1: Typisiert (Sein) + Downcast:

    Quellcode

    1. BaseClass* instance = …
    2. if( [instance isKindOfClass:[subclass1 class] ) { // Frage nach dem TYPEN, Methode interessiert nicht
    3. [(Subclass1*)instance doSomethingSubclass1CanDo]; // Downcasting auf den TYPEN
    4. } else if( [instance isKindOfClass:[subclass2 class] ) {


    2: Typlos, Konzentration auf Methoden

    Quellcode

    1. id instance = … // typ interessiert nicht
    2. if( [instance respondsToSelector:@selector( doSomethingSomeoneCanDo ) ) { // Frage nach der METHODE, Typ interessiert nicht
    3. [instance doSomethingSomeoneCanDo]; // Ausführung der METHODE, kein Downcast, weil der Typ inicht interessiert.
    4. } else if( [instance respondsToSelector:@selector( doSomethingSomeoneCanDo ) ) {


    Variante 2 ist Objective-C-ish, weil die dynamische Bindung ausgenutzt wird. Wenn es Probleme mit Methodennamen gibt, ist das kein Argument, da man Methodennamen gut wählen kann. Im allerschlimmsten Falle hilft man dem Compiler dann immer noch mit einem Cast. Thread ist von wolf10_de verlinkt.

    Wie bereits eingangs gesagt, ist es keine Lösung, im if nach der Methode zu fragen und dann im if-Zweig irgendwelche Annehmen über den Typen zu machen.
    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"?
  • Erster Gedanke zu 1)
    Wie soll denn das bitte etwas abstrakter aussehen?

    C-Quellcode

    1. if( [instance isKindOfClass:[subclass2 class] || [instance isKindOfClass:[subclass4 class] || [instance isKindOfClass:[subclass9 class])
    2. {
    3. //do stuff every of this subclasses can do
    4. }
    5. if( [instance isKindOfClass:[subclass1 class] || [instance isKindOfClass:[subclass3 class] || [instance isKindOfClass:[subclass9 class])
    6. {
    7. //do stuff every of this subclasses can do
    8. }

    Das ist ja neben hässlich auch noch total C++

    Amin Negm-Awad schrieb:

    Wie bereits eingangs gesagt, ist es keine Lösung, im if nach der Methode zu fragen und dann im if-Zweig irgendwelche Annehmen über den Typen zu machen.

    Wo zum Henker macht er bitte im if-Zweig irgendwelche Annahmen über den Typen? Die macht er ja wohl definitiv schon weit vor dem if-Zweig!

    Amin Negm-Awad schrieb:

    Übrigens bringt -start ganz gewiss keine Fehlermeldung, da diese keine Parameter nimmt. Und deshalb stört sich der Compiler auch nicht daran.

    Soweit ich mich erinnere gibt es gern mal Probleme, wenn der Compiler gleiche Methoden mit unterschiedlicher Signatur bekommt.
    Also Dinge wie -(void)start, -(void)start: (id)something, -(void)start: (id)something: (id)different: (id)also
    Hab jetzt keine Zeit im Forum zu suchern, erinnere mich aber, dass dazu was geschrieben stand.

    Amin Negm-Awad schrieb:

    Woher weißt du, ob die in einer Sammlung stecken?

    Ich gehe davon aus. Steht doch da.

    Amin Negm-Awad schrieb:

    Ah, deshalb antwrte ich dir auch gleich mit Schwachsinn.

    Genialität und Wahnsinn liegen dicht beieinander. Mit Weisheit und Schwachsinn dürfte es ähnlich sein.

    Nun gut, offenbar versuchen wir, dasselbe mitzuteilen.
    Deshalb fasse ich noch einmal in einem eigenen Post zusammen.
    «Applejack» "Don't you use your fancy mathematics to muddle the issue!"

    Iä-86! Iä-64! Awavauatsh fthagn!

    kmr schrieb:

    Ach, Du bist auch so ein leichtgläubiger Zeitgenosse, der alles glaubt, was irgendwelche Typen vor sich hin brabbeln. :-P
  • fwtag
    Wenn du deine Instanzobjekte dynamisch nach deren Methoden analysieren möchtest, dann typisiere auf id.
    Solltest du dann Fehlermeldungen kassieren, weil irgendwelche Methodennamen doppeldeutig sind, benenne deine eigenen Methoden aussagekräftig.
    Dann hast du auch keine Probleme mehr. :)
    «Applejack» "Don't you use your fancy mathematics to muddle the issue!"

    Iä-86! Iä-64! Awavauatsh fthagn!

    kmr schrieb:

    Ach, Du bist auch so ein leichtgläubiger Zeitgenosse, der alles glaubt, was irgendwelche Typen vor sich hin brabbeln. :-P