<?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[Virtual Functions - Code-Duplizierung vermeiden]]></title><description><![CDATA[<p>Hi,</p>
<p>ich wollte eine Klassenhierarchie erstellen die Bounding Volumes umfasst um mit diesen dann Schnitttests durchzuführen. Die Methoden für die Schnitttests untereinander wollte ich gern in die Unterklassen packen, nur bin ich dabei auf ein Entwurfs-Problem gestoßen bei dem mir keine richtig schöne Lösung einfällt.<br />
Bei der Suche nach verwandten Problemen bin ich leider auch nicht fündig geworden, drum der Post hier.</p>
<p>Das Szenario sieht folgendermaßen aus:</p>
<pre><code class="language-cpp">class BVolume{
  ...
  virtual bool intersect(BVolume *opponent) = 0;
}

class OBB : BVolume{
  ...
}

class BSphere : BVolume{
  ...
}

class AABB : BVolume{
  ...
}
</code></pre>
<p>Was ich brauche ist die Implementierung der &quot;intersect&quot;-Funktion mit allen möglichen Permutationen der einzelnen Bounding-Volume-Unterklassen <strong>ohne</strong> dabei Code zu <strong>duplizieren</strong>.<br />
Also OBB&lt;-&gt;OBB, OBB&lt;-&gt;BSphere, OBB&lt;-&gt;AABB, BSphere&lt;-&gt;BSphere, BSphere&lt;-&gt;AABB, AABB&lt;-&gt;AABB. Die Schnitttests für alle diese Kombinationen müssen implementiert werden. Ich finde einfach keine Möglichkeit die Implementierungen so zu verteilen, dass ich sie nicht 3-fach in allen 3 Unterklassen stehen hab.</p>
<p>Ich möchte die Funktion deswegen gern auf die Unterklassen verteilen, weil ich an einer anderen Stelle diverse Listen durchlaufe die BVolumes speichern und ich dann mit einem einzigen Aufruf den Schnitt untereinander durch die dynamische Typprüfung zur Laufzeit durchführen könnte.</p>
<p>Derzeit hab ich die intersect-Funktion komplett aus der Klassenhierarchie ausgelagert und mit den verschiedenen Unterklassen als Parameter überladen:</p>
<pre><code class="language-cpp">bool intersect(OBB*,OBB*);
bool intersect(OBB*,BSphere*);
bool intersect(OBB*,AABB*);
bool intersect(BSphere*,BSphere*);
bool intersect(BSphere*,AABB*)
bool intersect(AABB*,AABB*);
</code></pre>
<p>Das gefällt mir aber eigentlich gar nicht, weil ich dadurch extra eine Variable in der Oberklasse einführen musste die mir den Typ speichert. Mit Hilfe der Variable muss ich bis jetzt beim Durchlaufen der BVolumes in der Liste eine hässliche If-Kaskade durchlaufen, bevor ich die richtige Methode für den Schnitttest aufrufen kann. Außerdem sind diverse Downcasts nötig die ich auch gern vermeiden würde.</p>
<p>Hat irgendwer nen Tipp für mich wie ich die intersect-Methode wie gewollt in die Unterklassen einbauen kann um einen Schnitttest mittels Typprüfung zur Laufzeit zu erlauben?<br />
Templates wären mir auch recht, wenn dabei eine äquivalente Lösung zustande käme.</p>
<p>Danke schonmal im Voraus fürs grübeln.</p>
]]></description><link>https://www.c-plusplus.net/forum/topic/302703/virtual-functions-code-duplizierung-vermeiden</link><generator>RSS for Node</generator><lastBuildDate>Tue, 11 Aug 2026 05:47:17 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/302703.rss" rel="self" type="application/rss+xml"/><pubDate>Tue, 24 Apr 2012 23:00:16 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Virtual Functions - Code-Duplizierung vermeiden on Tue, 24 Apr 2012 23:00:16 GMT]]></title><description><![CDATA[<p>Hi,</p>
<p>ich wollte eine Klassenhierarchie erstellen die Bounding Volumes umfasst um mit diesen dann Schnitttests durchzuführen. Die Methoden für die Schnitttests untereinander wollte ich gern in die Unterklassen packen, nur bin ich dabei auf ein Entwurfs-Problem gestoßen bei dem mir keine richtig schöne Lösung einfällt.<br />
Bei der Suche nach verwandten Problemen bin ich leider auch nicht fündig geworden, drum der Post hier.</p>
<p>Das Szenario sieht folgendermaßen aus:</p>
<pre><code class="language-cpp">class BVolume{
  ...
  virtual bool intersect(BVolume *opponent) = 0;
}

class OBB : BVolume{
  ...
}

class BSphere : BVolume{
  ...
}

class AABB : BVolume{
  ...
}
</code></pre>
<p>Was ich brauche ist die Implementierung der &quot;intersect&quot;-Funktion mit allen möglichen Permutationen der einzelnen Bounding-Volume-Unterklassen <strong>ohne</strong> dabei Code zu <strong>duplizieren</strong>.<br />
Also OBB&lt;-&gt;OBB, OBB&lt;-&gt;BSphere, OBB&lt;-&gt;AABB, BSphere&lt;-&gt;BSphere, BSphere&lt;-&gt;AABB, AABB&lt;-&gt;AABB. Die Schnitttests für alle diese Kombinationen müssen implementiert werden. Ich finde einfach keine Möglichkeit die Implementierungen so zu verteilen, dass ich sie nicht 3-fach in allen 3 Unterklassen stehen hab.</p>
<p>Ich möchte die Funktion deswegen gern auf die Unterklassen verteilen, weil ich an einer anderen Stelle diverse Listen durchlaufe die BVolumes speichern und ich dann mit einem einzigen Aufruf den Schnitt untereinander durch die dynamische Typprüfung zur Laufzeit durchführen könnte.</p>
<p>Derzeit hab ich die intersect-Funktion komplett aus der Klassenhierarchie ausgelagert und mit den verschiedenen Unterklassen als Parameter überladen:</p>
<pre><code class="language-cpp">bool intersect(OBB*,OBB*);
bool intersect(OBB*,BSphere*);
bool intersect(OBB*,AABB*);
bool intersect(BSphere*,BSphere*);
bool intersect(BSphere*,AABB*)
bool intersect(AABB*,AABB*);
</code></pre>
<p>Das gefällt mir aber eigentlich gar nicht, weil ich dadurch extra eine Variable in der Oberklasse einführen musste die mir den Typ speichert. Mit Hilfe der Variable muss ich bis jetzt beim Durchlaufen der BVolumes in der Liste eine hässliche If-Kaskade durchlaufen, bevor ich die richtige Methode für den Schnitttest aufrufen kann. Außerdem sind diverse Downcasts nötig die ich auch gern vermeiden würde.</p>
<p>Hat irgendwer nen Tipp für mich wie ich die intersect-Methode wie gewollt in die Unterklassen einbauen kann um einen Schnitttest mittels Typprüfung zur Laufzeit zu erlauben?<br />
Templates wären mir auch recht, wenn dabei eine äquivalente Lösung zustande käme.</p>
<p>Danke schonmal im Voraus fürs grübeln.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2205384</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2205384</guid><dc:creator><![CDATA[Wega]]></dc:creator><pubDate>Tue, 24 Apr 2012 23:00:16 GMT</pubDate></item><item><title><![CDATA[Reply to Virtual Functions - Code-Duplizierung vermeiden on Tue, 24 Apr 2012 23:33:13 GMT]]></title><description><![CDATA[<p>Dafür brauchst du &quot;multiple dispatch&quot; - bzw. genauer: &quot;double dispatch&quot;.</p>
<p>C++ kann das von sich aus nicht, aber man kann es mit zwei normalen virtual Function Calls nachbilden:</p>
<pre><code class="language-cpp">bool intersect(OBB*,OBB*); 
bool intersect(OBB*,BSphere*); 
bool intersect(OBB*,AABB*); 
bool intersect(BSphere*,BSphere*); 
bool intersect(BSphere*,AABB*) 
bool intersect(AABB*,AABB*);

class OBB;
class BSphere;
class AABB;

class BVolume { 
   ... 
   virtual bool intersect(BVolume *opponent) = 0;
   virtual bool intersect(OBB *opponent) = 0;
   virtual bool intersect(BSphere *opponent) = 0;
   virtual bool intersect(AABB *opponent) = 0;
} 

inline bool intersect(BVolume* a, BVolume* b) {
    return a-&gt;intersect(b); // Dispatch by type of first object (a)
}

class OBB : BVolume {
   virtual bool intersect(BVolume *opponent) {
       return opponent-&gt;intersect(this); // Dispatch by type of second object (opponent aka. b)
   }

   virtual bool intersect(OBB *opponent) {
       return intersect(this, opponent); // Call suitable overload of free intersect() function
   }

   virtual bool intersect(BSphere *opponent) {
       return intersect(this, opponent); // ...
   }

   virtual bool intersect(AABB *opponent) {
       return intersect(this, opponent); // ...
   }
} 

class BSphere : BVolume {
   virtual bool intersect(BVolume *opponent) {
       return opponent-&gt;intersect(this); // Dispatch by type of second object (opponent aka. b)
   }

   virtual bool intersect(OBB *opponent) {
       return intersect(opponent, this);
   }

   virtual bool intersect(BSphere *opponent) {
       return intersect(this, opponent);
   }

   virtual bool intersect(AABB *opponent) {
       return intersect(this, opponent);
   }
} 

class AABB : BVolume {
   virtual bool intersect(BVolume *opponent) {
       return opponent-&gt;intersect(this); // Dispatch by type of second object (opponent aka. b)
   }

   virtual bool intersect(OBB *opponent) {
       return intersect(opponent, this);
   }

   virtual bool intersect(BSphere *opponent) {
       return intersect(opponent, this);
   }

   virtual bool intersect(AABB *opponent) {
       return intersect(this, opponent);
   }
}
</code></pre>
<p>Das gewinnt jetzt keinen Schönheitswettbewerb, aber es funktioniert.</p>
<p>Könnte aber leicht sein dass du mit der Typ-Variable schneller bist. Die if-Kaskade könnte man durch ein Array mit Funktionszeigern ersetzen. Dann rechnest du einfach <code>index = type1 * numberOfTypes + type2</code> und rufst darüber die passende Funktion auf. Das ist dann ein indirekter Aufruf statt zwei, also vermutlich ne Spur schneller.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2205387</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2205387</guid><dc:creator><![CDATA[hustbaer]]></dc:creator><pubDate>Tue, 24 Apr 2012 23:33:13 GMT</pubDate></item></channel></rss>