<?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[Liste von Basisklassenzeigern: suche elegante Lösung für den Zugriff auf runtergecastete Elemente [gelöst]]]></title><description><![CDATA[<p>Hallo zusammen,</p>
<p>eine Klasse verwaltet eine Liste von B-Zeigern und soll direkten Zugriff auf die D-Zeiger bieten. Bisher habe ich das so gelöst:</p>
<pre><code class="language-cpp">#include &lt;vector&gt;
#include &lt;typeinfo&gt;

class B
{
public:
	virtual ~B() {};
};

class D1 : public B {};
class D2 : public B {};

class Cont
{
public:
	~Cont();
	void Add( B* ptr );
	template &lt;typename T&gt;
	T* GetFirst();
private:
	std::vector &lt;B*&gt; _elems;
};

Cont::~Cont()
{
	for ( std::vector &lt;B*&gt;::iterator it( _elems.begin() ); it != _elems.end(); ++it )
	{
		delete *it;
		*it = 0;
	}
}

void Cont::Add( B* ptr )
{
	_elems.push_back( ptr );
}

template &lt;typename T&gt;
T* Cont::GetFirst()
{
	for ( std::vector &lt;B*&gt;::iterator it( _elems.begin() ); it != _elems.end(); ++it )
		if ( typeid( **it ).name() == typeid( T ).name() )
			return dynamic_cast &lt;T*&gt; ( *it );
	return 0;
}

int main()
{
	Cont c;
	c.Add( new D1() );
	c.Add( new D2() );
	D1* d1Ptr( c.GetFirst &lt;D1&gt; () );
	D2* d2Ptr( c.GetFirst &lt;D2&gt; () );
	return 0;
}
</code></pre>
<p>Hier im Minimalbeispiel habe ich die shared_ptr (deshalb der Cont-dtor), die typedefs, das const-Gerödel und dass B pure virtual ist mal weggelassen.</p>
<p>Es funktioniert so zwar, und das Ganze ist in meiner Anwendung auch nicht performance-kritisch, allerdings werde ich das Gefühl nicht los, dass man das eleganter lösen kann.<br />
Hat jemand einen Vorschlag, wie das dann aussehen könnte? <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>
<p>Gruß<br />
Dobi</p>
]]></description><link>https://www.c-plusplus.net/forum/topic/288244/liste-von-basisklassenzeigern-suche-elegante-lösung-für-den-zugriff-auf-runtergecastete-elemente-gelöst</link><generator>RSS for Node</generator><lastBuildDate>Thu, 20 Aug 2026 00:43:26 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/288244.rss" rel="self" type="application/rss+xml"/><pubDate>Mon, 13 Jun 2011 09:35:27 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Liste von Basisklassenzeigern: suche elegante Lösung für den Zugriff auf runtergecastete Elemente [gelöst] on Mon, 13 Jun 2011 12:05:51 GMT]]></title><description><![CDATA[<p>Hallo zusammen,</p>
<p>eine Klasse verwaltet eine Liste von B-Zeigern und soll direkten Zugriff auf die D-Zeiger bieten. Bisher habe ich das so gelöst:</p>
<pre><code class="language-cpp">#include &lt;vector&gt;
#include &lt;typeinfo&gt;

class B
{
public:
	virtual ~B() {};
};

class D1 : public B {};
class D2 : public B {};

class Cont
{
public:
	~Cont();
	void Add( B* ptr );
	template &lt;typename T&gt;
	T* GetFirst();
private:
	std::vector &lt;B*&gt; _elems;
};

Cont::~Cont()
{
	for ( std::vector &lt;B*&gt;::iterator it( _elems.begin() ); it != _elems.end(); ++it )
	{
		delete *it;
		*it = 0;
	}
}

void Cont::Add( B* ptr )
{
	_elems.push_back( ptr );
}

template &lt;typename T&gt;
T* Cont::GetFirst()
{
	for ( std::vector &lt;B*&gt;::iterator it( _elems.begin() ); it != _elems.end(); ++it )
		if ( typeid( **it ).name() == typeid( T ).name() )
			return dynamic_cast &lt;T*&gt; ( *it );
	return 0;
}

int main()
{
	Cont c;
	c.Add( new D1() );
	c.Add( new D2() );
	D1* d1Ptr( c.GetFirst &lt;D1&gt; () );
	D2* d2Ptr( c.GetFirst &lt;D2&gt; () );
	return 0;
}
</code></pre>
<p>Hier im Minimalbeispiel habe ich die shared_ptr (deshalb der Cont-dtor), die typedefs, das const-Gerödel und dass B pure virtual ist mal weggelassen.</p>
<p>Es funktioniert so zwar, und das Ganze ist in meiner Anwendung auch nicht performance-kritisch, allerdings werde ich das Gefühl nicht los, dass man das eleganter lösen kann.<br />
Hat jemand einen Vorschlag, wie das dann aussehen könnte? <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>
<p>Gruß<br />
Dobi</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2077379</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2077379</guid><dc:creator><![CDATA[Dobi]]></dc:creator><pubDate>Mon, 13 Jun 2011 12:05:51 GMT</pubDate></item><item><title><![CDATA[Reply to Liste von Basisklassenzeigern: suche elegante Lösung für den Zugriff auf runtergecastete Elemente [gelöst] on Mon, 13 Jun 2011 09:43:52 GMT]]></title><description><![CDATA[<p>Dobi schrieb:</p>
<blockquote>
<p>eine Klasse verwaltet eine Liste von B-Zeigern und soll direkten Zugriff auf die D-Zeiger bieten.</p>
</blockquote>
<p>Die Frage ist: Warum? Kannst du nicht virtuelle Funktionen einrichten, welche für jede abgeleitete Klasse anders implementiert sind? Dann könntest du im Benutzercode die Abstraktion bewahren und müsstest nicht explizit Typen unterscheiden, was in der Tat nicht sehr elegant ist.</p>
<p>Übrigens solltest du nie <code>std::type_info::name()</code> für irgendetwas ausser für Debuggingzwecke benutzen, also auch keine Vergleiche wie</p>
<pre><code class="language-cpp">if ( typeid( **it ).name() == typeid( T ).name() )
</code></pre>
<p>anstellen. Der Standard garantiert nämlich nichts über den Namen, prinzipiell dürfen verschiedene Typen den gleichen Namen haben.</p>
<pre><code class="language-cpp">*it = 0;
</code></pre>
<p>Ist ausserdem unnötig, weil das Objekt nicht länger existiert.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2077382</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2077382</guid><dc:creator><![CDATA[Nexus]]></dc:creator><pubDate>Mon, 13 Jun 2011 09:43:52 GMT</pubDate></item><item><title><![CDATA[Reply to Liste von Basisklassenzeigern: suche elegante Lösung für den Zugriff auf runtergecastete Elemente [gelöst] on Mon, 13 Jun 2011 10:04:30 GMT]]></title><description><![CDATA[<p>Stimmt, das Auf-0-Setzen ist unnötig. In so einem übersichtlichen Fall macht es nichts aus, ansonsten verwahre ich aber nur ungern ungültige Zeiger. In der eigentlichen Anwendung kümmern sich ja eh die Zeiger selbst um die Zerstörung ihrer Objekte.</p>
<p>Oh, dann ist std::type_info::name() hier ja wirklich doof. Ich seh gerade, dass type_info eh schon nen Vergleichsoperator hat. Dann also so:</p>
<pre><code class="language-cpp">if ( typeid( **it ) == typeid( T ) )
</code></pre>
<p>Wie ich nur mit virtuellen Funktionen klar kommen könnte, weiß ich leider nicht. Der Container ist bei mir ein Objekt, dass aus einem Bild raussegmentiert wurde, und trägt Eigenschaften (B) wie Kontur (D1), Histogramm (D2) usw.</p>
<p>Könnte ich sonst noch irgendwas besser machen? Gehts vielleicht ohne dynamic_cast?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2077388</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2077388</guid><dc:creator><![CDATA[Dobi]]></dc:creator><pubDate>Mon, 13 Jun 2011 10:04:30 GMT</pubDate></item><item><title><![CDATA[Reply to Liste von Basisklassenzeigern: suche elegante Lösung für den Zugriff auf runtergecastete Elemente [gelöst] on Mon, 13 Jun 2011 10:58:42 GMT]]></title><description><![CDATA[<p>Dobi schrieb:</p>
<blockquote>
<pre><code class="language-cpp">if ( typeid( **it ) == typeid( T ) )
</code></pre>
</blockquote>
<p>Typischerweise benutzt man für solche Tests dynamic_cast selbst (wobei zu beachten ist, dass dieser Test weniger streng ist)</p>
<pre><code class="language-cpp">template &lt;typename T&gt;
T* Cont::GetFirst()
{
    for ( std::vector &lt;B*&gt;::iterator it( _elems.begin() ); it != _elems.end(); ++it )
        if ( T* p = dynamic_cast &lt;T*&gt; ( *it ) )
            return p;
    return 0;
}
</code></pre>
<p>Ohne mehr über die Anwendung zu wissen, ist es schwierig, Designempfehlungen zu geben.</p>
<p>Ein denkbare Möglichkeit wäre, nicht eine Liste von B-Zeigern, sondern mehrere Listen entsprechender D-Zeiger zu verwalten, ungefähr so:</p>
<pre><code class="language-cpp">class B
{
public:
    ~B() {};
};

class D1 : public B {};
class D2 : public B {};

class cont_helper_base
{
    virtual ~helper_base() {}
};

template &lt;typename T&gt;
class cont_helper cont_helper_base
{
    std::vector &lt;T*&gt; elems;
public:
    ~cont_helper()
    {
        for ( std::vector&lt;T*&gt;::iterator it = elems.end(); it != elems.begin(); )
            delete *--it;
    }
    T* GetFirst()
    {
        return elems.empty() ? 0 : elemns.front();
    }
};

class Cont
{
public:
    template &lt;typename T&gt;
    void Add( T* ptr )
    {
        lists[ &amp;typeid( T ) ].push_back( ptr );
    }
    template &lt;typename T&gt;
    T* GetFirst()
    {
        map_type::iterator it = lists.find( &amp;typeid( T ) );
        return it == lists.end() ? 0 : static_cast&lt;cont_helper&lt;T&gt;*&gt;( it-&gt;second )-&gt;GetFirst();
    }
    ~Cont()
    {
        for ( map_type::iterator it = lists.begin(); it != lists.end(); ++it )
            delete it-&gt;second;
    }
private:
    typedef std::map&lt;const std::type_info*, cont_helper_base*&gt; map_type;
    map_type lists;
};
</code></pre>
<p>Wie angedeutet ist es damit nicht einmal notwendig, dass B virtuell ist, überhaupt werden keinerlei Beziehungen zwischen den verschiedenen Typen benötigt.<br />
P.S.: Ich gehe davon aus, dass für jedes T genau ein type_info-Objekt existiert, und somit ein Vergleich der Adressen ausreicht. Könnte allerdings sein, dass das nicht vorgeschrieben ist - dann müsste man noch einen geeigneten Comparator für die map benutzen.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2077413</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2077413</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Mon, 13 Jun 2011 10:58:42 GMT</pubDate></item><item><title><![CDATA[Reply to Liste von Basisklassenzeigern: suche elegante Lösung für den Zugriff auf runtergecastete Elemente [gelöst] on Mon, 13 Jun 2011 13:18:07 GMT]]></title><description><![CDATA[<p>Ah, type_info als key in einer Map find ich ne sehr coole Idee. Wie du die For-Schleifen geschrieben hast und die bedingten Ausdrücke benutzt, gefällt mir auch. Ich versuche jetzt aber erstmal, deinen Code irgendwie kompilierbar zu bekommen. <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>Edit: Da ich eigentlich nur ein Objekt pro Typ in Cont benötige, habe ich es mal etwas vereinfacht:</p>
<pre><code class="language-cpp">#include &lt;map&gt;
#include &lt;typeinfo&gt;

class TypeInfo
{
public:
	TypeInfo( const std::type_info&amp; ti ) : _ptr( &amp;ti ) {}
	~TypeInfo() {}
	const std::type_info* _ptr;
};

bool operator==( const TypeInfo&amp; lhs, const TypeInfo&amp; rhs )
{
	return ( lhs._ptr == rhs._ptr );
}

bool operator&lt;( const TypeInfo&amp; lhs, const TypeInfo&amp; rhs )
{
	return ( lhs._ptr-&gt;before( *rhs._ptr ) );
}

class B
{
public:
	virtual ~B() {};
};

class D1 : public B {};
class D2 : public B {};

class Cont
{
public:
	~Cont();
	template &lt;typename T&gt;
	void Add( T* ptr );
	template &lt;typename T&gt;
	T* Get();
private:
	typedef std::map &lt;const TypeInfo, B*&gt; TMap;
	TMap _elems;
};

Cont::~Cont()
{
	for ( TMap::iterator it( _elems.begin() ); it != _elems.end(); ++it )
	{
		delete it-&gt;second;
		it-&gt;second = 0;
	}
}

template &lt;typename T&gt;
void Cont::Add( T* ptr )
{
	_elems[ TypeInfo( typeid( T ) ) ] = ptr;
}

template &lt;typename T&gt;
T* Cont::Get()
{
	TMap::iterator it( _elems.find( TypeInfo( typeid( T ) ) ) );
        return it == _elems.end() ? 0 : dynamic_cast &lt;T*&gt;( it-&gt;second ); 
}

int main()
{
	Cont c;
	c.Add( new D1() );
	c.Add( new D2() );
	D1* d1Ptr( c.Get &lt;D1&gt; () );
	D2* d2Ptr( c.Get &lt;D2&gt; () );
	return 0;
}
</code></pre>
<p>Deine Grundidee ist ja aber noch drin. Find ich gut. So werde ich es wohl machen. Danke. <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>
<p>Modern C++ design (Seite 38) sagt übrigens, dass der Standard nicht garantiert, dass die Referenz, die typeid zurückgibt, immer auf das gleiche type_info-Objekt zeigt. Hab deshalb nen kleinen Wrapper drumgelegt.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2077428</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2077428</guid><dc:creator><![CDATA[Dobi]]></dc:creator><pubDate>Mon, 13 Jun 2011 13:18:07 GMT</pubDate></item><item><title><![CDATA[Reply to Liste von Basisklassenzeigern: suche elegante Lösung für den Zugriff auf runtergecastete Elemente [gelöst] on Wed, 15 Jun 2011 19:57:56 GMT]]></title><description><![CDATA[<p>Der Header heißt übrigens type_info.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2078689</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2078689</guid><dc:creator><![CDATA[314159265358979]]></dc:creator><pubDate>Wed, 15 Jun 2011 19:57:56 GMT</pubDate></item><item><title><![CDATA[Reply to Liste von Basisklassenzeigern: suche elegante Lösung für den Zugriff auf runtergecastete Elemente [gelöst] on Wed, 15 Jun 2011 20:02:58 GMT]]></title><description><![CDATA[<p>Bei mir (gcc version 4.5.2 (Ubuntu/Linaro 4.5.2-8ubuntu4)) nicht.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2078693</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2078693</guid><dc:creator><![CDATA[Dobi]]></dc:creator><pubDate>Wed, 15 Jun 2011 20:02:58 GMT</pubDate></item><item><title><![CDATA[Reply to Liste von Basisklassenzeigern: suche elegante Lösung für den Zugriff auf runtergecastete Elemente [gelöst] on Wed, 15 Jun 2011 20:54:57 GMT]]></title><description><![CDATA[<p>Tatsächlich.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2078743</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2078743</guid><dc:creator><![CDATA[314159265358979]]></dc:creator><pubDate>Wed, 15 Jun 2011 20:54:57 GMT</pubDate></item></channel></rss>