<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Verschiedene Klassen durch Vererbung in einem std::vector speichern]]></title><description><![CDATA[<p>Hallo,</p>
<p>Ich bin grade dabei eine kleine Game Engine mit OpenGL zu basteln. Im Grunde will ich erstmal mein OpenGL Programm aus meinem letzten Semester erweitern.</p>
<p>Was ich versucht habe zu implementieren ist ein Standard c++ Vektor:</p>
<pre><code>std::vector&lt; GLObject &gt; glObjects
</code></pre>
<p>GLObject soll eine superklasse für sämtliche Grafikobjekte sein.</p>
<p>Ich habe also noch eine Klasse GLTriangle die von GLObject erbt, aber die render() Methode überschreibt um ein Dreieck anzuzeigen</p>
<pre><code>void GLTriangle::render()
{
	glBegin(GL_POLYGON);
	glColor4fv(this-&gt;color4fv);
	GLfloat hoehe = 1.0f*extent;
	GLfloat c = 1.0f*extent;

	glVertex3f(-(c/2), -(hoehe/2), 0.0f);
	glVertex3f(+(c/2), -(hoehe/2), 0.0f);
	glVertex3f(0.0f, +(hoehe/2), 0.0f);
	glEnd();
}
</code></pre>
<p>Mein Problem ist, das wenn ich durch den Vektor iteriere und alle render() Funktionen aufrufe, nichts auf dem Bildschirm erscheint! vereinfacht:</p>
<pre><code>std::vector&lt; GLObject &gt; glObjects;
GLTriangle test;
glObjects.push_back(test);
glObjects[0].render();
</code></pre>
<p>ändere ich den Vektor zu einem std::vector&lt; GLTriangle &gt; geht wieder alles.<br />
Allerdings will ich ja keinen Vektor für Dreiecke, sonder beliebige Objekte!</p>
<p>GLObject sieht wie folgt aus:</p>
<pre><code>#ifndef GLOBJECT_H
#define GLOBJECT_H

#include &lt;OpenGL/OpenGL.h&gt;

class GLObject
{
public:
	GLObject();
	~GLObject();

	void render();
	void animate();
	void translatef();
	void rotatef();

private:
	GLfloat extent;
	GLfloat color4fv[4];
};

#endif //GLOBJECT_H
</code></pre>
<p>in der cpp habe ich dann alle Methoden leer implementiert</p>
<pre><code>void GLObject::render()
{
}
</code></pre>
<p>da diese sowieso überschrieben werden</p>
<p>Ich nehme an der Fehler beruht auf einem simplen Missverständnis meinerseits, aber ich komme einfach nicht darauf wie ich den Code reparieren könnte.</p>
]]></description><link>https://www.c-plusplus.net/forum/topic/246334/verschiedene-klassen-durch-vererbung-in-einem-std-vector-speichern</link><generator>RSS for Node</generator><lastBuildDate>Fri, 18 Sep 2026 03:31:37 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/246334.rss" rel="self" type="application/rss+xml"/><pubDate>Sun, 26 Jul 2009 20:00:14 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Verschiedene Klassen durch Vererbung in einem std::vector speichern on Sun, 26 Jul 2009 20:00:14 GMT]]></title><description><![CDATA[<p>Hallo,</p>
<p>Ich bin grade dabei eine kleine Game Engine mit OpenGL zu basteln. Im Grunde will ich erstmal mein OpenGL Programm aus meinem letzten Semester erweitern.</p>
<p>Was ich versucht habe zu implementieren ist ein Standard c++ Vektor:</p>
<pre><code>std::vector&lt; GLObject &gt; glObjects
</code></pre>
<p>GLObject soll eine superklasse für sämtliche Grafikobjekte sein.</p>
<p>Ich habe also noch eine Klasse GLTriangle die von GLObject erbt, aber die render() Methode überschreibt um ein Dreieck anzuzeigen</p>
<pre><code>void GLTriangle::render()
{
	glBegin(GL_POLYGON);
	glColor4fv(this-&gt;color4fv);
	GLfloat hoehe = 1.0f*extent;
	GLfloat c = 1.0f*extent;

	glVertex3f(-(c/2), -(hoehe/2), 0.0f);
	glVertex3f(+(c/2), -(hoehe/2), 0.0f);
	glVertex3f(0.0f, +(hoehe/2), 0.0f);
	glEnd();
}
</code></pre>
<p>Mein Problem ist, das wenn ich durch den Vektor iteriere und alle render() Funktionen aufrufe, nichts auf dem Bildschirm erscheint! vereinfacht:</p>
<pre><code>std::vector&lt; GLObject &gt; glObjects;
GLTriangle test;
glObjects.push_back(test);
glObjects[0].render();
</code></pre>
<p>ändere ich den Vektor zu einem std::vector&lt; GLTriangle &gt; geht wieder alles.<br />
Allerdings will ich ja keinen Vektor für Dreiecke, sonder beliebige Objekte!</p>
<p>GLObject sieht wie folgt aus:</p>
<pre><code>#ifndef GLOBJECT_H
#define GLOBJECT_H

#include &lt;OpenGL/OpenGL.h&gt;

class GLObject
{
public:
	GLObject();
	~GLObject();

	void render();
	void animate();
	void translatef();
	void rotatef();

private:
	GLfloat extent;
	GLfloat color4fv[4];
};

#endif //GLOBJECT_H
</code></pre>
<p>in der cpp habe ich dann alle Methoden leer implementiert</p>
<pre><code>void GLObject::render()
{
}
</code></pre>
<p>da diese sowieso überschrieben werden</p>
<p>Ich nehme an der Fehler beruht auf einem simplen Missverständnis meinerseits, aber ich komme einfach nicht darauf wie ich den Code reparieren könnte.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1749970</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1749970</guid><dc:creator><![CDATA[pad01]]></dc:creator><pubDate>Sun, 26 Jul 2009 20:00:14 GMT</pubDate></item><item><title><![CDATA[Reply to Verschiedene Klassen durch Vererbung in einem std::vector speichern on Sun, 26 Jul 2009 20:14:56 GMT]]></title><description><![CDATA[<p>Hi,</p>
<p>Polymorphie funktioniert in deinem Falle nur über Pointer/Referenzen.<br />
Zudem wird eine Funktion nur überschrieben, wenn sie als virtuell deklariert war.</p>
<p>Du hast also eine Basisklasse GLObject mit einer Render-Funktion. Hier kannst du keine allg. Implementierung bereitstellen, da dies die unteren Klassen machen sollen, also deklarierst du render als virtuell, genauer pure virtuell(=0):</p>
<pre><code class="language-cpp">virtuell void render() = 0;
</code></pre>
<p>Mit dieser rein abstrakten Methode wirde deine Klasse auch abstrakt, somit kannst du keine Objekte mehr von dieser erzeugen.</p>
<p>Nun willst du in Abhängigkeit des Types im vector die richtige Funktion aufrufen und genau dazu ist virtuell im Zusammenspiel mit Pointer/Referenzen da:</p>
<pre><code class="language-cpp">GLObject *base = new GLTriangle();
base-&gt;render(); // ruft Triangle::render auf
// ...
base = new GLBlub();
base-&gt;render(); // ruft Blub::render auf
</code></pre>
<p>Somit musst du in deinen vector GLObject*'te stecken, da alle abgeleiteten Klassenzeiger in den Basisklassenzeiger konvertiert werden können (Up-Cast).</p>
<p>Die weiteren Probleme die durch die Zeiger im Container entstehen, seien hier erstmals nicht erwähnt <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f642.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--slightly_smiling_face"
      title=":)"
      alt="🙂"
    /></p>
]]></description><link>https://www.c-plusplus.net/forum/post/1749978</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1749978</guid><dc:creator><![CDATA[[[global:guest]]]]></dc:creator><pubDate>Sun, 26 Jul 2009 20:14:56 GMT</pubDate></item><item><title><![CDATA[Reply to Verschiedene Klassen durch Vererbung in einem std::vector speichern on Sun, 26 Jul 2009 20:37:29 GMT]]></title><description><![CDATA[<p>Nicht zu vergessen: Destruktor entweder virtuell oder protected deklarieren.</p>
<p>Man sollte auch nicht leichtfertig new/delete benutzen und meinen, dass man bei der manuellen Verwaltung der Lebenszeit keine Fehler macht. Es gibt bessere Alternativen -- zB die Boost Pointer Container Library, oder schlaue Zeiger (shared_ptr, clone_ptr).</p>
<p>Es geht möglicherweise auch völlig anders und nicht weniger elegant ohne Laufzeitpolymorhie. Als ich noch in der &quot;von Java nach C++ umsteig&quot;-Phase war, habe ich noch viel zu viele abstrakte Klassen (Interfaces) gebaut, weil das der einzige Abstraktionsmechanismus war, den ich von Java kannte.</p>
<p>Viel Spaß beim C++ proggen!</p>
<p>Gruß,<br />
SP</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1749990</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1749990</guid><dc:creator><![CDATA[Sebastian Pizer]]></dc:creator><pubDate>Sun, 26 Jul 2009 20:37:29 GMT</pubDate></item><item><title><![CDATA[Reply to Verschiedene Klassen durch Vererbung in einem std::vector speichern on Mon, 27 Jul 2009 00:36:19 GMT]]></title><description><![CDATA[<p>Vielen Dank für die Hilfe soweit!</p>
<p>Ich habe jetzt die Sache mit den Virtuellen Methoden hinzugefügt und es geht soweit auch.</p>
<pre><code>this-&gt;glObjectsVector.push_back( new GLDreieck );
this-&gt;glObjectsVector.push_back( new GLViereck );
this-&gt;glObjectsVector.push_back( new GLKuchen );
for( std::vector&lt;GLObject*&gt;::const_iterator it = glObjects.begin();
	it != glObjects.end(); ++it)
{
	(*it)-&gt;render();
}
</code></pre>
<p>Jetzt hab ich ein anderes logisches Problem.<br />
Wenn ich nur Pointer in den Vektor speichere, wo speichere ich dann jeweils das &quot;Original&quot;?</p>
<p>In meinem kleinen Code oben ist das ja kein Problem weil ich die Objekte in einer Klasse erzeuge die eh das komplette Programm über läuft, aber was ist wenn ich mich entschließe in einer anderen temporären Methode ein Objekte zum Vektor hinzuzufügen? dann ist die Methode vorbei und ich hab in meinem Vektor einen Pointer der ins Nirwana zeigt...</p>
<p>Ich hab mir jetzt eine (immer laufende) Speicher-Klasse gebaut in der nochmal ein Vektor ist in der ich die Kopien eines Objekts speichern kann und dann einen Pointer daraus in den glObjectsVector speichere.<br />
Das ganze in der Hoffnung das ich immer überall dynamisch ein Objekt einfügen kann ohne Speicherzugriffs Probleme zu bekommen.</p>
<p>Leider waren meine ersten versuche nicht sehr erfolgreich, da er wieder nur die Funktionen der Superklasse aufruft und nicht die überschriebenen <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f615.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--confused_face"
      title=":-/"
      alt="😕"
    /></p>
<pre><code>GLObject * base = new GLTest;
this-&gt;glObjectsVector.push_back(StorageArea::getInstance()-&gt;addGLObject(base));
</code></pre>
<p>StorageArea.cpp:</p>
<pre><code>static std::vector&lt; GLObject &gt; kopien;
GLObject* StorageArea::addGLObject(GLObject* glOb)
{
	kopien.push_back((*glOb));
	return &amp;kopien[kopien.size()-1];
}
</code></pre>
<p>PS: Bei diesem vorgehen muss ich auch auf die Puren Virtuellen Methoden im GLObject verzichten und habe einfache virtuelle Methoden!</p>
<p>Ich verstehe auch nicht so recht warum es nur mit Pointern und Referenzen funktioniert, wenn ich eine Kopie des Objekts speichere müsste er sich doch auch deren überschriebenen Code merken, und nicht einfach auf die Methoden der Elternklasse zurückgreifen?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1750050</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1750050</guid><dc:creator><![CDATA[pad01]]></dc:creator><pubDate>Mon, 27 Jul 2009 00:36:19 GMT</pubDate></item><item><title><![CDATA[Reply to Verschiedene Klassen durch Vererbung in einem std::vector speichern on Mon, 27 Jul 2009 04:57:15 GMT]]></title><description><![CDATA[<p>pad01 schrieb:</p>
<blockquote>
<p>Ich habe jetzt die Sache mit den Virtuellen Methoden hinzugefügt und es geht soweit auch.</p>
<pre><code>this-&gt;glObjectsVector.push_back( new GLDreieck );
this-&gt;glObjectsVector.push_back( new GLViereck );
this-&gt;glObjectsVector.push_back( new GLKuchen );
for( std::vector&lt;GLObject*&gt;::const_iterator it = glObjects.begin();
	it != glObjects.end(); ++it)
{
	(*it)-&gt;render();
}
</code></pre>
</blockquote>
<p>Du meintest sicherlich <code>(*it).render();</code> .</p>
<p>pad01 schrieb:</p>
<blockquote>
<p>Jetzt hab ich ein anderes logisches Problem.<br />
Wenn ich nur Pointer in den Vektor speichere, wo speichere ich dann jeweils das &quot;Original&quot;?</p>
</blockquote>
<p>siehe meinen Kommentar bzgl Boost Pointer Container, schlauen Zeigern und einer eventuell komplett anderen und nicht weniger eleganten Lösung ohne Polymorhie.</p>
<p>pad01 schrieb:</p>
<blockquote>
<p>In meinem kleinen Code oben ist das ja kein Problem weil ich die Objekte in einer Klasse erzeuge die eh das komplette Programm über läuft, aber was ist wenn ich mich entschließe in einer anderen temporären Methode ein Objekte zum Vektor hinzuzufügen? dann ist die Methode vorbei und ich hab in meinem Vektor einen Pointer der ins Nirwana zeigt...</p>
</blockquote>
<p>Nur, wenn das Objekt ein &quot;automatisches&quot; Objekt war. (Du kennst die drei Speicherklassen &quot;auto&quot;, &quot;Freispeicher&quot; und &quot;statisch&quot;, ja?)</p>
<p>pad01 schrieb:</p>
<blockquote>
<pre><code>GLObject * base = new GLTest;
this-&gt;glObjectsVector.push_back(StorageArea::getInstance()-&gt;addGLObject(base));
</code></pre>
<p>StorageArea.cpp:</p>
<pre><code>static std::vector&lt; GLObject &gt; kopien;
GLObject* StorageArea::addGLObject(GLObject* glOb)
{
	kopien.push_back((*glOb));
	return &amp;kopien[kopien.size()-1];
}
</code></pre>
</blockquote>
<p>Ich glaube, Du hast die Sache mit der Polymorphie und der Indirektion noch nicht 100% verstanden. Dieser Code hat zwei Probleme: Es findet Slicing statt. Die Zeiger, die Du zurückgibst, werden nach einer Vergrößerung des Vektors ggf ungültig.</p>
<p>pad01 schrieb:</p>
<blockquote>
<p>PS: Bei diesem vorgehen muss ich auch auf die Puren Virtuellen Methoden im GLObject verzichten und habe einfache virtuelle Methoden!</p>
</blockquote>
<p>Das habe ich mir gedacht. Dass der Compiler sich beschwert, wenn Du abstrakte Objekte anlegen willst, hätte Dich warnen sollen.</p>
<p>pad01 schrieb:</p>
<blockquote>
<p>Ich verstehe auch nicht so recht warum es nur mit Pointern und Referenzen funktioniert, wenn ich eine Kopie des Objekts speichere müsste er sich doch auch deren überschriebenen Code merken, und nicht einfach auf die Methoden der Elternklasse zurückgreifen?</p>
</blockquote>
<p>Du speicherst aber keine Kopie des Objektes. Der Vektor kennt den dynamischen Typen gar nicht und weiß auch nicht, wie er solche polymorphen Objekte mit unterschiedlichen aber unbekannten Größen korrekt klonen und abspeichern kann. Es findet Slicing statt.</p>
<p>Polymorphie geht nunmal mit Indirektion Hand in Hand. Das ist bei Java auch nicht anders, da in Java Objekte nie direkt gehalten werden können, sondern immer nur über &quot;Referenzen&quot; erreichbar sind.</p>
<p>Gruß,<br />
SP</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1750067</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1750067</guid><dc:creator><![CDATA[Sebastian Pizer]]></dc:creator><pubDate>Mon, 27 Jul 2009 04:57:15 GMT</pubDate></item><item><title><![CDATA[Reply to Verschiedene Klassen durch Vererbung in einem std::vector speichern on Mon, 27 Jul 2009 16:06:10 GMT]]></title><description><![CDATA[<p>Sebastian Pizer schrieb:</p>
<blockquote>
<p>Du meintest sicherlich <code>(*it).render();</code> .</p>
</blockquote>
<p>Nein ist schon richtig so, ich dereferenziere ja erst den iterator und dann den GLObjects pointer.</p>
<blockquote>
<p>siehe meinen Kommentar bzgl Boost Pointer Container, schlauen Zeigern und einer eventuell komplett anderen und nicht weniger eleganten Lösung ohne Polymorhie.</p>
</blockquote>
<p>Ein anderer Weg fällt so direkt nicht ein, bevor ich aber die Idee aufgebe werd ich noch ein paar Verbesserungsversuche starten <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f609.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--winking_face"
      title=";)"
      alt="😉"
    /></p>
<p>Die Boost Smart Pointer habe ich mir mal angesehen, so wie ich das sehe wäre der shared_ptr meine Lösung oder?<br />
Wenn ich alles so richtig verstanden habe dann sorgt der shared pointer dafür das das Objekt so lange im Speicher bleibt wie ein Pointer darauf zeigt.<br />
Also müsste das Konstrukt bei mir dann ungefähr so aussehen (Habs noch nicht getestet, da ich noch kein boost auf dem Rechner habe)</p>
<pre><code>static std::vector&lt; boost::shared_ptr&lt; GLObject &gt; &gt; gloObjectsVector;
hinzufügen()
{
    this-&gt;glObjectsVector.push_back(boost::shared_ptr&lt; GLObject &gt;(new GLTest));
}
ausgeben()
{
    this-&gt;glObjectsVector[0]-&gt;render();
}
</code></pre>
<p>Da der shared pointer im Vektor auch nach der hinzufügen() Funktion weiterhin auf das GLTest Objekt zeigt, sollte das Objekt auch im Speicher bleiben, selbst wenn die hinzufügen() Funktion endet. Somit sollte ich bei der ausgeben() Funktion keine Probleme mit dem Speicherzugriff haben, sehe ich das richtig?</p>
<blockquote>
<p>Du speicherst aber keine Kopie des Objektes. Der Vektor kennt den dynamischen Typen gar nicht und weiß auch nicht, wie er solche polymorphen Objekte mit unterschiedlichen aber unbekannten Größen korrekt klonen und abspeichern kann. Es findet Slicing statt.</p>
</blockquote>
<p>Ah ok, Danke, jetzt versteh ich schon besser was passiert</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1750386</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1750386</guid><dc:creator><![CDATA[pad01]]></dc:creator><pubDate>Mon, 27 Jul 2009 16:06:10 GMT</pubDate></item><item><title><![CDATA[Reply to Verschiedene Klassen durch Vererbung in einem std::vector speichern on Mon, 27 Jul 2009 16:11:29 GMT]]></title><description><![CDATA[<p>Nein, nimm nicht <code>shared_ptr</code> , wenn du nur automatisches Aufräumen willst. Da sind die Boost PointerContainer viel besser geeignet.</p>
<p>Den Smart Pointer <code>shared_ptr</code> braucht man, wenn mehrere Zeiger auf das gleiche Objekt zeigen und nicht genau geregelt ist, wer es freigeben soll (und somit der letzte freigibt). Die ganze Referenzzählung, wodurch dieser Mechanismus implementiert ist, bringt in deinem Beispiel nur unnötigen Overhead mit sich. Mit den Pointer-Containern kannst du ebenfalls Polymorphie einsetzen und hast dabei noch ein freundlicheres Interface (Zeiger werden über Iteratoren direkt dereferenziert), kannst also fast wie mit normalen STL-Containern arbeiten.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1750390</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1750390</guid><dc:creator><![CDATA[Nexus]]></dc:creator><pubDate>Mon, 27 Jul 2009 16:11:29 GMT</pubDate></item><item><title><![CDATA[Reply to Verschiedene Klassen durch Vererbung in einem std::vector speichern on Mon, 27 Jul 2009 20:16:58 GMT]]></title><description><![CDATA[<p>Danke nochmal, ich hab zuerst die shared pointer eingebaut bevor ich hier weitergelesen habe, aber jetzt hab ich es zu einem Pointer Container umgebaut.</p>
<p>Alles läuft jetzt absolut bestens!<br />
Vielen vielen Dank!</p>
<pre><code>static boost::ptr_vector&lt; GLObject &gt; glBoostVector;
</code></pre>
<pre><code>void GLWorld::addObject(GLObject* glOb)
{
	glBoostVector.push_back(glOb);
}
</code></pre>
<pre><code>void GLWorld::init()
{
	GLObject * base = new GLTest;
	GLfloat white[] = {255/255.0f, 255/255.0f, 255/255.0f, 1.0f};
	base-&gt;setColor(white);
	base-&gt;setExtend(5.0f);
	base-&gt;setTranslatef(0, 0, 0);
	base-&gt;setRotatef(90.0f, 0, 0, 1);
	this-&gt;addObject(base);

	this-&gt;addObject(new GLTest);
}
</code></pre>
<pre><code>...boostIter()-&gt;render();
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/1750545</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1750545</guid><dc:creator><![CDATA[pad01]]></dc:creator><pubDate>Mon, 27 Jul 2009 20:16:58 GMT</pubDate></item></channel></rss>