Methode in anderer Klasse aufrufen



  • Hallo an alle ­čÖé

    Ich habe folgendes Problem:

    Ich habe eine Klasse Display1, die erstellt mir ein OGL Fenster. Darein will ich jetzt ein paar geometrische Figuren zeichnen.
    Dann gibt es eine Klasse Display2, auch da sollen Sachen rein.

    Jetzt wollte ich eine Klasse "Kreise" erstellen, mit einer Methode an welche ich beim Aufruf die Postion, die Farbe, die Winkel f├╝r den Bogen etc. ├╝bergebe. Diese Methode wollte ich dann in den Klassen Display1, Display2... aufrufen. Damit m├╝sste ich den Kreis nur einmal programmieren.

    Ich stolper aber ├╝ber das aufrufen der Kreismethode aus der Kreisklasse in der Displayklasse, denn wenn ich die Methode seperat aufrufe, zeichnet er mir nichts. Ich hab schon diverse Sachen versucht und nachgelesen, aber nichts hat zum Erfolg gef├╝hrt. Langsam verzweifle ich.

    W├Ąre froh ├╝ber eine Hilfestellung. Wer Code haben m├Âchte kann ihn haben, ist aber denke ich atm noch sinnlos, so lange ich noch nichts in der Richtung habe, was funktionieren k├Ânnte.

    Gr├╝├če ­čÖé



  • Erkl├Ąre mal genauer, was der Unterschied zwischen "Methode seperat aufrufen", wo es nicht funktioniert und "Methode nicht seperat aufrufen", wo es funktioniert (?) ist.

    Designm├Ą├čig w├╝rde ich von den Klassen Display1 und Display2 abraten (Was ist denn der Unterschied zwischen Display1 und Display2? Entweder sie tun dasselbe, dann sollte das eine Klasse sein, oder sie tun Unterschiedliches, dann sollten sie auch unterschiedlich hei├čen).
    Nenn das Ding zum Beispiel OGLWindow was eine Liste (vector) von Drawables entgegen nimmt, wobei Drawable eine abstrakte Klasse mit virtueller draw-Methode ist, die von Klasse Kreis ├╝berschrieben wird.

    Weiterhin erscheint mir bei deinem Design nicht sinnvoll das Malen von Kreisen in eine Klassenmethode zu tun, daf├╝r gibt es Funktionen.



  • Hallo erstmal,

    das mit Display1 und Display2 (hei├čen eigtl auch anders) ist nicht auf meinem Mist gewachsen. Das ist teils alter Code, teils von anderen Leuten und halt ein wenig zusammengeschustert. Unterliegt nicht direkt meiner Verantwortung, aber eigentlich hast du recht. Da k├Ânnte ich nochmal nachhaken.

    Bisher sieht die Sache so aus (aufs imo wesentliche reduziert):

    Display1.h

    class Display1 : public Drawable
    {
    public:
    	//Constructor and deconstructor
    	Display1(int DisplayWidth, int DisplayHeight);
    	~Display1();
    
    	//Draw function
    	virtual void draw();	
    };
    

    Display1.cpp

    Display1::Display1(int DisplayWidth, int DisplayHeight)
    {
    }
    
    Display1::~Display1()
    {
    }
    
    void Display1:: draw()
    {
    }
    

    main.cpp

    Display1 d1(800, 800);
    

    Urspr├╝nglich habe ich mit Displaylisten gearbeitet, welche ich in der Drawmethode aufgerufen habe. Aber das ist viel zu aufwendig.

    Versucht hatte ich nun folgendes: Eine Kreisklasse erstellen:

    class Kreis
    {
    public:
    	Kreis (float x, float y, int a, int b);
    	~Kreis (void);
    
    	void draw (float x, float y, int a, int b);
    };
    

    Hierbei sind x, y, a und b die Koordinaten des Kreises und die Winkel des Bogenausschnitts. Dann:

    void Kreis::draw (float x, float y, int a, int b)
    {
    	glTranslatef (x, y, 0);
    	glBegin(GL_LINE_STRIP);
    		for (float i = a; i <= b; i++)
    		{
    			glVertex2f(0.1*sin(i*PI/180),0.1*cos(i*PI/180));
    		}
    	glEnd();
    }
    
    Kreis::Kreis (float x, float y, int a, int b)
    {}
    
    Kreis::~Kreis()
    {}
    

    Und in der main.cpp habe ichs dann so gemacht:

    Kreis *kreis1 = new Kreis(0.5, 0.5, 90, 270);
    kreis1->draw(0.5, 0.5, 90, 270);
    delete kreis1;
    

    Eine versuchsweise in die drawfunction eingebaute Konsolenausgabe krieg ich da auch raus, aber in meinem OGL fenster sehe ich davon nichts. Daher dachte ich, dass der Compiler nicht wei├č, dass er den Kreis in mein Display1 zeichnen soll, woher auch? Mit verschiedenen Vererbungen habe ichs versucht, ergab keine Besserung.

    Was ich jetzt gemacht habe und auch funktioniert, ist dass ich die Drawmethode (dann Kreismethode genannt) in die Display1 Klasse gepackt habe und dann folgendes:

    void Display1:: draw()
    {
    	Display1::Kreis( 0.25, 0.25, 210, 450);
    }
    

    Abgesehen davon, dass ich glaube dass das sehr unsauber ist, ist das auch irgendwie nicht das, was ich will. Denn wenn ich jetzt noch eine Display2 Klasse und eine Display3 Klasse... erstelle, m├╝sste ich auch jedes mal wieder meinen Kreis definieren. Es muss doch auch gehen, indem ich den Kreis nur ein einziges mal definiere, in einer eigenen Klasse (so dachte ichs bisher) und die entsprechende Methode dann innerhalb der Drawmethode des jeweiligen Displays ├Âffne.

    Anders ist es nat├╝rlich jetzt, wenn ich f├╝r die Displays nur insgesamt eine Klasse erstelle, warum sollte das auch nicht gehen. Daran habe ich ehrlich gesagt noch gar nicht gedacht. Dann sollte das auch so funktionieren, oder irre ich da? ­čśĽ



  • Wieso ist Kreis nicht Drawable?

    Kreis *kreis1 = new Kreis(0.5, 0.5, 90, 270);
    kreis1->draw(0.5, 0.5, 90, 270);
    delete kreis1;
    

    O.o
    Erstmal ist ein new/delete-Paar nicht so sinnvoll.

    Kreis kreis1(0.5, 0.5, 90, 270);
    kreis1.draw(0.5, 0.5, 90, 270);
    

    Dann frage ich mich wieso die Parameter doppelt ├╝bergeben werden.
    Entweder:

    Kreis kreis1(0.5, 0.5, 90, 270);
    kreis1.draw();
    

    oder:

    Kreis kreis1;
    kreis1.draw(0.5, 0.5, 90, 270);
    

    Und in diesem Fall, falls kreis1 nicht weiter benutzt wird:

    Kreis(0.5, 0.5, 90, 270).draw();
    

    Vielleicht ist das nur ein Resultat des Code-K├╝rzens, dann ignoriere das.

    Wenn der Compiler was nicht wei├č, dann sagt er das mit einer Fehlermeldung, aber davon hast du nichts gesagt, daher wird der Compiler schon wissen was er tut. Kreis und Display scheinen keinen Zusammenhang zu haben, aber OpenGL hat immer einen aktuellen Kontext in dem die Befehle gelten.

    wglCreateContext(...);
    wglMakeCurrent(...);
    
    kreis(5, 6, 7).draw(); /*Kreis wei├č vom Kontext nichts, aber OpenGL wei├č,
        dass sich glVertexBla in Kreis::draw auf den aktuell definierten Kontext bezieht*/
    

    Ich wei├č auch nicht, was du gegen Listen hast. Ich w├╝rde sowas in der Art machen:

    struct Drawable{
        virtual void draw() const = 0;
        virtual ~Drawable();
    };
    
    struct Kreis : Drawable{
        void draw() const{
            glBegin(...);
            ...
            glEnd();
        }
        float x, y, r;
    };
    
    struct Dreieck : Drawable{
        void draw() const{
            glBegin(...);
            ...
            glEnd();
        }
        Point p1, p2, p3;
    };
    
    void display(const std::vector<const Drawable *> &elements){ //male alles
        glClearDepthBufferBitOderSo();
        for (auto cit = elements.cbegin(); cit != elements.cend(); ++cit)
            (*cit)->draw();
        glSwapBufferOderSo();
    }
    

    Der Grund, warum Kreis::draw nicht ohne Display::draw bei dir funktioniert hat war vielleicht, dass das glClear(Dephtbufferbit) fehlt.



  • Nabend,

    wieso w├╝rdest du das so machen? Oder: Was ist an meiner/deiner Idee nicht so gut, f├╝r jedes Display ein Objekt der Displayklasse erstellen und dann innerhalb der Drawfunction des Displays die Kreismethode oder was auch immer aufzurufen, bspw:

    Display1::Kreis( 0.25, 0.25, 210, 450);
    

    Es funktioniert ja, aber ich wei├č nur nicht, ob das "sauber" ist.

    Gr├╝├če



  • Mahlzeit,

    also, ich glaube ich n├Ąher mich der L├Âsung.

    Ich habe nochmal eine zweite M├Âglichkeit rausgearbeitet, die funktioniert. Was noch fehlt ist ein bisschen Ordnung, aber das d├╝rfte kein Problem mehr erzeugen (Gott, bitte!).

    Also, in der Display1.h:

    class Display1 : public Drawable
    {
    public:
    	//Constructor and deconstructor
    	Display1(int DisplayWidth, int DisplayHeight);
    	~Display1();
    
    	//Draw function
    	virtual void draw();	
    };
    
    class Kreis
    {
    public:
    	Kreis ();
    	~Kreis ();
    
    	void draw (float x, float y, int a, int b);
    };
    

    Die class Kreis w├╝rde ich dann in eine eigene Headerdatei packen, zusammen mit Vierecken, Strichen, Dreiecken und was sonst noch kommt und in Display1.cpp inkludieren.

    In der Display1.cpp:

    Display1::Display1(int DisplayWidth, int DisplayHeight):
    {
    }
    
    Display1::~Display1()
    {
    }
    
    void Display1:: draw()
    {
    	Kreis kreis1;
    	kreis1.draw(0.5, 0.5, 90, 270);
    }
    
    void Kreis::draw (float x, float y, int a, int b)
    {
    	//OpenGL zeugs
    }
    
    Kreis::Kreis ()
    {
    }
    
    Kreis::~Kreis()
    {
    }
    

    In der main.cpp wird nur noch das Display erstellt:

    Display1 d1(800, 800);
    

    Was sagt ihr dazu? Besser als meine vorhergegangen L├Âsung, oder? So brauch ich wirklich nur einmal einen Kreis erstellen und gebe dann Position, Winkel und was vllt noch kommt an und tjo, der Kreis wird tats├Ąchlich gezeichnet.

    Ich versteh gar nicht, wieso ich da vorher nicht drauf gekommen bin, ich hab unversch├Ąmt viel rumprobiert ­čśí

    Meinungen? ­čśâ



  • Der Grund f├╝r meine L├Âsung ist, dass Display1 nicht wissen muss was ein Kreis ist. Bei dir schon. Bei dir musst du die gesamte Grafik in in Display1::Draw rein tun, das wird irgendwann eine Monsterfunktion. Vektoren von Objekten, insbesondere wenn du sowas wie Hintergrund-, Normal- und Vordergrundobjekte hast lassen sich so einfacher ordnen und sind leicht erweiterbar.

    Weiterhin verstehe ich nicht, wieso du eine Klasse Kreis hast. Nimm die Klasse weg und mach aus Kreis::draw(float x, float y, int a, int b) drawKreis(float x, float y, int a, int b) und lass das Objekt weg, das benutzt du ja nicht.

    Dass du die Parameter nicht in draw, sondern im Konstruktor ├╝bergeben solltest hatte ich ja schon erw├Ąhnt, dann k├Ânnte man einen zweiten Konstruktor Kreis(float x, float y, float r) erstellen und dann h├Ątte die Kreisklasse mehr Sinn als nur ein Namespace zu sein.


Log in to reply