Zeiger und abgeleitete klassen

  • Dochm, das macht er. Das fällt dann negativ auf, wenn eine Methode in irgendwelchen Klassen mehrfach definiert ist, etwa einmal mit retval und einmal ohne, also ohne dass du einen Fehler gemacht hast! Ich glaube, -setName: ist so ein Kandidat.

    id wirklich nur dann benutzen, wenn es _irgendein_ Objekt ist.
    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"?
  • hups, mit sovielen antworten habe ich garnicht gerechnet. muss auch zugeben,dass ich gerade zum späteren zeitpunkt nicht mehr alles verstanden habe, wo die probleme liegen.
    ich werde es einfach mal mit beiden varianten probieren und schaun, welche er schluckt und vor allem ausführt.

    danke auf jeden fall für die informationen. ich werde es gleich morgen testen und mich melden, was geklappt hat :)


    ---------------------------------------------------------------------------------
    mir ist noch eine nette erklärung eingefallen, wie ich es besser umschreiben kann. und nein, ich habe nichts mit autos oder motorädern am hut ;)

    ich habe z.b. eine klasse motorad mit allen daten zu leistungen und ein paar motoradspezifische funktionen.

    ich habe z.b. eine klasse auto die daten zu autos aufnehmen kann und autospezifische funktionen enthält.

    weiterhin habe ich keine klasse namens fahrzeug mit einer variable die den fahrzeugtyp festhält und einen zeiger, der entweder auf auto oder motorad zeigt.

    fahrzeug wird in einem mutable array verwaltet. durch die typvariable wiess ich, welche funktionen ich über den zeiger aufrufen kann...
  • Du gehst die Sache falsch an.

    Nimm die Klasse Fahrzeug und implementiere da wie bisher den Typen (wenn du ihn überhaupt noch brauchst, dazu später mehr.)

    Leite Auto und Motorrad davon ab. Also nicht als Instanzvariable, sondern als Subklasse. Dort kannst du dann Erweiterungen unterbringen. Das meinte ich mit Zwischenklasse.

    Wenn der Fahrzeugtyp nur Motorrad oder Auto speichert, kannst du bei Fahrzeug auch ganz auf den Typen verzichten. Den erfährst du zur Laufzeit von der Subklasse mittels

    Quellcode

    1. if( [object isKindOfClass:[Bicycle class]] ) {
    2. NSLog( @"brumm brumm" );
    3. } else if( [brummbrumm isKindOfClass:[Car class]] ) {
    4. NSLog( @"töff töff" );
    5. }


    BTW: Gemeinsame Eigenschaften beider Fahrzeugtypen gehören in die Klasse Fahrzeug, Leistung etwa.
    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 der Fahrzeugtyp nur Motorrad oder Auto speichert, kannst du bei Fahrzeug auch ganz auf den Typen verzichten. Den erfährst du zur Laufzeit von der Subklasse mittels


    naja, sind etwa 25 bis 30 verschiedene klassen.

    stimmt aber, das ist auch eine art. gefällt mir :) die werde ich mal zuerst versuchen!
  • Original von Tom9811
    Ein Casting bringt nichts, weil es keine Sicherheit verspricht. Da kannste auch gleich diie Warning ausschalten.

    Stimmt, Castings bringen nichts - insbesondere der DSDS-Mist :)

    Naja, es ist schon ein Unterschied, ob ich an einer bestimmten Stelle einen Typecast vornehme, an der ich weiß, dass er korrekt ist oder ob ich die Warnungen generell abschalte. Das ist m.E. vollkommen sauberer Stil. Um sicher zu gehen, kann ich den Typecast in ein if ([x isKindOfClass: Y]) schachteln, dann kann es keine Laufzeitprobleme damit geben - oder ich kann einen id-Cast in ein if ([x respondsToSelector:Y]) schachteln, um Y aufzurufen. Und ich komme damit an Stellen weiter, in denen mir Kategorien auch nicht helfen - insb. dann, wenn es sich tatsächlich um heterogene Collections handelt. Kategorien sind toll, das ist unbestritten - aber die Testmöglichkeiten, die sie eröffnen, sind nunmal statisch.
    Multigrad - 360°-Produktfotografie für den Mac
  • also, ich habe mal die tests mit id unf NSView gemacht.

    er führt das programm korrekt aus, warnt aber, dass es sein kann, dass es die funktionen nicht gibt.
    alo unbrauchbar, da ich beim compilieren mit hunderten von warnungen bombardiert werde, auch wenn das programm funktioniert...

    jetzt kommt der test mit der abgeleiteten klasse...
  • Original von rml
    also, ich habe mal die tests mit id unf NSView gemacht.

    er führt das programm korrekt aus, warnt aber, dass es sein kann, dass es die funktionen nicht gibt.
    alo unbrauchbar, da ich beim compilieren mit hunderten von warnungen bombardiert werde, auch wenn das programm funktioniert...

    jetzt kommt der test mit der abgeleiteten klasse...

    Die Warnungen sollten aber nur bei der Referenzierung über NSView kommen und nicht über id.

    Wenn dies der Fall ist, dann wirst Du diese Warnungen mit Hilfe der abgeleiteten Klassen nicht los werden, da Dir die Methoden der abgeleiteten Klassen in der Basisklasse, über welche Du ja dann refernzieren willst, auch nicht bekannt sind.

    Der Ansatz mit den abgeleiteten Klassen ist zwar der richtige Weg in Bezug auf OO, wird Dir bei dem Referzierungsproblem jedoch nicht wirklich helfen.
  • na, bei NSView kommt diese meldung:

    /Users/rml/Desktop/Amanda3D/Interface/MainContentView.m:36: warning: 'NSView' may not respond to '-initialize'
    /Users/rml/Desktop/Amanda3D/Interface/MainContentView.m:36: warning: (Messages without a matching method signature
    /Users/rml/Desktop/Amanda3D/Interface/MainContentView.m:37: warning: 'NSView' may not respond to '-SetContext'
    /Users/rml/Desktop/Amanda3D/Interface/MainContentView.m:38: warning: 'NSView' may not respond to '-drawit'
    /Users/rml/Desktop/Amanda3D/Interface/MainContentView.m:78: warning: 'NSView' may not respond to '-SetContext'
    /Users/rml/Desktop/Amanda3D/Interface/MainContentView.m:79: warning: 'NSView' may not respond to '-drawit'


    und bei id folgende warnung:

    /Users/rml/Desktop/Amanda3D/Interface/MainContentView.m:34: warning: assignment from incompatible pointer type
    /Users/rml/Desktop/Amanda3D/Interface/MainContentView.m:35: warning: passing argument 1 of 'addSubview:' from incompatible pointer type
    /Users/rml/Desktop/Amanda3D/Interface/MainContentView.m:36: warning: invalid receiver type 'id*'
    /Users/rml/Desktop/Amanda3D/Interface/MainContentView.m:37: warning: invalid receiver type 'id*'
    /Users/rml/Desktop/Amanda3D/Interface/MainContentView.m:38: warning: invalid receiver type 'id*'
    /Users/rml/Desktop/Amanda3D/Interface/MainContentView.m:78: warning: invalid receiver type 'id*'
    /Users/rml/Desktop/Amanda3D/Interface/MainContentView.m:79: warning: invalid receiver type 'id*'
  • Original von rml
    na, bei NSView kommt diese meldung:

    /Users/rml/Desktop/Amanda3D/Interface/MainContentView.m:36: warning: 'NSView' may not respond to '-initialize'
    /Users/rml/Desktop/Amanda3D/Interface/MainContentView.m:36: warning: (Messages without a matching method signature
    /Users/rml/Desktop/Amanda3D/Interface/MainContentView.m:37: warning: 'NSView' may not respond to '-SetContext'
    /Users/rml/Desktop/Amanda3D/Interface/MainContentView.m:38: warning: 'NSView' may not respond to '-drawit'
    /Users/rml/Desktop/Amanda3D/Interface/MainContentView.m:78: warning: 'NSView' may not respond to '-SetContext'
    /Users/rml/Desktop/Amanda3D/Interface/MainContentView.m:79: warning: 'NSView' may not respond to '-drawit'

    Jepp, weil die Methoden in NSView nicht definiert sind.

    Original von rml
    und bei id folgende warnung:

    /Users/rml/Desktop/Amanda3D/Interface/MainContentView.m:34: warning: assignment from incompatible pointer type
    /Users/rml/Desktop/Amanda3D/Interface/MainContentView.m:35: warning: passing argument 1 of 'addSubview:' from incompatible pointer type
    /Users/rml/Desktop/Amanda3D/Interface/MainContentView.m:36: warning: invalid receiver type 'id*'
    /Users/rml/Desktop/Amanda3D/Interface/MainContentView.m:37: warning: invalid receiver type 'id*'
    /Users/rml/Desktop/Amanda3D/Interface/MainContentView.m:38: warning: invalid receiver type 'id*'
    /Users/rml/Desktop/Amanda3D/Interface/MainContentView.m:78: warning: invalid receiver type 'id*'
    /Users/rml/Desktop/Amanda3D/Interface/MainContentView.m:79: warning: invalid receiver type 'id*'

    Sieht so aus, als würdest Du als Referenz id *bla verwenden. Bei id reicht jedoch id bla aus.
  • Ich meinte freilich: In diesem Falle bringen Castings nichts. Ich wende sie ja auch zuweilen an, etwa bei Ableitungen von NSWindowController.

    Aber was er will, ist schlechtes Design. Und Casting würde das nur "dumm verdecken".

    Kategorien, die hier gerne angeführt werden, sind zu kurz: Sie versprechen die Erweiterung eines bestehenden Objektes. Hier geht es aber nicht darum, etwas bestehendes zu erweitern, sondern lediglich darum, einen Satz von Methoden sichherzustellen. Ob die Basis oder Erweiterung, ererbt oder selbst implemmentiert sind, spielt keine Rolle: Protokolle.

    Aber in seinem Fallle lässt sich das sogar durch eine Superklasse lösen.
    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"?
  • Wie kommt es nur, dass ich heute für das Buch über abstrakte Methoden und Klassen geschrieben habe. ;) Ich habe das wirklich nicht bewusst gemacht!

    Wieso sollten denn die Methoden in der Basisklasse nicht bekannt sein?
    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"?
  • also irgendwie komme ich bei dem versuch mit tom9811 seiner variante einer zwischenklasse nicht ganz klar.
    ich kriege die gleichen warnungen, als wenn ich es auf meine alten variante mit NSView mache.
    liegt es daran, dass keine einzige funktion der einzelnen klasse in einer anderen klasse benötigt wird ?

    bei auto und motorrad scheint es ja zu funktionieren, ich definiere einfach bestimmte funktionen in einer basisklasse, leite diese für motorrad und auto ab und rufe die funktionen ab, die ich in der basisklasse definiert habe.

    aber bei mir habe ich auch etwas wie motorrad und weissbrot. keine der funktionen von motorrad wird auch in weisbrot benötigt und anders herum.... vieleicht stehe ich auch auf der leitung, aber ich krieg nur eine id variante hin. ich habe also keine einheitliche "schnittstelle", über die ich zugreifen könnte, da die klassen absolut keine/wenige gemeinsamkeiten haben...

    ist das tatsächlich schlechter stil ?
  • Original von Tom9811
    Wieso sollten denn die Methoden in der Basisklasse nicht bekannt sein?

    Naja, dies trifft sicherlich nicht für alle Methoden zu, da die Methoden, welche zur Basisklasse passen, also auch in allen abgeleiteten Klassen vorhanden sind, natürlich auch in der Basisklasse definiert sind und somit über eine Referenz dieser Basisklasse ansprechbar sind.

    Da die abgeleiteten Klassen im allgemeinen eine Spezialisierung der Basisklasse darstellen, kann es dort natürlich Methoden geben, welche in den anderen Spezialisierungen nicht benötigt und daher auch nicht vorhanden sind.

    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. :D

    Von daher wird rml die Warnungen also auch nicht los werden, wenn er z.B. versucht die Methode oeffneFahrerTuer über eine Referenz auf die Basisklasse anzusprechen. 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. Die Verwendung von id als Referenzierungstyp ist natürlich auch immer möglich, allerdings wird dann natürlich überhaupt keine sinnvolle Methodenprüfung beim Compile mehr durchgeführt, da die verwendete Methode nur in einer beliebigen Klasse definiert sein muss, welche über den #import bekannt gemacht wurde, also z.B. in einer Klasse LKW, Bus, etc.

    Hm, ich hoffe nur, dass rml jetzt nicht ganz verwirrt ist. 8o
  • 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 ;( ;(

    in etwa der art:

    @interface MCVContainer : NSView {

    int contentType; //Type of the Container Content

    autoklasse *auto;
    motorradklasse *motorrad;
    davon etwa 25 stück....
    }

    funktionen, die mir die korrekte referenz liefert (z.b. auto).
    und anderes....

    @end