<?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[Polymorphes erkennen von Basisklassen; Struktur ähnlich boost::any]]></title><description><![CDATA[<p>Ich wusste leider nicht, wie ich den Titel aussagekräftiger hätte gestalten sollen. Ich denke, ein Stück Code erklärt mehr als tausend Worte.</p>
<p>Im Groben geht es darum, für einen zur Compilierzeit bekannten Typ herauszufinden, ob er von einem anderen Typ abgeleitet ist. Ist das der Fall, soll eine Methode dieses anderen Typs aufgerufen werden. Der andere Typ liegt aber zu dem Zeitpunkt schon in einer virtuellen Klasse als type_info Objekt vor, da ich diese Information als Tabelle anlegen will. Diese Tabelle ist eigentlich eine Map, die einen Namen (als String) dieser Information gegenüberstellt, das wurde aber fürs Beispiel weggelassen.</p>
<p>Der relevante Code:</p>
<pre><code class="language-cpp">#include &lt;typeinfo&gt;

namespace detail {

    struct InfoImpl
    {
        virtual ~InfoImpl() {}
        virtual std::type_info const&amp; Type() const = 0;
    };

    template&lt; typename Class &gt;
    struct InfoImplClass : public InfoImpl
    {
        InfoImplClass( void (Class::*func)() ) {}

        void Apply( Class* object )
        {
            // hier wird die im Ctor übergebene Methode aufgerufen
            std::cout &lt;&lt; &quot;Apply()&quot; &lt;&lt; std::endl;
        }

        virtual std::type_info const&amp; Type() const { return typeid( Class ); }
    };

} // namespace detail

class Info
{
public:
    template&lt; typename Class &gt;
    Info( std::string const&amp; name, void (Class::*func)() ) 
        : m_name( name )
        , m_impl( new detail::InfoImplClass&lt; Class &gt;( func ) ) {}

    std::string const&amp; Name() const { return m_name; }

    template&lt; typename Class &gt;
    void Apply( Class* object )
    {
        if ( m_impl-&gt;Type() == typeid( Class ) ) {
            static_cast&lt; detail::InfoImplClass&lt; Class &gt;* &gt;( m_impl )-&gt;Apply( object );
        }
    }

private:
    std::string m_name;
    detail::InfoImpl* m_impl;
};
</code></pre>
<p>Beispielprogramm:</p>
<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;functional&gt;

struct Control
{
    void SetWidth() { std::cout &lt;&lt; &quot;SetWidth&quot; &lt;&lt; std::endl; }
};

struct Label : public ControlWithLabel
{
    void SetText() { std::cout &lt;&lt; &quot;SetText&quot; &lt;&lt; std::endl; }
};

struct CheckBox : public ControlWithLabel
{
    void SetChecked() { std::cout &lt;&lt; &quot;SetChecked&quot; &lt;&lt; std::endl; }
};

int main()
{
    Info infos[] = {
        Info( &quot;width&quot;, &amp;Control::SetWidth ),
        Info( &quot;value&quot;, &amp;Label::SetText ),
        Info( &quot;value&quot;, &amp;CheckBox::SetChecked )
    };

    // Eingaben aus z.B. einer Datei 
    std::string name1 = &quot;value&quot;, value1 = &quot;true&quot;;
    std::string name2 = &quot;width&quot;, value2 = &quot;120&quot;;

    CheckBox cb;
    for ( Info* i = infos ; i != infos + 3 ; ++i ) {
        if ( i-&gt;Name() == name1 ) {
            i-&gt;Apply( &amp;cb );
        }
        else if ( i-&gt;Name() == name2 ) {
            i-&gt;Apply( &amp;cb );
        }
    }
}
</code></pre>
<p>Das Beispielprogramm soll &quot;SetChecked&quot; und &quot;SetWidth&quot; ausgeben. Für ein Label sollte das gleiche Beispielprogramm &quot;SetLabel&quot; und &quot;SetWidth&quot; ausgeben. Die gezeigte Implementierung zeigt natürlich nur einmal &quot;SetChecked&quot; an, wegen des Typvergleichs.</p>
<p>Hintergrund ist, dass ich viele Controls in einer Vererbungsstruktur habe, deren Eigenschaften aus einer Datei eingelesen werden sollen. Dabei können Eigenschaften auf alle Controls (z.B. &quot;width&quot;) auftreten, andere Eigenschaften haben bei unterschiedlichen Controls unterschiedliche Bedeutungen (wie &quot;value&quot;). Erschwerend kommt hinzu, dass in dieser Tabelle auch Typen stehen können, die nicht miteinander verwandt sind, sonst könnte ich den Templates die gemeinsame Basisklasse als Parametertyp von Apply() mitgeben und einen dynamic_cast probieren.</p>
<p>Gibt es eine Möglichkeit, in Info::Apply festzustellen, ob m_impl-&gt;Type() eine Basis von Class ist? Sieht jemand eine Alternative, die ich übersehe? Die notwendigen Informationen müssten m.E. alle zur Compilezeit vorliegen...</p>
]]></description><link>https://www.c-plusplus.net/forum/topic/220251/polymorphes-erkennen-von-basisklassen-struktur-ähnlich-boost-any</link><generator>RSS for Node</generator><lastBuildDate>Wed, 07 Oct 2026 11:58:06 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/220251.rss" rel="self" type="application/rss+xml"/><pubDate>Wed, 13 Aug 2008 15:22:20 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Polymorphes erkennen von Basisklassen; Struktur ähnlich boost::any on Thu, 14 Aug 2008 06:31:55 GMT]]></title><description><![CDATA[<p>Ich wusste leider nicht, wie ich den Titel aussagekräftiger hätte gestalten sollen. Ich denke, ein Stück Code erklärt mehr als tausend Worte.</p>
<p>Im Groben geht es darum, für einen zur Compilierzeit bekannten Typ herauszufinden, ob er von einem anderen Typ abgeleitet ist. Ist das der Fall, soll eine Methode dieses anderen Typs aufgerufen werden. Der andere Typ liegt aber zu dem Zeitpunkt schon in einer virtuellen Klasse als type_info Objekt vor, da ich diese Information als Tabelle anlegen will. Diese Tabelle ist eigentlich eine Map, die einen Namen (als String) dieser Information gegenüberstellt, das wurde aber fürs Beispiel weggelassen.</p>
<p>Der relevante Code:</p>
<pre><code class="language-cpp">#include &lt;typeinfo&gt;

namespace detail {

    struct InfoImpl
    {
        virtual ~InfoImpl() {}
        virtual std::type_info const&amp; Type() const = 0;
    };

    template&lt; typename Class &gt;
    struct InfoImplClass : public InfoImpl
    {
        InfoImplClass( void (Class::*func)() ) {}

        void Apply( Class* object )
        {
            // hier wird die im Ctor übergebene Methode aufgerufen
            std::cout &lt;&lt; &quot;Apply()&quot; &lt;&lt; std::endl;
        }

        virtual std::type_info const&amp; Type() const { return typeid( Class ); }
    };

} // namespace detail

class Info
{
public:
    template&lt; typename Class &gt;
    Info( std::string const&amp; name, void (Class::*func)() ) 
        : m_name( name )
        , m_impl( new detail::InfoImplClass&lt; Class &gt;( func ) ) {}

    std::string const&amp; Name() const { return m_name; }

    template&lt; typename Class &gt;
    void Apply( Class* object )
    {
        if ( m_impl-&gt;Type() == typeid( Class ) ) {
            static_cast&lt; detail::InfoImplClass&lt; Class &gt;* &gt;( m_impl )-&gt;Apply( object );
        }
    }

private:
    std::string m_name;
    detail::InfoImpl* m_impl;
};
</code></pre>
<p>Beispielprogramm:</p>
<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;functional&gt;

struct Control
{
    void SetWidth() { std::cout &lt;&lt; &quot;SetWidth&quot; &lt;&lt; std::endl; }
};

struct Label : public ControlWithLabel
{
    void SetText() { std::cout &lt;&lt; &quot;SetText&quot; &lt;&lt; std::endl; }
};

struct CheckBox : public ControlWithLabel
{
    void SetChecked() { std::cout &lt;&lt; &quot;SetChecked&quot; &lt;&lt; std::endl; }
};

int main()
{
    Info infos[] = {
        Info( &quot;width&quot;, &amp;Control::SetWidth ),
        Info( &quot;value&quot;, &amp;Label::SetText ),
        Info( &quot;value&quot;, &amp;CheckBox::SetChecked )
    };

    // Eingaben aus z.B. einer Datei 
    std::string name1 = &quot;value&quot;, value1 = &quot;true&quot;;
    std::string name2 = &quot;width&quot;, value2 = &quot;120&quot;;

    CheckBox cb;
    for ( Info* i = infos ; i != infos + 3 ; ++i ) {
        if ( i-&gt;Name() == name1 ) {
            i-&gt;Apply( &amp;cb );
        }
        else if ( i-&gt;Name() == name2 ) {
            i-&gt;Apply( &amp;cb );
        }
    }
}
</code></pre>
<p>Das Beispielprogramm soll &quot;SetChecked&quot; und &quot;SetWidth&quot; ausgeben. Für ein Label sollte das gleiche Beispielprogramm &quot;SetLabel&quot; und &quot;SetWidth&quot; ausgeben. Die gezeigte Implementierung zeigt natürlich nur einmal &quot;SetChecked&quot; an, wegen des Typvergleichs.</p>
<p>Hintergrund ist, dass ich viele Controls in einer Vererbungsstruktur habe, deren Eigenschaften aus einer Datei eingelesen werden sollen. Dabei können Eigenschaften auf alle Controls (z.B. &quot;width&quot;) auftreten, andere Eigenschaften haben bei unterschiedlichen Controls unterschiedliche Bedeutungen (wie &quot;value&quot;). Erschwerend kommt hinzu, dass in dieser Tabelle auch Typen stehen können, die nicht miteinander verwandt sind, sonst könnte ich den Templates die gemeinsame Basisklasse als Parametertyp von Apply() mitgeben und einen dynamic_cast probieren.</p>
<p>Gibt es eine Möglichkeit, in Info::Apply festzustellen, ob m_impl-&gt;Type() eine Basis von Class ist? Sieht jemand eine Alternative, die ich übersehe? Die notwendigen Informationen müssten m.E. alle zur Compilezeit vorliegen...</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1564182</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1564182</guid><dc:creator><![CDATA[LordJaxom]]></dc:creator><pubDate>Thu, 14 Aug 2008 06:31:55 GMT</pubDate></item><item><title><![CDATA[Reply to Polymorphes erkennen von Basisklassen; Struktur ähnlich boost::any on Wed, 13 Aug 2008 15:28:13 GMT]]></title><description><![CDATA[<p>schau dir mal boost::type_traits an.</p>
<p>Im Prinzip reicht dir aber normale Funktionsüberladung, denke ich.</p>
<p>Oder willst du das ganze wirklich erst zur Laufzeit zusammen bauen? Dann wird es sehr sehr häßlich...</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1564192</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1564192</guid><dc:creator><![CDATA[Shade Of Mine]]></dc:creator><pubDate>Wed, 13 Aug 2008 15:28:13 GMT</pubDate></item><item><title><![CDATA[Reply to Polymorphes erkennen von Basisklassen; Struktur ähnlich boost::any on Thu, 14 Aug 2008 06:12:28 GMT]]></title><description><![CDATA[<p>Über type_traits habe ich auch schon länger gegrübelt, das Problem ist, dass ich in InfoImpl ja nur den Typ kenne, mit dem instanziert wurde, nicht den Typ, mit dem aufgerufen wird. Sonst wäre das ja kein Problem.</p>
<p>Inwiefern kann mir Funktionsüberladung helfen? (Vielleicht denke ich zu kompliziert :)).</p>
<p>Ich habe das Beispielprogramm mal etwas geändert und einen Abschnitt ergänzt, vielleicht wird dann klarer, was ich möchte. Ich vermute so langsam, ich denke wirklich zu kompliziert.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1564425</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1564425</guid><dc:creator><![CDATA[LordJaxom]]></dc:creator><pubDate>Thu, 14 Aug 2008 06:12:28 GMT</pubDate></item><item><title><![CDATA[Reply to Polymorphes erkennen von Basisklassen; Struktur ähnlich boost::any on Thu, 14 Aug 2008 08:20:07 GMT]]></title><description><![CDATA[<p>LordJaxom schrieb:</p>
<blockquote>
<p>Die notwendigen Informationen müssten m.E. alle zur Compilezeit vorliegen...</p>
</blockquote>
<p>Sehe ich auch so. Ich habe auch lange über dieses Problem (DoubleDispatch mit Erkennung von Vererbung) gegrübelt, eine Lösung dazu ist mir allerdings nicht eingefallen.</p>
<p>Die einzige Idee, die mir überhaupt einfallen würde, wäre die beteiligten Klassen zu modifizieren (was im Falle einer vorgegebenen GUI-Bibliothek i.a. nicht möglich ist).</p>
<p>Eine Möglichkeit wäre dann noch, eine parallele Klassenhierarchie aufzuziehen, aber auch das ist normalerweise Overkill und wider dem Konzept, da man das ja genau dafür baut um nicht alle beteiligten Klassen zu benennen oder überhaupt kennen zu müssen. <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f61e.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--disappointed_face"
      title=":("
      alt="😞"
    /></p>
]]></description><link>https://www.c-plusplus.net/forum/post/1564428</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1564428</guid><dc:creator><![CDATA[7H3 N4C3R]]></dc:creator><pubDate>Thu, 14 Aug 2008 08:20:07 GMT</pubDate></item><item><title><![CDATA[Reply to Polymorphes erkennen von Basisklassen; Struktur ähnlich boost::any on Thu, 14 Aug 2008 09:56:40 GMT]]></title><description><![CDATA[<p>Nochmal ein Nachtrag:</p>
<p>Falls es dir selber nicht klar sein sollte - was du hier willst und brauchst (für die völlig allgemeine Eierlegendewollmilschau-Lösung) ist ein Double-Dispatch mit Erkennung von Vererbungsbeziehungen und ohne gemeinsame Basisklasse, also der schwierigste überhaupt mögliche Fall.</p>
<p>Im Prinzip soll ja folgendes passieren:<br />
dispatch( Control, Value)<br />
-&gt;<br />
functor mit Kenntnis der konkreten Methode( Control, Value) (Control-&gt;*Methode)( Value)</p>
<p>Ich stand vor einem ähnlichen Problem. Bei mir haben nun Control und Value jeweils eine gemeinsame Basisklasse.</p>
<p>Das Vererbungsproblem konnte ich nicht lösen - stattdessen habe ich einen &quot;Forward-Funktor&quot; eingerichtet, bei dem ich alle beteiligten Klassen zusammen mit der minimal benötigten Basisklasse (also die, die die Methode unterstützt) registriere.<br />
Dadurch muss ich zwar alle konkreten Controls benennen (die Anzahl ist überschaubar), habe aber nur eine konkrete Basisklasse zur Implementierung.</p>
<p>Einen Double-Dispatcher mit Funktoren und dem automatischen dynamic_casten auf den konkreten Typ kannst du dir in Loki bzw. Modern C++ Design abgucken.</p>
<p>Zu dem Problem mit den nicht-verwandten Klassen, insbesondere der Values, wenn es z.B. triviale Klassen bzw. integrale Typen sind, habe ich mal über folgendes zumindest nachgedacht (keine Ahnung, ob es funktioniert, bzw. es war nicht zuende gedacht):<br />
Jeder Value wird per Template-Kapselung von einer gemeinsamen Value-Basisklasse abgeleitet. Diese ist in der Lage, Values korrekt ein- und wieder auszupacken. Sowohl beim registrieren als auch beim Dispatch müssen dann aber die konkreten Typen bekannt sein. Das kann auf jeden Fall beim Dispatch wieder nachteilig sein.</p>
<p>Ansonsten musst du wohl darüber nachdenken, bei deinem Design Abstriche zu machen. Alternativ könnte es noch von deiner konkreten GUI-Bibliothek abhängen. Vielleicht bietet diese wiederum spezielle Möglichkeiten für deine Zwecke, auch wenn die Lösung dann nicht mehr 100% allgemein wäre.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1564565</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1564565</guid><dc:creator><![CDATA[7H3 N4C3R]]></dc:creator><pubDate>Thu, 14 Aug 2008 09:56:40 GMT</pubDate></item><item><title><![CDATA[Reply to Polymorphes erkennen von Basisklassen; Struktur ähnlich boost::any on Thu, 14 Aug 2008 09:53:38 GMT]]></title><description><![CDATA[<p>Bisher implementierst du deine Info-Liste ja als ein (großes) Array.</p>
<p>Du solltest einfach die Infos genauso hierarchisch anordnen wie die echten Klassen, d.h. hierarchisch. Nun kannst du einfach die Info-Subarrays rekursiv durchlaufen.</p>
<pre><code class="language-cpp">typedef std::pair&lt; std::vector&lt;Info&gt;, Infos* base_class_infos &gt; Infos;

// und diese Infos steckst du dann in eine Map (zwecks Klassennamensvergleich)
</code></pre>
<p>So kannst du sogar ein Überschreiben von Eigenschaften ermöglichen.</p>
<p>Ein komplexes System dieser Art habe ich selbst schon als ein Propertysystem implementiert (mit Templates und Makros), welches die Daten aus einer XML-Datei parst.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1564567</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1564567</guid><dc:creator><![CDATA[Th69]]></dc:creator><pubDate>Thu, 14 Aug 2008 09:53:38 GMT</pubDate></item><item><title><![CDATA[Reply to Polymorphes erkennen von Basisklassen; Struktur ähnlich boost::any on Thu, 14 Aug 2008 09:57:51 GMT]]></title><description><![CDATA[<p>@7H3 N4C3R:<br />
Den Ansatz mit der gemeinsamen Basisklasse habe ich schon verfolgt (funktioniert auch wie ich es wollte), nur hatte ich versuche diese Abhängigkeit zu entfernen, weil ich der Meinung war, alle notwendigen Informationen lägen in Form von Typen vor. Das ist im Fall der InfoImpl-Instanz zwar auch der Fall, allerdings nur als type_info-Instanz.</p>
<p><a class="plugin-mentions-user plugin-mentions-a" href="https://www.c-plusplus.net/forum/uid/18594">@Th69</a>:<br />
Das werde ich mir noch anschauen. Übrigens geht es genau um sowas, nämlich in einer (XML-)Datei abgelegte Attribute anhand ihres Namens den richtigen Settern der Klassen zuzuweisen.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1564571</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1564571</guid><dc:creator><![CDATA[LordJaxom]]></dc:creator><pubDate>Thu, 14 Aug 2008 09:57:51 GMT</pubDate></item><item><title><![CDATA[Reply to Polymorphes erkennen von Basisklassen; Struktur ähnlich boost::any on Thu, 14 Aug 2008 10:06:07 GMT]]></title><description><![CDATA[<p>Und aus type_infos kann man leider nicht mehr als eine totale Ordnung aufbauen. <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f61e.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--disappointed_face"
      title=":("
      alt="😞"
    /> Ich bin mit nichtmal sicher, ob eine Basisklasse bei einem Test von baseclass_info.before( derivedclass_info) immer true sein muss (das könnte ich eigentlich gerade mal im Standard nachschauen). Das wäre aber auch nur ein Teilschritt zum Ziel.</p>
<p>Edit: Die Ordnung ist implementierungsabhängig, keine Garantien oder weitere Aussagen.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1564577</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1564577</guid><dc:creator><![CDATA[7H3 N4C3R]]></dc:creator><pubDate>Thu, 14 Aug 2008 10:06:07 GMT</pubDate></item></channel></rss>