<?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[Designfrage]]></title><description><![CDATA[<p>Hallo,</p>
<p>mir ist klar, dass der Titel leider sehr inhaltslos gewählt ist. Allerdings weiß ich nicht, wie mein Problem in ganz kurzen Worten zu beschreiben ist:</p>
<p>Ich habe eine (abstrakte) Basisklasse <code>ABC</code> , von welcher verschiedene Kindklassen erben. Die Instanzen der Kindklassen werden nun in einem <code>std::vector&lt;ABC*&gt;</code> gespeichert (bitte nicht auf &quot;Speicherlöcher&quot; etc. hinweisen. Das dient hier nur dem Verständnis).</p>
<p>Jetzt möchte ich diese Liste durch verschiedene &quot;Darsteller&quot; <code>D</code> jagen, welche dann eine geeignete Repräsentation (z.B. als <code>std::string</code> ) aus dieser Liste erzeugen. <code>D</code> ist dabei wieder eine abstrakte Basisklasse.<br />
Das Problem ist nun: Wenn ich die Implementierung der Darstellung für ein Objekt vom Typ <code>ABC</code> in einer Subklasse von <code>D</code> implementiere, muss ich casten und prüfen, von welchem Typ das Objekt konkret ist:</p>
<pre><code class="language-cpp">std::string create_representation(const std::vector&lt;ABC*&gt;&amp; list) {
  std::stringstream str;

  for (size_t i = 0; i &lt; list.size(); ++i) {
    if (dynamic_cast&lt;ABCSubClass1*&gt;(list[i]))
      str += do_representation(dynamic_cast&lt;SubClass1*&gt;(list[i]));
    else if (...)
      // ...
  }
  return str.str();
}
</code></pre>
<p>(Kurz hingeklatscht, läuft SO vllt. nicht, aber man bekommt die Idee)</p>
<p>Das gefällt mir aber nicht:<br />
1. Man muss viel casten und prüfen, das ist m.M.n. schlecht (und langsam).<br />
2. Wird eine neue Subklasse von <code>ABC</code> dem Projekt hinzugefügt und kann in der Liste auftreten, so müssen ALLE Subklassen von <code>D</code> um diese neue Subklasse erweitert werden. Da passieren schnell Fehler.</p>
<p>Ein alternativer Ansatz wäre es, die Darstellung für eine Subklasse von <code>D</code> direkt in der Subklasse von <code>ABC</code> zu implementieren:</p>
<pre><code class="language-cpp">std::string represent_as_DSubClass1() {
  // ...
}
</code></pre>
<p>Da treten allerdings ähnliche Probleme auf:<br />
1. Wird eine neue Subklasse von <code>D</code> dem Projekt Hinzugefügt, muss ich in allen Subklassen von <code>ABC</code> eine Methode zur Repräsentation für die Subklasse hinzufügen.<br />
2. Die Repräsentation gehört plötzlich zur Subklasse von <code>ABC</code> . Das gehört da aber eigentlich gar nicht hinein!</p>
<p>Meine Frage ist daher: Wie würde man dieses Problem am elegantesten lösen? Leider hängen Erweiterungen beider Klassen voneinander ab (so scheint es mir zumindest), daher sehe ich keine wirklich gute Lösung. Aber vielleicht hat ja jemand schon einmal mit dieser Problematik zu tun gehabt und weiß Rat.</p>
<p>Grüße<br />
- Eulentick</p>
]]></description><link>https://www.c-plusplus.net/forum/topic/292656/designfrage</link><generator>RSS for Node</generator><lastBuildDate>Sun, 16 Aug 2026 18:09:11 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/292656.rss" rel="self" type="application/rss+xml"/><pubDate>Wed, 14 Sep 2011 19:36:40 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Designfrage on Wed, 14 Sep 2011 19:36:40 GMT]]></title><description><![CDATA[<p>Hallo,</p>
<p>mir ist klar, dass der Titel leider sehr inhaltslos gewählt ist. Allerdings weiß ich nicht, wie mein Problem in ganz kurzen Worten zu beschreiben ist:</p>
<p>Ich habe eine (abstrakte) Basisklasse <code>ABC</code> , von welcher verschiedene Kindklassen erben. Die Instanzen der Kindklassen werden nun in einem <code>std::vector&lt;ABC*&gt;</code> gespeichert (bitte nicht auf &quot;Speicherlöcher&quot; etc. hinweisen. Das dient hier nur dem Verständnis).</p>
<p>Jetzt möchte ich diese Liste durch verschiedene &quot;Darsteller&quot; <code>D</code> jagen, welche dann eine geeignete Repräsentation (z.B. als <code>std::string</code> ) aus dieser Liste erzeugen. <code>D</code> ist dabei wieder eine abstrakte Basisklasse.<br />
Das Problem ist nun: Wenn ich die Implementierung der Darstellung für ein Objekt vom Typ <code>ABC</code> in einer Subklasse von <code>D</code> implementiere, muss ich casten und prüfen, von welchem Typ das Objekt konkret ist:</p>
<pre><code class="language-cpp">std::string create_representation(const std::vector&lt;ABC*&gt;&amp; list) {
  std::stringstream str;

  for (size_t i = 0; i &lt; list.size(); ++i) {
    if (dynamic_cast&lt;ABCSubClass1*&gt;(list[i]))
      str += do_representation(dynamic_cast&lt;SubClass1*&gt;(list[i]));
    else if (...)
      // ...
  }
  return str.str();
}
</code></pre>
<p>(Kurz hingeklatscht, läuft SO vllt. nicht, aber man bekommt die Idee)</p>
<p>Das gefällt mir aber nicht:<br />
1. Man muss viel casten und prüfen, das ist m.M.n. schlecht (und langsam).<br />
2. Wird eine neue Subklasse von <code>ABC</code> dem Projekt hinzugefügt und kann in der Liste auftreten, so müssen ALLE Subklassen von <code>D</code> um diese neue Subklasse erweitert werden. Da passieren schnell Fehler.</p>
<p>Ein alternativer Ansatz wäre es, die Darstellung für eine Subklasse von <code>D</code> direkt in der Subklasse von <code>ABC</code> zu implementieren:</p>
<pre><code class="language-cpp">std::string represent_as_DSubClass1() {
  // ...
}
</code></pre>
<p>Da treten allerdings ähnliche Probleme auf:<br />
1. Wird eine neue Subklasse von <code>D</code> dem Projekt Hinzugefügt, muss ich in allen Subklassen von <code>ABC</code> eine Methode zur Repräsentation für die Subklasse hinzufügen.<br />
2. Die Repräsentation gehört plötzlich zur Subklasse von <code>ABC</code> . Das gehört da aber eigentlich gar nicht hinein!</p>
<p>Meine Frage ist daher: Wie würde man dieses Problem am elegantesten lösen? Leider hängen Erweiterungen beider Klassen voneinander ab (so scheint es mir zumindest), daher sehe ich keine wirklich gute Lösung. Aber vielleicht hat ja jemand schon einmal mit dieser Problematik zu tun gehabt und weiß Rat.</p>
<p>Grüße<br />
- Eulentick</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2119464</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2119464</guid><dc:creator><![CDATA[Eulentick]]></dc:creator><pubDate>Wed, 14 Sep 2011 19:36:40 GMT</pubDate></item><item><title><![CDATA[Reply to Designfrage on Wed, 14 Sep 2011 20:05:53 GMT]]></title><description><![CDATA[<p>Das sieht für mich wie nach einem Anwendungsfall für das Visitor-Pattern aus.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2119474</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2119474</guid><dc:creator><![CDATA[314159265358979]]></dc:creator><pubDate>Wed, 14 Sep 2011 20:05:53 GMT</pubDate></item><item><title><![CDATA[Reply to Designfrage on Thu, 15 Sep 2011 08:53:41 GMT]]></title><description><![CDATA[<p>314159265358979 schrieb:</p>
<blockquote>
<p>Das sieht für mich wie nach einem Anwendungsfall für das Visitor-Pattern aus.</p>
</blockquote>
<p>Das Visitor pattern hat er ja schon drin. Das Problem was er hat nennt sich <strong>double dispatch</strong>. -&gt;Google hilft ggf. weiter.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2119594</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2119594</guid><dc:creator><![CDATA[pumuckl]]></dc:creator><pubDate>Thu, 15 Sep 2011 08:53:41 GMT</pubDate></item><item><title><![CDATA[Reply to Designfrage on Thu, 15 Sep 2011 10:03:59 GMT]]></title><description><![CDATA[<p>Wie ich es verstanden habe ist es schon eine Möglichkei für Visitor.</p>
<pre><code class="language-cpp">class Visitor;
class ABC
{
public:
    virtual void Visit(const Visitor&amp; v) const = 0;
};

class A;
class B;

class Visitor
{
public:
    void operator()(const ABC* abc) const
    {
        abc-&gt;Visit(*this);
    }
    virtual void VisitA(const A&amp;) const = 0;
    virtual void VisitB(const B&amp;) const = 0;
};

class A : public ABC
{
public:
    std::string s;
    A(const std::string&amp; text) : s(text){}
    void Visit(const Visitor&amp; v) const
    {
        v.VisitA(*this);
    }
};

class B : public ABC
{
public:
    std::string t;
    B(const std::string&amp; text) : t(text){}
    void Visit(const Visitor&amp; v) const
    {
        v.VisitB(*this);
    }
};

class Printer : public Visitor
{
public:
    void VisitA(const A&amp; a) const
    {
        std::cout &lt;&lt; a.s &lt;&lt; &quot;\n&quot;;
    }

    void VisitB(const B&amp; b) const
    {
        std::cout &lt;&lt; b.t &lt;&lt; &quot;\n&quot;;
    }
};
class ReversePrinter : public Visitor
{
public:
    void VisitA(const A&amp; a) const
    {
        std::copy(a.s.rbegin(), a.s.rend(), 
            std::ostream_iterator&lt;char&gt;(std::cout));
        std::cout &lt;&lt; &quot;\n&quot;;
    }

    void VisitB(const B&amp; b) const
    {
        std::copy(b.t.rbegin(), b.t.rend(), 
            std::ostream_iterator&lt;char&gt;(std::cout));
        std::cout &lt;&lt; &quot;\n&quot;;
    }
};

int main()
{
    std::vector&lt;ABC*&gt; v;
    v.push_back(new A(&quot;hallo&quot;));
    v.push_back(new B(&quot;welt&quot;));

    Printer p;
    ReversePrinter pr;

    std::for_each(v.begin(), v.end(), p);
    std::for_each(v.begin(), v.end(), pr);

    return 0;
}
</code></pre>
<p>Allerdings ist das Visitor Muster nicht besonders beliebt, denn Du hast auch das Problem, dass Du alle Visitor anpassen musst, wenn neue ABC Untertypen dazukommen. Allerdings kannst Du das nciht einfach vergessen, wie in einer dynamic_cast Schleife, da die entsprechenden abstrakte Methoden implementiert werden müssen.</p>
<p>Generell würde ich erstmal vom Visitor abraten. Kann man aber nur sagen, wenn man den genauen Anwendungsfall kennt. Wenn Du Die Darstellung in den Subklassen implementierst könnte es z.B. auch in Richtung Bridge gehen.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2119630</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2119630</guid><dc:creator><![CDATA[brotbernd]]></dc:creator><pubDate>Thu, 15 Sep 2011 10:03:59 GMT</pubDate></item></channel></rss>