[gelöst] Klassendesign, virtual



  • Hallo,

    folgendes Diagramm:
    http://www.directupload.net/file/d/3658/chbf9hn6_png.htm

    Damit habe ich ein Problem. Und zwar kann ich in der Klasse "Streckenmenge", in dem Vector _strecken nicht den Operator <= von Spiegel- und Glasstrecke aufrufen. Ich dachte jetzt, ich müsste diesen Operator dann in der Klasse "Strecke" virtual und abstrakt deklarieren, um in "Streckenmenge" darauf zugreifen zu können. Das versteht der Compiler aber gar nicht und meckert Syntaxfehler.

    Hat jemand eine Idee bzw. Begründung, wie man das lösen kann bzw. warum es nicht funktioniert?

    Danke,
    Thilo



  • Thilo87 schrieb:

    Ich dachte jetzt, ich müsste diesen Operator dann in der Klasse "Strecke" virtual und abstrakt deklarieren, um in "Streckenmenge" darauf zugreifen zu können.

    Jo. So könnte man das machen.

    Wobei die "schönere" Variante vermutlich wäre den Operator als freie Funktion zu definieren, und dann über virtuelle Memberfunktionen der Klasse Strecke zu implementieren.
    Also z.B.

    inline bool operator <= (Strecke const& lhs, Strecke const& rhs)
    {
        return lhs.GetLength() <= rhs.GetLength();
    }
    

    Das versteht der Compiler aber gar nicht und meckert Syntaxfehler.

    Hat jemand eine Idee bzw. Begründung, wie man das lösen kann bzw. warum es nicht funktioniert?

    Woher sollen wir wissen was du dabei falsch gemacht hast, wenn du den Code nicht herzeigst?

    ps: Bist du sicher die Klasse Lichtstrecke in deinem Diagramm richtig eingezeichnet ist? Sind Spiegelstrecke und Glasstrecke denn keine Lichtstrecke n?


  • Mod

    Hat jemand eine Idee

    Ja. Du machst einen Fehler.

    bzw. Begründung

    Unmöglich. Du sagst uns ja nicht einmal, was falsch ist.

    wie man das lösen kann

    Dazu müsste man genau wissen, was das Programm überhaupt machen soll. Sieht so ein bisschen so aus, als wolltest du mit Gewalt eine komplexe Klassenhierarchie entwerfen, obwohl das in C++ eher unüblich ist.

    warum es nicht funktioniert

    Was soll passieren, wenn der Operator <= für eine Lichtstrecke aufgerufen wird? Programmabsturz? Nein, selbst wenn du die Syntax richtig machst, wird dir der Compiler nie erlauben, eine Lichtstrecke zu erzeugen, wenn diese eine abstrakte Funktion enthält. Es kommt mir auch komisch vor, dass der Operator <= hier eine Memberfunktion ist. Ist das wirklich Absicht, dass der korrekte dynamic dispatch nur bei linksseitigem Aufruf erfolgt?



  • Ich denke, da ist kein syntaktischer Fehler, aber hier:

    #ifndef STRECKE_H
    #define STRECKE_H
    
    #include "Vektor.h"
    #include "Lichtstrecke.h"
    
    #include <iostream>
    using namespace std ;
    
    // benötigt zum Zeichnen
    #include <Windows.h>
    #include <GdiPlus.h>
    using namespace Gdiplus ;
    
    class Strecke
    {
    protected:
    	Vektor _ort ;
    	Vektor _richtung ;
    
    /***  geschützte Konstruktoren  ***/
    
    	// Initialisierungskonstruktor mit Anfangs- und Endpunkt von Objekt
    	Strecke ( Vektor const& anfangspunkt, Vektor const& endpunkt )
    		: _ort( anfangspunkt ),
    		  _richtung( endpunkt - anfangspunkt )
    	{ }
    
    public:
    /***  Rechenmethoden  ***/
    
    	// addiert einen Vektor zu der Strecke, also zum Orts- und Richtungsvektor
    	void operator += ( Vektor const& vek ) ;
    
    	// subtrahiert einen Vektor von der Strecke, also vom Orts- und Richtungsvektor
    	void operator -= ( Vektor const& vek ) ;
    
    /***  Interaktionsmethoden  ***/
    
    	// gibt den Schnittpunkt von Objekt und str zurück
    	Vektor operator & ( Strecke const& str ) const ;
    
    /***  Rechenmethoden  ***/
    
    	// gibt eine ausfallende Lichtstrecke zurück
    	virtual Lichtstrecke operator <= ( Lichtstrecke const& lichtstrecke ) const = 0 ;
    } ;
    
    #endif // STRECKE_H
    
    #ifndef SPIEGELSTRECKE_H
    #define SPIEGELSTRECKE_H
    
    #include "Strecke.h"
    #include "Lichtstrecke.h"
    
    class Spiegelstrecke
    	: public Strecke
    {
    	// Normaleneinheitsvektor zum Objekt
    	Vektor _normalenvektor ;
    
    public:
    /***  öffentliche Konstruktoren  ***/
    	Spiegelstrecke ( Vektor const& anfangspunkt, Vektor const& endpunkt )
    		: Strecke( anfangspunkt, endpunkt )
    	{ }
    
    /***  Rechenmethoden  ***/
    
    	// gibt eine ausfallende Lichtstrecke zurück
    	Lichtstrecke operator <= ( Lichtstrecke const& lichtstrecke ) const ;
    } ;
    
    #endif // SPIEGELSTRECKE_H
    
    #ifndef GLASSTRECKE_H
    #define GLASSTRECKE_H
    
    #include "Strecke.h"
    #include "Lichtstrecke.h"
    
    class Glasstrecke
    	: public Strecke
    {
    	// Brechungsindex vom Objekt
    	double _brechungsindex ;
    
    	// Normalenvektor vom Objekt
    	Vektor _normalenvektor ;
    
    public:
    /***  öffentliche Konstruktoren  ***/
    	Glasstrecke ( Vektor const& anfangspunkt, Vektor const& endpunkt, double brechungsindex )
    		: Strecke( anfangspunkt, endpunkt ),
    		  _brechungsindex( brechungsindex )
    	{ }
    
    /***  Rechenmethoden  ***/
    
    	// gibt eine ausfallende Lichtstrecke zurück
    	Lichtstrecke operator <= ( Lichtstrecke const& lichtstrecke ) const ;
    } ;
    
    #endif // GLASSTRECKE_H
    

    Also wie im Code gibt der Operator <= eine ausfallende Lichtstrecke zurück, z.B. bei

    Lichtstrecke ausfallender = ( glasstrecke <= einfallender ) ;
    

    und ich muss diesen Operator auch in der Klasse "Streckenmenge" aufrufen können. Die Klasse "Lichtstrecke" soll diesen Operator aber nicht haben.



  • 1. operator <= als "Name" für einen Funktion zu verwenden, die nicht "kleiner gleich" implementiert: GANZ schlechte Idee.

    2. Schön, jetzt sehen wir den Code. Wie lautet die Fehlermeldung des Compilers?



  • Wieso? Ist doch intuitiv verständlich, was "gegenstand <= lichtstrahl" bedeutet, nämlich dass der Lichtstrahl auf den Gegenstand trifft 😛

    Das sind die Fehlermeldungen:

    1>c:\users\thilo\documents\visual studio 2010\projects\prog2b\reflexion2\Strecke.h(46): error C2143: Syntaxfehler: Es fehlt ';' vor '<='
    1>c:\users\thilo\documents\visual studio 2010\projects\prog2b\reflexion2\Strecke.h(46): error C2433: 'Strecke::Lichtstrecke': 'virtual' bei der Deklaration von Daten nicht zulässig
    1>c:\users\thilo\documents\visual studio 2010\projects\prog2b\reflexion2\Strecke.h(46): error C4430: Fehlender Typspezifizierer - int wird angenommen. Hinweis: "default-int" wird von C++ nicht unterstützt.
    1>c:\users\thilo\documents\visual studio 2010\projects\prog2b\reflexion2\Strecke.h(46): error C2061: Syntaxfehler: Bezeichner 'Lichtstrecke'
    1>c:\users\thilo\documents\visual studio 2010\projects\prog2b\reflexion2\Strecke.h(46): error C4430: Fehlender Typspezifizierer - int wird angenommen. Hinweis: "default-int" wird von C++ nicht unterstützt.
    1>c:\users\thilo\documents\visual studio 2010\projects\prog2b\reflexion2\Strecke.h(46): error C2805: Binärer Operator '<=' hat zu wenig Parameter
    1>c:\users\thilo\documents\visual studio 2010\projects\prog2b\reflexion2\Strecke.h(46): error C2253: "Strecke::operator <=": Ein reiner Spezifizierer oder ein abstrakter Überschreibungsspezifizierer ist nur für eine virtuelle Funktion zulässig.



  • Und wieder mal ein typischer Cross-Include: Strecke.h und Lichtstrecke.h binden sich gegenseitig ein (auch wenn du Lichtstrecke.h nicht gezeigt hast, aber die Fehler deuten darauf hin)!
    Lösung: Forward declarations

    Aber warum sollen Spiegelstrecke und Glasstrecke den Typ Lichtstrecke überhaupt kennen? Packe wenn überhaupt die Vergleichsoperatoren als freie Funktionen in einen eigenen Header!

    Und

    // benötigt zum Zeichnen
    #include <Windows.h>
    #include <GdiPlus.h>
    using namespace Gdiplus ;
    

    solltest du auch aus dieser Datenklasse verbannen!

    Aber noch schlimmer ist

    using namespace std ;
    

    NIEMALS in Header-Dateien benutzen (da jedes Einbinden dieses Headers dann zum automatischen Auflösen aller Typen aus dem std-Namensraum in den globalen führt -> Konflike vorprogrammiert)!



  • Lösung: Forward declarations

    Das hilft auch nicht. Wenn ich Lichtstrecke in "Strecke.h" vorwärts deklariere, sagt der Compiler, dass Lichtstrecke nicht definiert ist.

    Aber warum sollen Spiegelstrecke und Glasstrecke den Typ Lichtstrecke überhaupt kennen? Packe wenn überhaupt die Vergleichsoperatoren als freie Funktionen in einen eigenen Header!

    Ich möchte aber Zugriff auf die privaten Methoden der Klassen Spiegelstrecke und Glasstrecke haben. Für Berechnungen in dem Operator brauche ich nämlich Brechungsindex, Normalen-, Orts-, Richtungsvektor...

    Ich weiss nicht, vielleicht liege ich mit dem Klassendesign auch total daneben, weswegen es so viele Probleme gibt. Das ist ja mein erstes Projekt, wo ich wirklich von Anfang an auf das Klassendesign achte. Habt ihr eine Idee, wie man das besser gestalten kann?



  • Thilo87 schrieb:

    Wieso? Ist doch intuitiv verständlich, was "gegenstand <= lichtstrahl" bedeutet, nämlich dass der Lichtstrahl auf den Gegenstand trifft 😛

    Tu was du nicht lassen kannst.

    Thilo87 schrieb:

    Lösung: Forward declarations

    Das hilft auch nicht. Wenn ich Lichtstrecke in "Strecke.h" vorwärts deklariere, sagt der Compiler, dass Lichtstrecke nicht definiert ist.

    Doch, das hilft - funktioniert wunderbar. Keine Ahnung was du dabei wieder falsch gemacht hast.
    https://ideone.com/gHflGY



  • Doch, das hilft - funktioniert wunderbar. Keine Ahnung was du dabei wieder falsch gemacht hast.

    Ich auch nicht, aber jetzt klappts.

    Danke für die Hilfe.

    Dann bis zum nächsten Problem 😃


Log in to reply