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.


Anmelden zum Antworten