<?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[Inversion durch Radierung]]></title><description><![CDATA[<p>Hallo Leute,<br />
ich warte gerade Stundenlang auf den Bau der llvm - Suite(brauche mehr Kerne!), daher melde ich mich gerade mal mit einer Sache, die mir aufgefallen ist, während ich mich die letzten Tage nebenbei etwas eingehender mit Type-Erasure beschäftigt habe. Es wird eine Code-Schwall von 3 Implementierungs-Ansätzen folgen, aber ihr als erfahrene C++-Anwender werdet schnell die Muster entdecken, es ist nicht viel darüber hinaus gehender Inhalt im Quelltext, also bitte ich ohne Vorbehalt einfach mal drauf loszulesen - es wird gar nicht so lange dauern, wie es den Anschein hat (oder besser, wie es für micht hätte).</p>
<p>Das folgende ist ein Code-Konstrukt, das irgendwie immer wieder auftrat und mir auch immer wieder ein Dorn im Augen war - es geht um das Abspeichern und Lesen von &quot;polymorphen&quot; Objekten, bei denen die Basisklasse echte Funktionalität bietet, und nicht einfach nur alles &quot;runterreicht&quot;. Das &quot;Name&quot;-Attribut habe ich jetzt einfach mal als Repräsentant für soetwas hergenommen.</p>
<pre><code class="language-cpp">class Base {
public:
	Base(string name) : name_(move(name)) {}

	void ChangeName(string name) { name_ = move(name); }
	string GetName() { return name_; }

public:
	// Some ist eine Methode, die alle Base-Objekte haben sollen.
	virtual void Some() = 0;

	virtual void Write(stream s) {
		s &lt;&lt; name_;
	}

	virtual ~Base() {}
private:
	string name_;
};

class Derived : 
	public Base
{
public:
	Derived(string name) : Base(name) {}

	static shared_ptr&lt;Derived&gt; Read(stream&amp; s)
	{
		scoped_read_guard guard(s);
		string name;
		s &gt;&gt; name;
		return make_shared&lt;Derived&gt;(std::move(name));
		// Die abgelittene Klasse muss also der Basisklasse ihre Parameter
		// auslesen und sie immer durch ihren eigenen Konstruktor schleifen
		// und einen guard um das gesamte Objekt legen
	}

	void Write(stream s) override
	{
		scoped_write_guard guard(s);
		Base::Write(s);  // Ich muss dafür sorgen, dass Base geschrieben wird
		// Zudem kann Base im Stream keine &quot;Hülle&quot; um das gesamte Objekt legen
		// (Ich verwende gerne Scoped-Reader und -Writer, die das Dateiformat mit
		// Navigations und Redundanz-Daten anreichern.
		s &lt;&lt; &quot;blah&quot;;
	}

	void Some() override {}

	// ... und mehr Methoden
};

shared_ptr&lt;Base&gt; ReadObject1(stream&amp; s)
{
	// Irgendwie wird der Typ herausgefunden
	return Derived::Read(s);
}

void WriteObject1(stream&amp; s, Base&amp; b)
{
	b.Write(s);
}
</code></pre>
<p>Das Problem habe ich in den Kommentar geschrieben, bislang ist mir dafür irgendwie noch keine gute Lösung eingefallen.<br />
Nun kommt der Ansatz der Typ - Ausradierung:</p>
<pre><code class="language-cpp">class Concrete2;

class Base2 {
public:
	Base2(string name) : name_(name) {}

	void Some() {
		content_-&gt;Some();
	}

	static shared_ptr&lt;Base2&gt; Read(stream&amp; s) {
		scoped_read_guard guard(s);
		string name;
		s &gt;&gt; name;
		auto result = make_shared&lt;Base2&gt;(name);
		// Irgendwie wird der Typ herausgefunden und das Äquivalent zu dieser
		// Anweisung generiert.
		result-&gt;Assign(Concrete2::Read(s));
		return result;
	}

	void Write(stream&amp; s) {
		scoped_write_guard guard(s);
		s &lt;&lt; name_;
		// Irgendwie wird der Typ herausgefunden
		content_-&gt;Write(s);
	}

private:
	Base2() {}

	// &quot;Type-Erasure&quot;-Boilerplate
	template&lt; typename T &gt; Assign(T&amp;&amp; obj) {
		content_.reset(new concrete_wrapper&lt;T&gt;(move(obj)));
	}

	struct wrapper_base {
		virtual void Some() = 0;
		virtual void Write(stream&amp; s) = 0;
	};

	template&lt; typename Content &gt;
	struct concrete_wrapper : public wrapper_base
	{
		template&lt; typename... Args &gt;
		concrete_wrapper(Args&amp;&amp;... args) : content_(forward&lt;Args&gt;(args)...) {}

		void Some() override { content_.Some(); }
		void Write(stream&amp; s) override { content_.Write(s); }
		Content content_;
	};

private:
	unique_ptr&lt;wrapper_base&gt; content_;
	string name_;
};

class Concrete2 {
public:
	void Some() {}
	void Write(stream&amp; s) {}
	static Concrete2 Read(stream&amp; s) {}
};
</code></pre>
<p>Was ist jetzt das Problem? Man kommt an keine Referenz von einem Typ, der sowohl das Interface von Base als auch das von Concrete2 anbietet. Das heißt, Client-Code, der sich auf spezifische Typen bezieht, muss mehr oder weniger zwei Referenzen mitschleppen, eine auf das Base2-Objekt und eine auf das typisierte Concrete2. Also nächster Anlauf:</p>
<pre><code class="language-cpp">class Concrete3;

class Base3 {
public:
	Base3(string name) : name_(name) {}

	void Some() {
		content_-&gt;Some();
	}

	static shared_ptr&lt;Base3&gt; Read(stream&amp; s) {
		scoped_read_guard guard(s);
		string name;
		s &gt;&gt; name;
		auto result = make_shared&lt;Base3&gt;(name);
		// Irgendwie wird der Typ herausgefunden und das Äquivalent zu dieser
		// Anweisung generiert.
		result-&gt;Assign(Concrete2::Read(s));
		return result;
	}

	void Write(stream&amp; s) {
		scoped_write_guard guard(s);
		s &lt;&lt; name_;
		// Irgendwie wird der Typ herausgefunden
		content_-&gt;Write(s);
	}

private:
	Base3() {}

	// &quot;Type-Erasure&quot;-Boilerplate
	template&lt; typename T &gt; Assign(T&amp;&amp; obj) {
		content_.reset(new concrete&lt;T&gt;(this, std::move(obj)));
	}

	struct concrete_base {
		virtual void Some() = 0;
		virtual void Write(stream&amp; s) = 0;
	};

	template&lt; typename Content &gt;
	struct concrete : public Content, public concrete_base
	{
		template&lt; typename... Args &gt;
		concrete(Base3* this_, Args&amp;&amp;... args) : Content(std::forward&lt;Args&gt;(args)...), this__(this_) {}

		void Some() override { Content::Some(); }
		void Write(stream&amp; s) override { Content::Write(s); }

		void GetName() { return this__-&gt;GetName(); }
		void SetName(string s) { this__-&gt;SetName(); }

	private:
		Base3* this__;
	};

private:
	unique_ptr&lt;concrete_base&gt; content_;
	string name_;
};

class Concrete3 {
public:
	void Some() {}
	void Write(stream&amp; s) {}
	static Concrete3 Read(stream&amp; s) {}
};

// Client-Code:
Base3::concrete&lt;Concrete3&gt;&amp; base.get_typed&lt;Concrete3&gt;(); /* oder besser auto, aber hier wollte ich den Typ mal zeigen */
</code></pre>
<p>Jetzt kann jeder Code, der Concrete3 als erweiterte Base3 behandeln will, eben eine Referenz auf Base3::concrete&lt;Concrete3&gt; erhalten und bekommt beide Schnittstellen in einem Objekt.<br />
Allerdings ist das Konstrukt schon sagen wir mal für das Problem extremal-komplex. Daher habe ich den Eindruck, mich megamäßig verrannt zu haben. Aus meinen Überlegungen über die Typausradierung und dem was ich hier versucht habe schließe ich folgendes: Des öfteren möchte ich zwar ableiten, aber &quot;umgekehrt&quot;. Die abgeleitet Klasse soll nicht die Basisklasse &quot;boxen&quot;, sondern andersherum (Und trotzdem sollen beide am Ende eine Einheit bilden). Und nichts anderes ist doch eigentlich Type-Erasure, das Umkehren der Besitzverhältnisse beim &quot;Ableiten&quot;, beziehungsweise beim Ins-Verhältnis-Setzen von Typen.</p>
<p>Ich schätze, jemand von euch wird einige gute Vorschläge haben, die das Ausgangsproblem &quot;richtig&quot; angehen oder vielleicht auch gedankliche Fehler auf meinem Lösungsweg finden. Es würde mich sehr, freuen, wenn ihr sie hier kundtun könntet!</p>
<p>Bis denne!<br />
Ratzefummel</p>
]]></description><link>https://www.c-plusplus.net/forum/topic/320411/inversion-durch-radierung</link><generator>RSS for Node</generator><lastBuildDate>Fri, 24 Jul 2026 03:41:49 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/320411.rss" rel="self" type="application/rss+xml"/><pubDate>Fri, 27 Sep 2013 09:12:40 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Inversion durch Radierung on Fri, 27 Sep 2013 09:12:40 GMT]]></title><description><![CDATA[<p>Hallo Leute,<br />
ich warte gerade Stundenlang auf den Bau der llvm - Suite(brauche mehr Kerne!), daher melde ich mich gerade mal mit einer Sache, die mir aufgefallen ist, während ich mich die letzten Tage nebenbei etwas eingehender mit Type-Erasure beschäftigt habe. Es wird eine Code-Schwall von 3 Implementierungs-Ansätzen folgen, aber ihr als erfahrene C++-Anwender werdet schnell die Muster entdecken, es ist nicht viel darüber hinaus gehender Inhalt im Quelltext, also bitte ich ohne Vorbehalt einfach mal drauf loszulesen - es wird gar nicht so lange dauern, wie es den Anschein hat (oder besser, wie es für micht hätte).</p>
<p>Das folgende ist ein Code-Konstrukt, das irgendwie immer wieder auftrat und mir auch immer wieder ein Dorn im Augen war - es geht um das Abspeichern und Lesen von &quot;polymorphen&quot; Objekten, bei denen die Basisklasse echte Funktionalität bietet, und nicht einfach nur alles &quot;runterreicht&quot;. Das &quot;Name&quot;-Attribut habe ich jetzt einfach mal als Repräsentant für soetwas hergenommen.</p>
<pre><code class="language-cpp">class Base {
public:
	Base(string name) : name_(move(name)) {}

	void ChangeName(string name) { name_ = move(name); }
	string GetName() { return name_; }

public:
	// Some ist eine Methode, die alle Base-Objekte haben sollen.
	virtual void Some() = 0;

	virtual void Write(stream s) {
		s &lt;&lt; name_;
	}

	virtual ~Base() {}
private:
	string name_;
};

class Derived : 
	public Base
{
public:
	Derived(string name) : Base(name) {}

	static shared_ptr&lt;Derived&gt; Read(stream&amp; s)
	{
		scoped_read_guard guard(s);
		string name;
		s &gt;&gt; name;
		return make_shared&lt;Derived&gt;(std::move(name));
		// Die abgelittene Klasse muss also der Basisklasse ihre Parameter
		// auslesen und sie immer durch ihren eigenen Konstruktor schleifen
		// und einen guard um das gesamte Objekt legen
	}

	void Write(stream s) override
	{
		scoped_write_guard guard(s);
		Base::Write(s);  // Ich muss dafür sorgen, dass Base geschrieben wird
		// Zudem kann Base im Stream keine &quot;Hülle&quot; um das gesamte Objekt legen
		// (Ich verwende gerne Scoped-Reader und -Writer, die das Dateiformat mit
		// Navigations und Redundanz-Daten anreichern.
		s &lt;&lt; &quot;blah&quot;;
	}

	void Some() override {}

	// ... und mehr Methoden
};

shared_ptr&lt;Base&gt; ReadObject1(stream&amp; s)
{
	// Irgendwie wird der Typ herausgefunden
	return Derived::Read(s);
}

void WriteObject1(stream&amp; s, Base&amp; b)
{
	b.Write(s);
}
</code></pre>
<p>Das Problem habe ich in den Kommentar geschrieben, bislang ist mir dafür irgendwie noch keine gute Lösung eingefallen.<br />
Nun kommt der Ansatz der Typ - Ausradierung:</p>
<pre><code class="language-cpp">class Concrete2;

class Base2 {
public:
	Base2(string name) : name_(name) {}

	void Some() {
		content_-&gt;Some();
	}

	static shared_ptr&lt;Base2&gt; Read(stream&amp; s) {
		scoped_read_guard guard(s);
		string name;
		s &gt;&gt; name;
		auto result = make_shared&lt;Base2&gt;(name);
		// Irgendwie wird der Typ herausgefunden und das Äquivalent zu dieser
		// Anweisung generiert.
		result-&gt;Assign(Concrete2::Read(s));
		return result;
	}

	void Write(stream&amp; s) {
		scoped_write_guard guard(s);
		s &lt;&lt; name_;
		// Irgendwie wird der Typ herausgefunden
		content_-&gt;Write(s);
	}

private:
	Base2() {}

	// &quot;Type-Erasure&quot;-Boilerplate
	template&lt; typename T &gt; Assign(T&amp;&amp; obj) {
		content_.reset(new concrete_wrapper&lt;T&gt;(move(obj)));
	}

	struct wrapper_base {
		virtual void Some() = 0;
		virtual void Write(stream&amp; s) = 0;
	};

	template&lt; typename Content &gt;
	struct concrete_wrapper : public wrapper_base
	{
		template&lt; typename... Args &gt;
		concrete_wrapper(Args&amp;&amp;... args) : content_(forward&lt;Args&gt;(args)...) {}

		void Some() override { content_.Some(); }
		void Write(stream&amp; s) override { content_.Write(s); }
		Content content_;
	};

private:
	unique_ptr&lt;wrapper_base&gt; content_;
	string name_;
};

class Concrete2 {
public:
	void Some() {}
	void Write(stream&amp; s) {}
	static Concrete2 Read(stream&amp; s) {}
};
</code></pre>
<p>Was ist jetzt das Problem? Man kommt an keine Referenz von einem Typ, der sowohl das Interface von Base als auch das von Concrete2 anbietet. Das heißt, Client-Code, der sich auf spezifische Typen bezieht, muss mehr oder weniger zwei Referenzen mitschleppen, eine auf das Base2-Objekt und eine auf das typisierte Concrete2. Also nächster Anlauf:</p>
<pre><code class="language-cpp">class Concrete3;

class Base3 {
public:
	Base3(string name) : name_(name) {}

	void Some() {
		content_-&gt;Some();
	}

	static shared_ptr&lt;Base3&gt; Read(stream&amp; s) {
		scoped_read_guard guard(s);
		string name;
		s &gt;&gt; name;
		auto result = make_shared&lt;Base3&gt;(name);
		// Irgendwie wird der Typ herausgefunden und das Äquivalent zu dieser
		// Anweisung generiert.
		result-&gt;Assign(Concrete2::Read(s));
		return result;
	}

	void Write(stream&amp; s) {
		scoped_write_guard guard(s);
		s &lt;&lt; name_;
		// Irgendwie wird der Typ herausgefunden
		content_-&gt;Write(s);
	}

private:
	Base3() {}

	// &quot;Type-Erasure&quot;-Boilerplate
	template&lt; typename T &gt; Assign(T&amp;&amp; obj) {
		content_.reset(new concrete&lt;T&gt;(this, std::move(obj)));
	}

	struct concrete_base {
		virtual void Some() = 0;
		virtual void Write(stream&amp; s) = 0;
	};

	template&lt; typename Content &gt;
	struct concrete : public Content, public concrete_base
	{
		template&lt; typename... Args &gt;
		concrete(Base3* this_, Args&amp;&amp;... args) : Content(std::forward&lt;Args&gt;(args)...), this__(this_) {}

		void Some() override { Content::Some(); }
		void Write(stream&amp; s) override { Content::Write(s); }

		void GetName() { return this__-&gt;GetName(); }
		void SetName(string s) { this__-&gt;SetName(); }

	private:
		Base3* this__;
	};

private:
	unique_ptr&lt;concrete_base&gt; content_;
	string name_;
};

class Concrete3 {
public:
	void Some() {}
	void Write(stream&amp; s) {}
	static Concrete3 Read(stream&amp; s) {}
};

// Client-Code:
Base3::concrete&lt;Concrete3&gt;&amp; base.get_typed&lt;Concrete3&gt;(); /* oder besser auto, aber hier wollte ich den Typ mal zeigen */
</code></pre>
<p>Jetzt kann jeder Code, der Concrete3 als erweiterte Base3 behandeln will, eben eine Referenz auf Base3::concrete&lt;Concrete3&gt; erhalten und bekommt beide Schnittstellen in einem Objekt.<br />
Allerdings ist das Konstrukt schon sagen wir mal für das Problem extremal-komplex. Daher habe ich den Eindruck, mich megamäßig verrannt zu haben. Aus meinen Überlegungen über die Typausradierung und dem was ich hier versucht habe schließe ich folgendes: Des öfteren möchte ich zwar ableiten, aber &quot;umgekehrt&quot;. Die abgeleitet Klasse soll nicht die Basisklasse &quot;boxen&quot;, sondern andersherum (Und trotzdem sollen beide am Ende eine Einheit bilden). Und nichts anderes ist doch eigentlich Type-Erasure, das Umkehren der Besitzverhältnisse beim &quot;Ableiten&quot;, beziehungsweise beim Ins-Verhältnis-Setzen von Typen.</p>
<p>Ich schätze, jemand von euch wird einige gute Vorschläge haben, die das Ausgangsproblem &quot;richtig&quot; angehen oder vielleicht auch gedankliche Fehler auf meinem Lösungsweg finden. Es würde mich sehr, freuen, wenn ihr sie hier kundtun könntet!</p>
<p>Bis denne!<br />
Ratzefummel</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2355929</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2355929</guid><dc:creator><![CDATA[Ratzefummel]]></dc:creator><pubDate>Fri, 27 Sep 2013 09:12:40 GMT</pubDate></item><item><title><![CDATA[Reply to Inversion durch Radierung on Fri, 27 Sep 2013 11:26:37 GMT]]></title><description><![CDATA[<p>Ich fuhr mal mit sowas ganz gut:</p>
<p>Das Format ist dann ungefähr</p>
<pre><code>Ork 
{
    x=10
    y=11
    z=2
    name=Hubert
}

Ghoul
{
    x=101
    y=34
    z=35
    name=Paul
    zauber=3,4,7,8,9,10,17
}
</code></pre>
<p>oder so. Die Klassen dazu wären</p>
<pre><code class="language-cpp">class ActiveObject{
    void doSomething()=0;
};
class Mob{
    Position pos;
};
class Monster:public Mob{
    string name;
};
class Ork:public Monster{
};
class Ghoul:public Monster{
    vector&lt;int&gt; zauber;
};
</code></pre>
<p>Implementiert ungefähr so, die Attributenamen zu schreiben und mit Prüfung wegzulesen, habe ich mal weggelassen.</p>
<pre><code class="language-cpp">class Base {
public:
	Base(string name) : name_(move(name)) {}
    Base(istream&amp; in){
        in&gt;&gt;name_;
    }
	void ChangeName(string name) { name_ = move(name); }
	string GetName() { return name_; }
public:
	// Some ist eine Methode, die alle Base-Objekte haben sollen.
	virtual void Some() = 0;

	virtual void Write(stream&amp; s) {
		s &lt;&lt; name_ &lt;&lt;'\n';
	}
	virtual ~Base() {}
private:
	string name_;
};

class Derived : 
	public Base
{
public:
	Derived(string name) : Base(name) {}
    Derived(istream&amp; in) : Base(in) /*,more base classes and members*/{
        //read attributes from derived
    }
	void Write(stream s) override
	{
		Base::Write(s);  // Ich muss dafür sorgen, dass Base geschrieben wird
		// Zudem kann Base im Stream keine &quot;Hülle&quot; um das gesamte Objekt legen
		// (Ich verwende gerne Scoped-Reader und -Writer, die das Dateiformat mit
		// Navigations und Redundanz-Daten anreichern.
		s &lt;&lt; &quot;blah&quot;;
		//Jo, die Hülle macht aber die Lese-Schreib-Factory drum.
	}

	void Some() override {}

	// ... und mehr Methoden
};

shared_ptr&lt;BaseObject&gt; readOrk(stream&amp; in){
    shared_ptr&lt;BaseObject&gt; p(new Ork(in));
    return p;
}
shared_ptr&lt;Base&gt; ReadObject1(stream&amp; in)
{
	// Irgendwie wird der Typ herausgefunden
	string type;
	in&gt;&gt;type;
	in.checkAndIgnore('{');
	shared_ptr res=readermap(type)(s);
	in.checkAndIgnore('}');
	return res;
}

void WriteObject1(stream&amp; s, Base&amp; b)
{
    s&lt;&lt;b.getClassName()&lt;&lt;'\n';
    s&lt;&lt;'{'&lt;&lt;'\n';
	b.Write(s);
    s&lt;&lt;'}'&lt;&lt;'\n';
    s&lt;&lt;'\n';
}
</code></pre>
<p>Das Format war sehr schnell und für mich genau richtig, weil ich in den Daten per Hand rumfuchteln wollte. Und später hätte ich ja nach TextStream und BinaryStream erweitern können. Aber so (mit leichten Speed-Änderungen) war es schon mehr als zehnmal so schnell wie Vorgängerlösung.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2355940</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2355940</guid><dc:creator><![CDATA[volkard]]></dc:creator><pubDate>Fri, 27 Sep 2013 11:26:37 GMT</pubDate></item><item><title><![CDATA[Reply to Inversion durch Radierung on Fri, 27 Sep 2013 10:49:17 GMT]]></title><description><![CDATA[<p>Hallo volkard,<br />
viel Dank schoneinmal, dass Du Dir die Zeit genommen hast!<br />
In Deiner Lösung verschiebst Du jetzt (für mich leider) das Problem, das ich zu lösen gedachte in die externe &quot;Lese-Schreib-Factory&quot;. Wie sähe die denn aus? Ich verstehe meine &quot;Base&quot;-Objekte jetzt als Elemente eines &quot;größeren, äußeren&quot; Datenmodells, und habe es mir im Gedanken so zurechtgelegt, dass das große äußere sich nicht darum kümmern muss, wie die Daten geschrieben werden. Wenn sich parallel zu der Modell-Datenstruktur eine Reader- und Writer-Factory befindet, sodass sich eben das Modell nicht um Details seiner Elemente und Subelemente kümmern muss, dann wäre das eigentlich auch in Ordnung für mich. Dann kann ich auch gut damit leben, dass der Stream in die Konstruktoren gegeben wird und die abgeleitete Klasse eben die Basisklasse beim Schreiben aufrufen muss.</p>
<p>Während ich in der Zwischenzeit so darüber nachgedacht habe, kam mir der Gedanke, dass es doch auch irgendwie cool wäre, wenn C++ &quot;reversed virtual&quot;- und &quot;reversed hiding&quot;-Funktionen hätte. Bei denen eben die Version in der Basisklasse die in der abgeleite Klasse überschreibt bzw. verdekt - aber der Kontext da ist, um von dort die abgeleitete Implementierung aufzurufen.</p>
<p>Ratzefummel</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2355949</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2355949</guid><dc:creator><![CDATA[Ratzefummel]]></dc:creator><pubDate>Fri, 27 Sep 2013 10:49:17 GMT</pubDate></item><item><title><![CDATA[Reply to Inversion durch Radierung on Fri, 27 Sep 2013 11:39:11 GMT]]></title><description><![CDATA[<p>Hast du da eine tiefe Vererbungshierachie? Ich werfe mal das hier in den Raum falls nicht:</p>
<pre><code>class A
{
public:
    void write(std::ostream&amp; s)
    {
        s &lt;&lt; 55 &lt;&lt; '\n';
        over_write(s);
    }
private:
   virtual void over_write(std::ostream&amp; s)
   {}
};

class B : public A
{
public:
private:
   void over_write(std::ostream&amp; s) final override
   {
        s &lt;&lt; 77 &lt;&lt; '\n';
   }
};
</code></pre>
<p>Ansonsten gäbe es noch die Möglichkeit, dass die Objekte einfach eine std::function next_write im Konstruktor nehmen.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2355954</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2355954</guid><dc:creator><![CDATA[cooky451]]></dc:creator><pubDate>Fri, 27 Sep 2013 11:39:11 GMT</pubDate></item><item><title><![CDATA[Reply to Inversion durch Radierung on Fri, 27 Sep 2013 12:16:49 GMT]]></title><description><![CDATA[<p>Hallo cooky,</p>
<p>ja - leider habe ich hier durchaus mit Veerbung von mehr als einer Stufe zu tun, daher ist dieser Ansatz auch &quot;unschön&quot;.<br />
Ich bin gerade am überlegen, beim Lesen keinen Stream durchzureichen, sondern einen Kontext, der per Type-Erasure (boost::any oder soetwas) Objekte zwischenspeichern kann, die dann in der umgekehrten Reihenfolge wieder zerstört werden. So kann jede Basisklasse etwas um die abgeleitete Klasse drumherumbasteln, bei dem die abgeleitete Klasse nicht zwischenfunken kann. Damit wäre der Konstruktionsfall schon einmal abgehandelt. Das müsste beim Zerstören eigentlich auch funktionieren, solange eben die abgeleitete Klasse daran denkt, die Basisklasse aufzurufen. Ja ich weiß, bei mir hat Type-Erasure gerade Hochkonjunktur <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 />
Ich warte aber auf jeden Fall ab, ob volkard noch etwas genauer auf diese Reader-Writer-Factory eingeht, die Chancen stehen immerhin gut, dass das eine total gute Lösung wäre, wenn ich sie nur vor meinen inneren Augen hätte!</p>
<p>Ratzefummel</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2355968</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2355968</guid><dc:creator><![CDATA[Ratzefummel]]></dc:creator><pubDate>Fri, 27 Sep 2013 12:16:49 GMT</pubDate></item><item><title><![CDATA[Reply to Inversion durch Radierung on Fri, 27 Sep 2013 12:25:00 GMT]]></title><description><![CDATA[<p>Ratzefummel schrieb:</p>
<blockquote>
<p>In Deiner Lösung verschiebst Du jetzt (für mich leider) das Problem, das ich zu lösen gedachte in die externe &quot;Lese-Schreib-Factory&quot;. Wie sähe die denn aus?</p>
</blockquote>
<p>Die steht fast vollständig schon da.</p>
<blockquote>
<pre><code>shared_ptr&lt;BaseObject&gt; readOrk(stream&amp; in){
    shared_ptr&lt;BaseObject&gt; p(new Ork(in));
    return p;
}
//Oder auch als
template&lt;class T&gt; read(istream&amp; in){
    shared_ptr&lt;BaseObject&gt; p(new T(in));
    return p;
}
//oder als 
template&lt;class T&gt;
struct Reader{
    shared_ptr&lt;BaseObject&gt; read(istream&amp; in)...
}
//oder ohne Namen als lamda

//Pro konkreter Klasse muss es eine solche Funktion geben und sie muss 
//in der globalen map registriert werden. 

//Das kann man mit Makros fein erledigen...
#define registerClass(className) registerClassSub(#className,&amp;read&lt;className&gt;)
//oder ähnlich. Dann schreibt man nur noch ans Ende der Derived.cpp
registerClass(Derived);
//und ab jetzt können die globalen Read- und Write-Funktionen damit umgehen. 

shared_ptr&lt;Base&gt; ReadObject1(stream&amp; in)
{
    // Irgendwie wird der Typ herausgefunden
    string type;
    in&gt;&gt;type;
    in.checkAndIgnore('{');
    shared_ptr res=readermap(type)(s);//dafür die globale map
    in.checkAndIgnore('}');
    return res;
}
 
void WriteObject1(stream&amp; s, Base&amp; b)
{
    s&lt;&lt;b.getClassName()&lt;&lt;'\n';
    s&lt;&lt;'{'&lt;&lt;'\n';
    b.Write(s);
    s&lt;&lt;'}'&lt;&lt;'\n';
    s&lt;&lt;'\n';
}
</code></pre>
</blockquote>
<p>Ich nannte sie nur factory, weil sie bei mir eine eine Klasse war. Und nicht ein paar globale Funktionen wie hier. Der Name erschien mir recht passend.</p>
<blockquote>
<p>Während ich in der Zwischenzeit so darüber nachgedacht habe, kam mir der Gedanke, dass es doch auch irgendwie cool wäre, wenn C++ &quot;reversed virtual&quot;- und &quot;reversed hiding&quot;-Funktionen hätte. Bei denen eben die Version in der Basisklasse die in der abgeleite Klasse überschreibt bzw. verdekt - aber der Kontext da ist, um von dort die abgeleitete Implementierung aufzurufen.</p>
</blockquote>
<p>Hmm. Ich bin nicht sicher, daß ich verstanden habe, was Du suchst.<br />
Vielleicht sowas?</p>
<pre><code>#include &lt;iostream&gt;
#include &lt;string&gt;
using namespace std;

class ActiveObject{
    public:
    virtual void write(ostream&amp; out)=0;//per write only one virtual call
    template&lt;typename Derived&gt; void doWrite(ostream&amp; out,Derived&amp; derived,char const* className){//dispatcher
        cout&lt;&lt;className&lt;&lt;&quot;{\n&quot;;
        derived.writeMembers(out);
        cout&lt;&lt;&quot;}\n\n&quot;;
    }
    void writeMembers(ostream&amp; out){
    }
};
class Mob:public ActiveObject{
    int pos;
public:
    Mob(int pos)
    :pos(pos){
    }
    void writeMembers(ostream&amp; out){
        ActiveObject::writeMembers(out);
        out&lt;&lt;&quot;  pos=&quot;&lt;&lt;pos&lt;&lt;'\n';
    }
};
class Monster:public Mob{
    string name;
    public:
    Monster(int pos,string name)
    :Mob(pos)
    ,name(name){
    }
    void writeMembers(ostream&amp; out){
        Mob::writeMembers(out);
        out&lt;&lt;&quot;  name=&quot;&lt;&lt;name&lt;&lt;'\n';
    }
};
class Ork:public Monster{
    public:
        Ork(int pos,string name)
        :Monster(pos,name){
        }
    void doSomething(){
        cout&lt;&lt;&quot;sing 'I am an Ork an shmash your Head, lalala.'\n&quot;;
    }
    void writeMembers(ostream&amp; out){
        Monster::writeMembers(out);
    }
    virtual void write(ostream&amp; out){
        ActiveObject::doWrite(out,*this,&quot;Ork&quot;);
    }
};

int main(){
    ActiveObject* o=new Ork(5,&quot;Otto&quot;);
    o-&gt;write(cout);
}
</code></pre>
<p>Ausgabe:</p>
<pre><code>Ork{
  pos=5
  name=Otto
}
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/2355971</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2355971</guid><dc:creator><![CDATA[volkard]]></dc:creator><pubDate>Fri, 27 Sep 2013 12:25:00 GMT</pubDate></item><item><title><![CDATA[Reply to Inversion durch Radierung on Fri, 27 Sep 2013 13:03:14 GMT]]></title><description><![CDATA[<p>Irgendwie fehlt mir eine genaue Erklärung, was das Problem überhaupt ist. Oder das &quot;Ziel&quot;. Was ist dieser ominöse &quot;scoped_read_guard&quot;? Ist der Problemrelevant?<br />
Was hat das Problem mit Typeerasure zu tun? Und ist &quot;Umgekehrt ableiten&quot; nicht das Selbe wie: &quot;Komposition ist, was ich eigentlich machen will&quot;?</p>
<p>Warum nicht so?</p>
<pre><code>class Base {
public:
    Base(string name) : name_(move(name)) {}

    void ChangeName(string name) { name_ = move(name); }
    string GetName() { return name_; }

public:
    virtual void Read(stream s) {// Warum gabs die Methode in der Base nicht?
        s &gt;&gt; name_;
    }

    virtual void Write(stream s) {
        s &lt;&lt; name_;
    }

    virtual ~Base() {}
private:
    string name_;
};

class Derived :
    public Base
{
public:
    Derived(string name) : Base(name) {}

    static shared_ptr&lt;Derived&gt; Read(stream&amp; s)
    {
        Base::Read(s);
        //was auch immer hier noch gebraucht wird lesen
    }

    void Write(stream s) override
    {
        Base::Write(s);
        //was auch immer hier noch gebraucht wird schreiben
    }

};
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/2355986</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2355986</guid><dc:creator><![CDATA[otze]]></dc:creator><pubDate>Fri, 27 Sep 2013 13:03:14 GMT</pubDate></item><item><title><![CDATA[Reply to Inversion durch Radierung on Fri, 27 Sep 2013 13:06:17 GMT]]></title><description><![CDATA[<p>Hallo volkard,</p>
<p>ja also meine globalen Funktionen waren eigentlich statisch im Object1 und auch ich habe so eine &quot;Registry&quot;, die mir typ-Namen oder ids typ_info-Objekte übersetzen kann. Das war das was ich in dem einen Kommentar mit &quot;irgendwie&quot; ausdrücken wollte, weil es ja nicht entscheidend für den Ablauf des Lese- oder Schreibvorgangs einer Klassenhierarchie war. Da wär mein Codebeispiel ja noch undurchsichtiger geworden^^.</p>
<p>Zu Deinem Beispiel: ich muss nocheinmal genau darüber nachdenken. Ich hatte jetzt eben die ganze Zeit in eine andere Richtung gedacht und muss nun erstmal wieder umdenken.<br />
Folgendes Datenlayout im Stream würde so ja erstmal kein Problem darstellen:</p>
<pre><code>object head
   object data
   type info
   sub-object head
      sub-object data
   sub-object tail
   final-object head
      final-object data
   final-object tail
object tail
</code></pre>
<p>Wobei final-object von sub-object ableitet und final-object der konkrete Typ war, der gespeichert wurde.<br />
Was ich jetzt aber klasse fänd' wäre folgende Struktur:</p>
<pre><code>object head
   object data
   type info
   final-object head
      sub-object head
         sub-object data
      sub-object tail
      final-object data
   final-object tail
object tail
</code></pre>
<p>Aber dafür müsste ich wohl irgendwie in der Initialisierer-Liste tricksen, beim Einlesen. Hrmmm. Auf jeden Fall sehe ich gerade, dass all meine initialen Ansätze sowieso nicht dafür getaugt hätten. Und ich habe gelernt, dass Type-Erasure nicht so gut dafür taugt, wenn man damit versucht Klassenhierarchien abzubilden!</p>
<p>Zur anderen Frage:<br />
Was ich meinte war folgendes:</p>
<pre><code class="language-cpp">class A {
  reversevirtual void foo() {
      //...
      foo(); // innerhalb der funktion ruft man &quot;nach oben&quot; auf.
      //...      
  }
};

class B : A {
  void foo() underride {}
};

B b;
b.foo(); // ruft A::foo auf und A::foo ruft dann B::foo auf.
</code></pre>
<p>War nur so ein fixer Gedanke, das würde aus irgendwelchen Gründen in gewissen Situationen bestimmt überhaupt gar keinen Sinn ergeben.</p>
<p>Ratzefummel</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2355989</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2355989</guid><dc:creator><![CDATA[Ratzefummel]]></dc:creator><pubDate>Fri, 27 Sep 2013 13:06:17 GMT</pubDate></item><item><title><![CDATA[Reply to Inversion durch Radierung on Fri, 27 Sep 2013 13:13:07 GMT]]></title><description><![CDATA[<p>Hallo otze!</p>
<pre><code class="language-cpp">class Derived :
    public Base
{
public:
    Derived(string name) : Base(name) {}

    static shared_ptr&lt;Derived&gt; Read(stream&amp; s)
    {
        Base::Read(s); // Read ist einer echte Methode von Base,
                       // wie kann das hier funktionieren?
    }

    void Write(stream s) override
    {
        Base::Write(s);
        //was auch immer hier noch gebraucht wird schreiben
    }

};
</code></pre>
<p>Ich kann gerade nur vermuten, dass Deine Idee darauf beruht, dass man Base &quot;leer&quot; Standard-konstruieren kann, sodass man die Möglichkeit hat, nach der Konstruktion &quot;Read&quot; auszuführen?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2355991</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2355991</guid><dc:creator><![CDATA[Ratzefummel]]></dc:creator><pubDate>Fri, 27 Sep 2013 13:13:07 GMT</pubDate></item><item><title><![CDATA[Reply to Inversion durch Radierung on Fri, 27 Sep 2013 13:57:28 GMT]]></title><description><![CDATA[<p>Ratzefummel schrieb:</p>
<blockquote>
<p>Was ich jetzt aber klasse fänd' wäre folgende Struktur:</p>
<pre><code>object head
   object data
   type info
   final-object head
      sub-object head
         sub-object data
      sub-object tail
      final-object data
   final-object tail
object tail
</code></pre>
</blockquote>
<p>Die Typen verschachtelt zu schreibe und zu lesen ist natürlich auch kein Problem</p>
<pre><code>class Ork{
   inherits Monster{
      inherits Mob{
        inherits ActiveObject{
        }
        has Position pos={
           int x=1
           int y=3
        }//end position
      }//end Mob
      has string name=&quot;Otto&quot;
   }//end of Monster
}//end Ork
</code></pre>
<p>Aber mein Ansatz kann nur genau in der Kontruktionsreihenfolge streamen und der Klassenname der final-Klasse (Ork) muss am Anfang stehen. Alles außer &quot;Ork&quot;, &quot;1&quot;, &quot;2&quot; und &quot;Otto&quot; wäre fest und würde nur als Schmuck mit herausgeschrieben werden und beim Lesen ignortiert. Mit der Verschachtelung hatte ich auch angefangen, sie aber dann weitgehend wieder fallenlassen, es war zu umständlich in solchen Dateien per Hand Daten zu ändern. Eine Position schreibt sich evtl gerne als &quot;pos{x=1;y=3}&quot; in eine Zeile und viel Vererbung gibt man einfach auch nicht aus.</p>
<p>War halt für mich angemessen, weil ich mir das Schreibformat frei aussuchen konnte und es vorwiegend um Schreibgeschwindigkeit ging.</p>
<p>Klassen fangen bei mir nach Möglichkeit nie Default-Kunstruktoren, deswegen kann ich schonmal nicht</p>
<pre><code>Ork* o=new Ork;
datei&gt;&gt;*o;
return 0;
</code></pre>
<p>machen.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2356002</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2356002</guid><dc:creator><![CDATA[volkard]]></dc:creator><pubDate>Fri, 27 Sep 2013 13:57:28 GMT</pubDate></item></channel></rss>