<?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[Funktionierende Zuweisung unterschiedlicher Typen - Eine Handleklasse wirft Fragen auf]]></title><description><![CDATA[<p>Hallo liebe C++-Community :),</p>
<p>da ich momentan ein paar Dinge ausprobiere, bin ich nun auch in Kontakt mit Handleklassen gekommen. Beim testen einer Handleklasse, die ich im Großen und Ganzen dem C++-Primer entnommen habe, bin ich über ein mir nicht so recht erklärbares Verhalten gestoßen, das in diesem Buch auch nicht wirklich erklärt wird. Hier erstmal ein (hoffentlich kurz genug gehaltener) kompilierbarer Beispielcode:<br />
<strong>abstractclass.h</strong></p>
<pre><code class="language-cpp">#ifndef MYABSTRACTCLASS_H
#define MYABSTRACTCLASS_H

#include &lt;cstddef&gt;

class AbstractClass {
public:
	virtual AbstractClass* clone() const = 0;
	virtual void doSomething() const = 0;
	virtual ~AbstractClass() { }
};

class AbstractClassHandle {
public:
	AbstractClassHandle();
	AbstractClassHandle(const AbstractClass &amp;abs);
	AbstractClassHandle(const AbstractClassHandle &amp;orig);
	~AbstractClassHandle();
	AbstractClassHandle&amp; operator=(const AbstractClassHandle &amp;rhs);
	const AbstractClass* operator-&gt;() const;
	const AbstractClass&amp; operator*() const;
private:
	AbstractClass *m_pointer;
	std::size_t *m_use;
	void decrementUse();
};

class DerivedClass: public AbstractClass {
public:
	virtual DerivedClass* clone() const;
	virtual void doSomething() const;
};

#endif // MYABSTRACTCLASS_H
</code></pre>
<p><strong>abstractclass.cpp</strong></p>
<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;stdexcept&gt;
#include &quot;abstractclass.h&quot;

AbstractClassHandle::AbstractClassHandle(): m_pointer(0), m_use(new std::size_t(1)) { }

AbstractClassHandle::AbstractClassHandle(const AbstractClass &amp;abs): m_pointer(abs.clone()), m_use(new std::size_t(1)) { }

AbstractClassHandle::AbstractClassHandle(const AbstractClassHandle &amp;orig): m_pointer(orig.m_pointer), m_use(orig.m_use)
{
	++*m_use;
}

AbstractClassHandle::~AbstractClassHandle()
{
	decrementUse();
}

AbstractClassHandle&amp; AbstractClassHandle::operator=(const AbstractClassHandle &amp;rhs)
{
	++*rhs.m_use;
	decrementUse();
	m_pointer = rhs.m_pointer;
	m_use = rhs.m_use;
	return *this;
}

const AbstractClass* AbstractClassHandle::operator-&gt;() const
{
	if(m_pointer)
		return m_pointer;
	throw std::logic_error(&quot;unbound handle&quot;);
}

const AbstractClass&amp; AbstractClassHandle::operator*() const
{
	if(m_pointer)
		return *m_pointer;
	throw std::logic_error(&quot;unbound handle&quot;);
}

void AbstractClassHandle::decrementUse()
{
	if(--*m_use == 0) {
		delete m_pointer;
		delete m_use;
	}
}

DerivedClass* DerivedClass::clone() const
{
	return new DerivedClass();
}

void DerivedClass::doSomething() const
{
	std::cout &lt;&lt; &quot;do something&quot; &lt;&lt; std::endl;
}
</code></pre>
<p><strong>main.cpp</strong></p>
<pre><code class="language-cpp">#include &quot;abstractclass.h&quot;

int main()
{
	DerivedClass derived;
	AbstractClassHandle handle;
	handle = derived; // &lt;-- Wieso klappt die Zuweisung?
	handle-&gt;doSomething();

	return 0;
}
</code></pre>
<p>Wie man am Kommentar in der <code>main.cpp</code> sieht, bereitet mir die Zuweisung des <code>DerivedClass</code> -Objektes an das <code>AbstractClassHandle</code> -Objekt Kopfzerbrechen. Ich habe die Zuweisung bereits mittels des Visual Studio Debuggers Schritt für Schritt versucht nachzuvollziehen. Dabei fiel mir auf, dass zuerst ein temporäres <code>AbstractClassHandle</code> -Objekt mittels des zweiten Konstruktors der <code>AbstractClassHandle</code> -Klasse erzeugt wird und mit diesem dann die Zuweisung durchgeführt wird. Ich verstehe nur nicht so recht wie der Compiler(?) darauf kommt dieses temporäre Objekt für die Zuweisung zu erzeugen. Eigentlich hätte ich damit gerechnet, dass mir eine Fehlermeldung a la:</p>
<pre><code>Es konnte kein Operator gefunden werden, der einen rechtsseitigen Operanden vom Typ 'DerivedClass' akzeptiert etc.
</code></pre>
<p>an den Kopf geworfen wird.</p>
<p>Ich hoffe das mir jemand dieses Verhalten vielleicht etwas genauer erklären könnte. Und schon mal ein Danke für das Lesen dieses etwas lang geratenen Beitrages <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/topic/250816/funktionierende-zuweisung-unterschiedlicher-typen-eine-handleklasse-wirft-fragen-auf</link><generator>RSS for Node</generator><lastBuildDate>Tue, 15 Sep 2026 20:54:25 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/250816.rss" rel="self" type="application/rss+xml"/><pubDate>Thu, 24 Sep 2009 16:07:20 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Funktionierende Zuweisung unterschiedlicher Typen - Eine Handleklasse wirft Fragen auf on Thu, 24 Sep 2009 16:07:20 GMT]]></title><description><![CDATA[<p>Hallo liebe C++-Community :),</p>
<p>da ich momentan ein paar Dinge ausprobiere, bin ich nun auch in Kontakt mit Handleklassen gekommen. Beim testen einer Handleklasse, die ich im Großen und Ganzen dem C++-Primer entnommen habe, bin ich über ein mir nicht so recht erklärbares Verhalten gestoßen, das in diesem Buch auch nicht wirklich erklärt wird. Hier erstmal ein (hoffentlich kurz genug gehaltener) kompilierbarer Beispielcode:<br />
<strong>abstractclass.h</strong></p>
<pre><code class="language-cpp">#ifndef MYABSTRACTCLASS_H
#define MYABSTRACTCLASS_H

#include &lt;cstddef&gt;

class AbstractClass {
public:
	virtual AbstractClass* clone() const = 0;
	virtual void doSomething() const = 0;
	virtual ~AbstractClass() { }
};

class AbstractClassHandle {
public:
	AbstractClassHandle();
	AbstractClassHandle(const AbstractClass &amp;abs);
	AbstractClassHandle(const AbstractClassHandle &amp;orig);
	~AbstractClassHandle();
	AbstractClassHandle&amp; operator=(const AbstractClassHandle &amp;rhs);
	const AbstractClass* operator-&gt;() const;
	const AbstractClass&amp; operator*() const;
private:
	AbstractClass *m_pointer;
	std::size_t *m_use;
	void decrementUse();
};

class DerivedClass: public AbstractClass {
public:
	virtual DerivedClass* clone() const;
	virtual void doSomething() const;
};

#endif // MYABSTRACTCLASS_H
</code></pre>
<p><strong>abstractclass.cpp</strong></p>
<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;stdexcept&gt;
#include &quot;abstractclass.h&quot;

AbstractClassHandle::AbstractClassHandle(): m_pointer(0), m_use(new std::size_t(1)) { }

AbstractClassHandle::AbstractClassHandle(const AbstractClass &amp;abs): m_pointer(abs.clone()), m_use(new std::size_t(1)) { }

AbstractClassHandle::AbstractClassHandle(const AbstractClassHandle &amp;orig): m_pointer(orig.m_pointer), m_use(orig.m_use)
{
	++*m_use;
}

AbstractClassHandle::~AbstractClassHandle()
{
	decrementUse();
}

AbstractClassHandle&amp; AbstractClassHandle::operator=(const AbstractClassHandle &amp;rhs)
{
	++*rhs.m_use;
	decrementUse();
	m_pointer = rhs.m_pointer;
	m_use = rhs.m_use;
	return *this;
}

const AbstractClass* AbstractClassHandle::operator-&gt;() const
{
	if(m_pointer)
		return m_pointer;
	throw std::logic_error(&quot;unbound handle&quot;);
}

const AbstractClass&amp; AbstractClassHandle::operator*() const
{
	if(m_pointer)
		return *m_pointer;
	throw std::logic_error(&quot;unbound handle&quot;);
}

void AbstractClassHandle::decrementUse()
{
	if(--*m_use == 0) {
		delete m_pointer;
		delete m_use;
	}
}

DerivedClass* DerivedClass::clone() const
{
	return new DerivedClass();
}

void DerivedClass::doSomething() const
{
	std::cout &lt;&lt; &quot;do something&quot; &lt;&lt; std::endl;
}
</code></pre>
<p><strong>main.cpp</strong></p>
<pre><code class="language-cpp">#include &quot;abstractclass.h&quot;

int main()
{
	DerivedClass derived;
	AbstractClassHandle handle;
	handle = derived; // &lt;-- Wieso klappt die Zuweisung?
	handle-&gt;doSomething();

	return 0;
}
</code></pre>
<p>Wie man am Kommentar in der <code>main.cpp</code> sieht, bereitet mir die Zuweisung des <code>DerivedClass</code> -Objektes an das <code>AbstractClassHandle</code> -Objekt Kopfzerbrechen. Ich habe die Zuweisung bereits mittels des Visual Studio Debuggers Schritt für Schritt versucht nachzuvollziehen. Dabei fiel mir auf, dass zuerst ein temporäres <code>AbstractClassHandle</code> -Objekt mittels des zweiten Konstruktors der <code>AbstractClassHandle</code> -Klasse erzeugt wird und mit diesem dann die Zuweisung durchgeführt wird. Ich verstehe nur nicht so recht wie der Compiler(?) darauf kommt dieses temporäre Objekt für die Zuweisung zu erzeugen. Eigentlich hätte ich damit gerechnet, dass mir eine Fehlermeldung a la:</p>
<pre><code>Es konnte kein Operator gefunden werden, der einen rechtsseitigen Operanden vom Typ 'DerivedClass' akzeptiert etc.
</code></pre>
<p>an den Kopf geworfen wird.</p>
<p>Ich hoffe das mir jemand dieses Verhalten vielleicht etwas genauer erklären könnte. Und schon mal ein Danke für das Lesen dieses etwas lang geratenen Beitrages <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/1783712</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1783712</guid><dc:creator><![CDATA[Mizar]]></dc:creator><pubDate>Thu, 24 Sep 2009 16:07:20 GMT</pubDate></item><item><title><![CDATA[Reply to Funktionierende Zuweisung unterschiedlicher Typen - Eine Handleklasse wirft Fragen auf on Thu, 24 Sep 2009 16:16:54 GMT]]></title><description><![CDATA[<p>Das Zauberwort heißt Vererbung. Da deine DerivedClass von AbstractClass erbt, ist jedes Objekt der DerivedClass auch ein Objekt vom Typ AbstractClass</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1783717</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1783717</guid><dc:creator><![CDATA[Tolpan]]></dc:creator><pubDate>Thu, 24 Sep 2009 16:16:54 GMT</pubDate></item><item><title><![CDATA[Reply to Funktionierende Zuweisung unterschiedlicher Typen - Eine Handleklasse wirft Fragen auf on Thu, 24 Sep 2009 16:18:50 GMT]]></title><description><![CDATA[<p>Die Vererbung ist aber nicht (nur) das interessante <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="😉"
    /><br />
Mach mal das</p>
<pre><code class="language-cpp">explicit AbstractClassHandle(const AbstractClass &amp;abs);
</code></pre>
<p>und wunder dich.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1783719</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1783719</guid><dc:creator><![CDATA[explicit0r]]></dc:creator><pubDate>Thu, 24 Sep 2009 16:18:50 GMT</pubDate></item><item><title><![CDATA[Reply to Funktionierende Zuweisung unterschiedlicher Typen - Eine Handleklasse wirft Fragen auf on Thu, 24 Sep 2009 16:28:52 GMT]]></title><description><![CDATA[<p>Tolpan schrieb:</p>
<blockquote>
<p>Da deine DerivedClass von AbstractClass erbt, ist jedes Objekt der DerivedClass auch ein Objekt vom Typ AbstractClass</p>
</blockquote>
<p>Ja, das ist mir klar, aber das erklärt mir (glaube ich) noch nicht so recht die Zuweisung eines Objektes vom Typ <code>AbstractClass</code> an ein Objekt vom Typ <code>AbstractClassHandle</code> . Schließlich erwartet ja der Zuweisungsoperator von der <code>AbstractClassHandle</code> -Klasse eben auch ein <code>AbstractClassHandle</code> -Objekt. Wieso wird denn dann trotzdem vor der Zuweisung der zweite Konstruktor der <code>AbstractClassHandle</code> -Klasse aufgerufen, um die Zuweisung dennoch durchführen zu können?</p>
<p>explicit0r schrieb:</p>
<blockquote>
<p>Mach mal das</p>
<pre><code class="language-cpp">explicit AbstractClassHandle(const AbstractClass &amp;abs);
</code></pre>
<p>und wunder dich.</p>
</blockquote>
<p>Okay, dadurch bekomme ich nun die erwartete Fehlermeldung:</p>
<pre><code>error C2679: Binärer Operator '=': Es konnte kein Operator gefunden werden, der einen rechtsseitigen Operanden vom Typ 'DerivedClass' akzeptiert (oder keine geeignete Konvertierung möglich)
</code></pre>
<p>Irgendwie verstehe ich jetzt gar nichts mehr <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f603.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--grinning_face_with_big_eyes"
      title=":D"
      alt="😃"
    /></p>
]]></description><link>https://www.c-plusplus.net/forum/post/1783726</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1783726</guid><dc:creator><![CDATA[Mizar]]></dc:creator><pubDate>Thu, 24 Sep 2009 16:28:52 GMT</pubDate></item><item><title><![CDATA[Reply to Funktionierende Zuweisung unterschiedlicher Typen - Eine Handleklasse wirft Fragen auf on Thu, 24 Sep 2009 16:38:01 GMT]]></title><description><![CDATA[<p><code>explicit</code> besagt, dass eben keine implizite Typkonvertierung stattfindet. Beim Aufruf von</p>
<pre><code class="language-cpp">handle = derived;
</code></pre>
<p>wird der Konstruktor von handle aufgerufen, dieser konvertiert derived in das Basisobjekt und übernimmt es. <code>explicit</code> unterbindet nun diese Polymorphie.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1783729</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1783729</guid><dc:creator><![CDATA[Verb0r]]></dc:creator><pubDate>Thu, 24 Sep 2009 16:38:01 GMT</pubDate></item><item><title><![CDATA[Reply to Funktionierende Zuweisung unterschiedlicher Typen - Eine Handleklasse wirft Fragen auf on Thu, 24 Sep 2009 16:38:36 GMT]]></title><description><![CDATA[<p>Mizar schrieb:</p>
<blockquote>
<p>Okay, dadurch bekomme ich nun die erwartete Fehlermeldung:</p>
<pre><code>error C2679: Binärer Operator '=': Es konnte kein Operator gefunden werden, der einen rechtsseitigen Operanden vom Typ 'DerivedClass' akzeptiert (oder keine geeignete Konvertierung möglich)
</code></pre>
<p>Irgendwie verstehe ich jetzt gar nichts mehr <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f603.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--grinning_face_with_big_eyes"
      title=":D"
      alt="😃"
    /></p>
</blockquote>
<p>Was vorher passiert ist:<br />
Der Compiler sucht einen operator=(const DerivedClass&amp;), wird nicht gefunden.<br />
Derived ist ein AbstractClass, für den gibt es aber auch keinen operator=. Und jetzt kommt das &quot;explicit&quot;, denn der Compiler findet nur den operator=(const AbtractClassHandle&amp;), womit er als nächtes einen Konstruktor für AbstractClassHandle sucht, der mit einem Argument des Typs DerivedClass was anfangen kann - und wird bei AbstractClassHandle(const AbstractClass&amp;) fündig!<br />
Das explicit im Konstruktor verbietet es nun, implizit diesen Konstruktor aufzurufen. Und schon hast du den Fehler.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1783730</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1783730</guid><dc:creator><![CDATA[explicit0r]]></dc:creator><pubDate>Thu, 24 Sep 2009 16:38:36 GMT</pubDate></item><item><title><![CDATA[Reply to Funktionierende Zuweisung unterschiedlicher Typen - Eine Handleklasse wirft Fragen auf on Thu, 24 Sep 2009 16:51:38 GMT]]></title><description><![CDATA[<p>Gut, das erklärt mir einiges. Vor allem dieser Teil, war mir bis jetzt noch gar nicht bewusst:</p>
<p>explicit0r schrieb:</p>
<blockquote>
<p>[...]denn der Compiler findet nur den operator=(const AbtractClassHandle&amp;), <strong>womit er als nächtes einen Konstruktor für AbstractClassHandle sucht, der mit einem Argument des Typs DerivedClass was anfangen kann</strong> - und wird bei AbstractClassHandle(const AbstractClass&amp;) fündig![...]</p>
</blockquote>
<p>Ich dachte bisher, dass der Compiler nur nach einem geeigneten Zuweisungsoperator sucht und wenn er keinen findet sogleich eine Fehlermeldung ausspuckt. Das er jedoch sogar noch weiter nach einem Konstruktor sucht war mir, wie bereits gesagt, noch nicht bekannt. Das erklärt mir nun die Funktionierende Zuweisung vollends. Vielen Dank <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/1783741</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1783741</guid><dc:creator><![CDATA[Mizar]]></dc:creator><pubDate>Thu, 24 Sep 2009 16:51:38 GMT</pubDate></item></channel></rss>