<?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[Basisklassenzeiger bei Mehrfachvererbung]]></title><description><![CDATA[<p>Hallo!</p>
<p>Ich experimentiere gerade etwas herum, versuch(t)e eine Art einfaches Event-System zu implementieren, frei nach dem Observer-Pattern, wobei die Observer dem Observable einen Methodenzeiger für das Callback mitgeben. Das funktionierte, bis eine abgeleitete Klasse zum Observer wurde und plötzlich die Zeiger nicht mehr stimmten... Das fiel mir auf, als ich in der abgeleiteten Klasse falsche Werte in Variablen der Basisklasse hatte. Die Klassenhierarchie sieht so aus:</p>
<pre><code>+-----------+    +-----------+ 
| SomeBase  |    | Observer  |
+-----------+    +-----------+ 
| int val   |    +-----------+ 
+-----------+          ^
       ^               |
       |               |
       +-------|-------+
               |
        +-----------+ 
        | SomeClass |
        +-----------+ 
        | OnEvent() |
        +-----------+
</code></pre>
<p>Hier nun eine vereinfachte Darstellung meines Codes, der die wesentliche Hierarchie wiedergbit:</p>
<pre><code class="language-cpp">// Interface für Klassen, die Events empfangen
struct Observer
{
	// Die Methoden sind beliebig und in den abgeleiteten Klassen definiert
};

// Basisklasse in irgendeiner Hierarchie
struct SomeBase
{
	SomeBase(int v): val(v) { std::cout &lt;&lt; &quot;SomeBase Ctor: &quot; &lt;&lt; val &lt;&lt; std::endl; }
	int val;
};

typedef void (Observer::*pEventHandler)();
typedef Observer* pObserver;

// Eine konkrete Klasse, die vom SomeBase erbt und das Observer-Interface &quot;implementiert&quot;
struct SomeClass: public SomeBase, public Observer
{
	SomeClass(int v): SomeBase(v) 
	{
		// Der this-Zeiger verschiebt sich zwischen den Hierarchien
		// um 4 Byte, also der Größe von SomeBase
		std::cout &lt;&lt; &quot;(Observer*)this: &quot; &lt;&lt; (Observer*) this &lt;&lt; std::endl; 
		std::cout &lt;&lt; &quot;(SomeBase*)this: &quot; &lt;&lt; (SomeBase*)this &lt;&lt; std::endl;
		std::cout &lt;&lt; &quot;this: &quot; &lt;&lt; this &lt;&lt; std::endl;
	}

	// Diese Methode wird vom Observable aufgerufen, sobald ein Event ausgelöst wird
	void OnEvent() 
	{ 
		// Auf die Variable kann nur in der Some*-Hierarchie zugegriffen werden
		std::cout &lt;&lt; &quot;OnEvent() val: &quot; &lt;&lt; val &lt;&lt; std::endl;

		// Bei Aufruf über die Observer-Hierarchie ist der Wert 4 Byte davor zu finden:
		int* p = &amp;val;
		std::cout &lt;&lt; &quot;OnEvent() val-1: &quot; &lt;&lt; *(p-1) &lt;&lt; std::endl; // 1337
	}
};

int main()
{
	SomeClass c(1337);
	c.OnEvent();

	// Das Observable würde einen Zeiger auf den Observer und einen Methodenzeiger übernehmen
	pObserver o = &amp;c;
	pEventHandler e = (pEventHandler)&amp;SomeClass::OnEvent;

	(o-&gt;*e)(); // val wird 4 Byte zu spät gelesen, da der Aufruf über einen Observer-Zeiger erfolgt

	return 0;
}
</code></pre>
<p>Die Ausgabe sieht z.B. so aus:</p>
<pre><code>SomeBase Ctor: 1337
(Observer*)this: 002AFD10
(SomeBase*)this: 002AFD0C
this: 002AFD0C
OnEvent() val: 1337
OnEvent() val-1: -858993460
OnEvent() val: -858993460
OnEvent() val-1: 1337
</code></pre>
<p>Das alles betrachtet, fällt über den Observer-Hierarchiepfad das SomeBase-Objekt quasi raus, liegt aber natürlich im Speicher. Darauf lässt sich jedoch nicht korrekt zugreifen, stattdessen wird von einer anderen Speicherstelle gelesen (bzw. die selbe, relativ zum Objekt) - denn wenn man Observer ein int verpasst, wird genau dieses ausgegeben. Die wird da jeweils der Weg zum int gefunden? Und warum ist das so? In der Observer-Hierarche arbeite ich letztlich mit einem unvollständigen Objekt - und ich hab sehr lange gebraucht um das herauszufinden (bzw. den obigen Code zu isolieren).</p>
<p>Was für Möglichkeiten habe ich nun? Ich könnte Observer in SomeBase implementieren, auch wenn das ein wenig der Logik widerspricht. Oder ich erzeuge ein Objekt das parallel zu SomeClass exisitiert und nur die Events empfängt, ...aber bestimmt kann man es ganz anders besser machen <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>Ich freue mich auf eure Antworten! <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>MfG,<br />
Meisterfrickler</p>
]]></description><link>https://www.c-plusplus.net/forum/topic/232847/basisklassenzeiger-bei-mehrfachvererbung</link><generator>RSS for Node</generator><lastBuildDate>Fri, 25 Sep 2026 04:26:38 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/232847.rss" rel="self" type="application/rss+xml"/><pubDate>Wed, 28 Jan 2009 03:57:54 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Basisklassenzeiger bei Mehrfachvererbung on Wed, 28 Jan 2009 03:57:54 GMT]]></title><description><![CDATA[<p>Hallo!</p>
<p>Ich experimentiere gerade etwas herum, versuch(t)e eine Art einfaches Event-System zu implementieren, frei nach dem Observer-Pattern, wobei die Observer dem Observable einen Methodenzeiger für das Callback mitgeben. Das funktionierte, bis eine abgeleitete Klasse zum Observer wurde und plötzlich die Zeiger nicht mehr stimmten... Das fiel mir auf, als ich in der abgeleiteten Klasse falsche Werte in Variablen der Basisklasse hatte. Die Klassenhierarchie sieht so aus:</p>
<pre><code>+-----------+    +-----------+ 
| SomeBase  |    | Observer  |
+-----------+    +-----------+ 
| int val   |    +-----------+ 
+-----------+          ^
       ^               |
       |               |
       +-------|-------+
               |
        +-----------+ 
        | SomeClass |
        +-----------+ 
        | OnEvent() |
        +-----------+
</code></pre>
<p>Hier nun eine vereinfachte Darstellung meines Codes, der die wesentliche Hierarchie wiedergbit:</p>
<pre><code class="language-cpp">// Interface für Klassen, die Events empfangen
struct Observer
{
	// Die Methoden sind beliebig und in den abgeleiteten Klassen definiert
};

// Basisklasse in irgendeiner Hierarchie
struct SomeBase
{
	SomeBase(int v): val(v) { std::cout &lt;&lt; &quot;SomeBase Ctor: &quot; &lt;&lt; val &lt;&lt; std::endl; }
	int val;
};

typedef void (Observer::*pEventHandler)();
typedef Observer* pObserver;

// Eine konkrete Klasse, die vom SomeBase erbt und das Observer-Interface &quot;implementiert&quot;
struct SomeClass: public SomeBase, public Observer
{
	SomeClass(int v): SomeBase(v) 
	{
		// Der this-Zeiger verschiebt sich zwischen den Hierarchien
		// um 4 Byte, also der Größe von SomeBase
		std::cout &lt;&lt; &quot;(Observer*)this: &quot; &lt;&lt; (Observer*) this &lt;&lt; std::endl; 
		std::cout &lt;&lt; &quot;(SomeBase*)this: &quot; &lt;&lt; (SomeBase*)this &lt;&lt; std::endl;
		std::cout &lt;&lt; &quot;this: &quot; &lt;&lt; this &lt;&lt; std::endl;
	}

	// Diese Methode wird vom Observable aufgerufen, sobald ein Event ausgelöst wird
	void OnEvent() 
	{ 
		// Auf die Variable kann nur in der Some*-Hierarchie zugegriffen werden
		std::cout &lt;&lt; &quot;OnEvent() val: &quot; &lt;&lt; val &lt;&lt; std::endl;

		// Bei Aufruf über die Observer-Hierarchie ist der Wert 4 Byte davor zu finden:
		int* p = &amp;val;
		std::cout &lt;&lt; &quot;OnEvent() val-1: &quot; &lt;&lt; *(p-1) &lt;&lt; std::endl; // 1337
	}
};

int main()
{
	SomeClass c(1337);
	c.OnEvent();

	// Das Observable würde einen Zeiger auf den Observer und einen Methodenzeiger übernehmen
	pObserver o = &amp;c;
	pEventHandler e = (pEventHandler)&amp;SomeClass::OnEvent;

	(o-&gt;*e)(); // val wird 4 Byte zu spät gelesen, da der Aufruf über einen Observer-Zeiger erfolgt

	return 0;
}
</code></pre>
<p>Die Ausgabe sieht z.B. so aus:</p>
<pre><code>SomeBase Ctor: 1337
(Observer*)this: 002AFD10
(SomeBase*)this: 002AFD0C
this: 002AFD0C
OnEvent() val: 1337
OnEvent() val-1: -858993460
OnEvent() val: -858993460
OnEvent() val-1: 1337
</code></pre>
<p>Das alles betrachtet, fällt über den Observer-Hierarchiepfad das SomeBase-Objekt quasi raus, liegt aber natürlich im Speicher. Darauf lässt sich jedoch nicht korrekt zugreifen, stattdessen wird von einer anderen Speicherstelle gelesen (bzw. die selbe, relativ zum Objekt) - denn wenn man Observer ein int verpasst, wird genau dieses ausgegeben. Die wird da jeweils der Weg zum int gefunden? Und warum ist das so? In der Observer-Hierarche arbeite ich letztlich mit einem unvollständigen Objekt - und ich hab sehr lange gebraucht um das herauszufinden (bzw. den obigen Code zu isolieren).</p>
<p>Was für Möglichkeiten habe ich nun? Ich könnte Observer in SomeBase implementieren, auch wenn das ein wenig der Logik widerspricht. Oder ich erzeuge ein Objekt das parallel zu SomeClass exisitiert und nur die Events empfängt, ...aber bestimmt kann man es ganz anders besser machen <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>Ich freue mich auf eure Antworten! <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>MfG,<br />
Meisterfrickler</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1653609</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1653609</guid><dc:creator><![CDATA[Meisterfrickler]]></dc:creator><pubDate>Wed, 28 Jan 2009 03:57:54 GMT</pubDate></item><item><title><![CDATA[Reply to Basisklassenzeiger bei Mehrfachvererbung on Wed, 28 Jan 2009 09:11:48 GMT]]></title><description><![CDATA[<p>Hallo</p>
<p>Im folgenden ein paar Änderungen, wie ich es machen würde. Es bleibt Deine Aufgabe sie zu verstehen:</p>
<pre><code class="language-cpp">#include &lt;iostream&gt;
using namespace std;

// Interface für Klassen, die Events empfangen
struct Observer
{
	virtual void OnEvent() = 0; 
	// !!!!! Die Methoden sind beliebig und in den abgeleiteten Klassen definiert !!!?????? &gt;&gt;Quatsch&lt;&lt;
};

....

int main()
{
	SomeClass c(1337);
	c.OnEvent();

	// Das Observable würde einen Zeiger auf den Observer und einen Methodenzeiger übernehmen
	pObserver o = &amp;c;

	//!!!pEventHandler e = (pEventHandler)&amp;SomeClass::OnEvent;
	//!!!(o-&gt;*e)(); // val wird 4 Byte zu spät gelesen, da der Aufruf über einen Observer-Zeiger erfolgt
         //?? wie kommst Du auf dieses Zeug?

	o-&gt;OnEvent();

	return 0;
}
</code></pre>
<p>Grüsse</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1653707</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1653707</guid><dc:creator><![CDATA[Drehleiter]]></dc:creator><pubDate>Wed, 28 Jan 2009 09:11:48 GMT</pubDate></item><item><title><![CDATA[Reply to Basisklassenzeiger bei Mehrfachvererbung on Wed, 28 Jan 2009 09:56:45 GMT]]></title><description><![CDATA[<p>Hmm, was gibt es daran jetzt zu verstehen, mehr als das paar Dinge Quatsch wären hast du jetzt ja nicht gesagt.</p>
<p>Drehleiter schrieb:</p>
<blockquote>
<p>// !!!!! Die Methoden sind beliebig und in den abgeleiteten Klassen definiert !!!?????? &gt;&gt;Quatsch&lt;&lt;</p>
</blockquote>
<p>Im Observer-Interface hatte ich auch erst eine virtuelle Methode, aber die Events, auf die ich reagieren will, kommen von GUI-Elementen. <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="🙂"
    /> Angenommen ich habe 5 Buttons, deren Events ich alle in einer Klasse behandeln möchte - dazu könnte ich jetzt im Interface maximal eine &quot;OnButtonEvent&quot;-Methode einführen, die dann für alle Buttons aufgerufen wird. In der Implementierung dieser Methode müsste ich irgendwie herausfinden, welcher Button das Event ausgelöst hat und dann ggf. eine weitere Methode aufrufen, die das Event dann tatsächlich behandelt. Indem ich beliebige Methoden an die Events knüpfen kann, umgehe ich diese beiden Probleme (falls man das so machen kann, das möchte ich mir ja lieber noch absegnen lassen...).</p>
<p>Drehleiter schrieb:</p>
<blockquote>
<p>//?? wie kommst Du auf dieses Zeug?</p>
</blockquote>
<p>Verstehe die Frage nicht wirklich. Der Fehler trat halt auf und dann habe ich ihn zurückverfolgt. Sagen wir, es hat sich so ergeben!</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1653731</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1653731</guid><dc:creator><![CDATA[Meisterfrickler]]></dc:creator><pubDate>Wed, 28 Jan 2009 09:56:45 GMT</pubDate></item><item><title><![CDATA[Reply to Basisklassenzeiger bei Mehrfachvererbung on Wed, 28 Jan 2009 10:42:31 GMT]]></title><description><![CDATA[<p>Hallo</p>
<p>Ich sehe es so:</p>
<p>&quot;Observer&quot; ist das Interface, über dass du auf die Objekte zugreifen willst, also musst Du ihm auch eien adequate Schnittstelle geben. Wenn &quot;Observer&quot; keine Schnittstelle hat, dann braucht man es auch nicht!</p>
<blockquote>
<p>Im Observer-Interface hatte ich auch erst eine virtuelle Methode, aber die Events, auf die ich reagieren will, kommen von GUI-Elementen. Angenommen ich habe 5 Buttons, deren Events ich alle in einer Klasse behandeln möchte - dazu könnte ich jetzt im Interface maximal eine &quot;OnButtonEvent&quot;-Methode einführen, die dann für alle Buttons aufgerufen wird. In der Implementierung dieser Methode müsste ich irgendwie herausfinden, welcher Button das Event ausgelöst hat und dann ggf. eine weitere Methode aufrufen, die das Event dann tatsächlich behandelt.</p>
</blockquote>
<p>Klingt für mich richtig.</p>
<blockquote>
<p>Indem ich beliebige Methoden an die Events knüpfen kann, umgehe ich diese beiden Probleme (falls man das so machen kann, das möchte ich mir ja lieber noch absegnen lassen...).</p>
</blockquote>
<p>Geht auch, indem die Interface-Funktion einen entsprechenden Funktionspointer als Argument akzeptiert.</p>
<p>Grüsse</p>
<p>PS:<br />
Es gibt noch eine Lösung die bestimmt nicht Standard-Konform ist(geht mit VC++).<br />
Vertausche die Riehenfolge der Ableitungen:</p>
<pre><code>struct SomeClass: public Observer, public SomeBase
</code></pre>
<p>und hier zeigt sich aus das Problem: Der Zusammenhang zwischen der Adresse des Objektes und der Basisklasse ist nicht eindeutig.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1653753</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1653753</guid><dc:creator><![CDATA[Drehleiter]]></dc:creator><pubDate>Wed, 28 Jan 2009 10:42:31 GMT</pubDate></item><item><title><![CDATA[Reply to Basisklassenzeiger bei Mehrfachvererbung on Thu, 29 Jan 2009 09:50:09 GMT]]></title><description><![CDATA[<p>Drehleiter schrieb:</p>
<blockquote>
<p>&quot;Observer&quot; ist das Interface, über dass du auf die Objekte zugreifen willst, also musst Du ihm auch eien adequate Schnittstelle geben. Wenn &quot;Observer&quot; keine Schnittstelle hat, dann braucht man es auch nicht!</p>
</blockquote>
<p>Naja, es hat eine &quot;dynamische Schnittstelle&quot; ;). Und ich brauche es bei diesem Ansatz, um die Observer auf nen gemeinsamen Nenner zu bringen...</p>
<p>Drehleiter schrieb:</p>
<blockquote>
<p>Geht auch, indem die Interface-Funktion einen entsprechenden Funktionspointer als Argument akzeptiert.</p>
</blockquote>
<p>Das würde aber zu den gleichen Problemen führen, weil er Aufruf wieder über die Observer-Hierarchie geschieht.</p>
<p>Aber das alles ist jetzt hinfällig geworden! Ein kluger Kopf hat mir verraten, wie man es besser machen kann: Mit Funktionsobjekten. Das Observable bekommt den Observer nicht mehr direkt übergeben, sondern ein Funktionsobjekt, das den Aufruf der Memberfunktion kapselt. Das bringt den unschätzbaren Vorteil mit sich, dass jede beliebige Klasse Events empfangen kann und dabei nicht einmal ein bestimmtes Interface implementiern muss. Sogar freie Funktionen lassen sich so als Event-Handler benutzen. <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f60b.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--face_savoring_food"
      title=":yum:"
      alt="😋"
    /></p>
<p>Auf den ursprünglichen Code angewandt sieht das z.B. so aus:</p>
<pre><code class="language-cpp">SomeClass c(1337);

	boost::function&lt;void ()&gt; f = boost::bind(&amp;SomeClass::OnEvent, &amp;c);
	f();
</code></pre>
<p>Sehr geil!</p>
]]></description><link>https://www.c-plusplus.net/forum/post/1654236</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/1654236</guid><dc:creator><![CDATA[Meisterfrickler]]></dc:creator><pubDate>Thu, 29 Jan 2009 09:50:09 GMT</pubDate></item></channel></rss>