<?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[2 Fragen ...]]></title><description><![CDATA[<pre><code>class Foo
{
public:
	Foo() {}
	virtual ~Foo() {flush();}
	virtual void write(const Bar&amp;) = 0;
	virtual void flush() throw() = 0;
}
</code></pre>
<p>Der Beispielcode hat 2 Probleme:<br />
1. Linkerfehler weil flush() pure virtual ist<br />
2. vermutlich ein Crash beim Zerstören von abgeleiteten Klassen, da das richige flush() nicht mehr aufgerufen werden kann</p>
<p>Wie kann ich das umsetzen, was der Beispielcode prinzipiell beschreibt? Also abgeleitete Klassen dazu zwingen, flush() zu überschreiben und trotzdem sicherzustellen, dass auf jeden Fall flush() aufgerufen wird?</p>
]]></description><link>https://www.c-plusplus.net/forum/topic/314113/2-fragen</link><generator>RSS for Node</generator><lastBuildDate>Sat, 01 Aug 2026 15:50:58 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/314113.rss" rel="self" type="application/rss+xml"/><pubDate>Thu, 21 Feb 2013 02:22:19 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to 2 Fragen ... on Thu, 21 Feb 2013 02:22:19 GMT]]></title><description><![CDATA[<pre><code>class Foo
{
public:
	Foo() {}
	virtual ~Foo() {flush();}
	virtual void write(const Bar&amp;) = 0;
	virtual void flush() throw() = 0;
}
</code></pre>
<p>Der Beispielcode hat 2 Probleme:<br />
1. Linkerfehler weil flush() pure virtual ist<br />
2. vermutlich ein Crash beim Zerstören von abgeleiteten Klassen, da das richige flush() nicht mehr aufgerufen werden kann</p>
<p>Wie kann ich das umsetzen, was der Beispielcode prinzipiell beschreibt? Also abgeleitete Klassen dazu zwingen, flush() zu überschreiben und trotzdem sicherzustellen, dass auf jeden Fall flush() aufgerufen wird?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2300508</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2300508</guid><dc:creator><![CDATA[eine_frage]]></dc:creator><pubDate>Thu, 21 Feb 2013 02:22:19 GMT</pubDate></item><item><title><![CDATA[Reply to 2 Fragen ... on Thu, 21 Feb 2013 05:21:13 GMT]]></title><description><![CDATA[<p>eine_frage schrieb:</p>
<blockquote>
<pre><code>class Foo
{
public:
	Foo() {}
	virtual ~Foo() {flush();}
	virtual void write(const Bar&amp;) = 0;
	virtual void flush() throw() = 0;
}
</code></pre>
<p>Der Beispielcode hat 2 Probleme:<br />
1. Linkerfehler weil flush() pure virtual ist<br />
2. vermutlich ein Crash beim Zerstören von abgeleiteten Klassen, da das richige flush() nicht mehr aufgerufen werden kann</p>
<p>Wie kann ich das umsetzen, was der Beispielcode prinzipiell beschreibt? Also abgeleitete Klassen dazu zwingen, flush() zu überschreiben und trotzdem sicherzustellen, dass auf jeden Fall flush() aufgerufen wird?</p>
</blockquote>
<p>Das Foo nenne ich mal File. Und es soll die ReadFile,WriteFile und so aus der Win-Api wrappen.</p>
<p>Für mich tragfähig ist</p>
<pre><code>class StreamBuffer//geht auch für sockets, pipes, console. hierauf opertiert op&lt;&lt;
{
   virtual void flush()=0;
   virtual void write(const Bar&amp;) = 0;
   virtual ~Buffer(){
   }
   char* begin,writePos,end;
}
class File:public StreamBuffer
{
   ~Foo(){
      flush();//muss leider sein, ist aber absolut zu verschmerzen
   }
   //implementiert flush&amp;write
}
</code></pre>
<p>Alles zu automatisieren, riskiert man signifikant, zu viele Begriffe zu erfinden, die keine dauerhafte Bedeutung haben und nur in diesem einen Fall etwas bringen. Also daß man in fünf Jahren sich im Code gar nicht mehr zurechtfindet. Oder der neue Mitarbeiter aus dem Fenster springt. Man riskiert, den code komplett zu verboosteln.</p>
<pre><code>class StreamBuffer{
   virtual void flush()=0;
   virtual void write(const Bar&amp;) = 0;
   virtual void warnIfUsedBarely()=0;
}
class FileBuffer:public StreamBuffer{
   //implementiert flush&amp;write
}
template &lt;typename AbstractStreamBuffer&gt;
class ConcreteStreamBuffer:public AbstractStreamBuffer{
   ConcreteStreamBuffer(){
      flush();//geht doch
   }
   void warnIfUsedBarely(){};
}
class File:private ConcreteStreamBuffer&lt;FileBuffer&gt;
{
}
</code></pre>
<p>Auch mal gucken, wie std::&lt;iostream&gt; dabei vorgeht. Onkel Struppi war vor 20 Jahren schon erstaunlich weit.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2300515</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2300515</guid><dc:creator><![CDATA[volkard]]></dc:creator><pubDate>Thu, 21 Feb 2013 05:21:13 GMT</pubDate></item><item><title><![CDATA[Reply to 2 Fragen ... on Thu, 21 Feb 2013 07:50:40 GMT]]></title><description><![CDATA[<p>Das gibt schon mal keinen Linkerfehler mehr (VS 2010 Express):</p>
<pre><code>class Foo
{
   public:
      Foo() {}
      virtual ~Foo() {test();}
      virtual void flush() throw() = 0;

   private:
      void test(){flush();}
};
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/2300536</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2300536</guid><dc:creator><![CDATA[Belli]]></dc:creator><pubDate>Thu, 21 Feb 2013 07:50:40 GMT</pubDate></item><item><title><![CDATA[Reply to 2 Fragen ... on Thu, 21 Feb 2013 08:08:58 GMT]]></title><description><![CDATA[<p>Das Problem ist, dass die abgeleitete Klasse vor der Basisklasse aufgeräumt wird. Und dazu gehört, die vtable, also die Sprungtabelle für virtuelle Methoden anzupassen. Im Destruktor werden damit keine virtuellen Methoden der abgeleitete Klasse aufgerufen.</p>
<p>Das macht auch Sinn, da im Destruktor die abgeleitete Klasse möglicherweise seine Member bereits zerstört hat. Dann würde eine virtuelle Methode der abgeleitete Klasse möglicherweise auf diese Member zugreifen wollen.</p>
<p>Beispiel:</p>
<pre><code>class Bar : public Foo
{
      std::ofstream* out;
   public:
      ~Bar()
      {
          delete out;
      }
      virtual void flush() throw()
      {
          out-&gt;flush();
      }
}
</code></pre>
<p>Würde der Destruktor von Foo Bar::flush() aufrufen, würde Bar::flush() auf out zugreifen, welches aber bereits gelöscht ist. Da hilft es auch nicht, den Aufruf vor dem Compiler zu verstecken, indem man eine test()-Methode schreibt. Das erschwert lediglich, dass der Compiler vor diesem Fehler warnen kann.</p>
<p>Das gleiche gilt im übrigen für den Konstruktor. Auch dort kann man keine virtuellen Methoden der abgeleiteten Klasse aufrufen.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2300543</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2300543</guid><dc:creator><![CDATA[ich bins]]></dc:creator><pubDate>Thu, 21 Feb 2013 08:08:58 GMT</pubDate></item><item><title><![CDATA[Reply to 2 Fragen ... on Thu, 21 Feb 2013 08:10:52 GMT]]></title><description><![CDATA[<p>Belli schrieb:</p>
<blockquote>
<p>Das gibt schon mal keinen Linkerfehler mehr (VS 2010 Express):</p>
<pre><code>class Foo
{
   public:
      Foo() {}
      virtual ~Foo() {test();}
      virtual void flush() throw() = 0;
      
   private:
      void test(){flush();}
};
</code></pre>
</blockquote>
<p>Aber das ruft nach Ärger.<br />
Im Dtor von Foo ist das Bar-Objekt schon teildestruiert und kein Bar-Objekt mehr, sondern nur noch ein Foo-Objekt. Darum wird die virtuelle Funktion nicht mehr korrekt aufgerufen, also nicht im Sinne des Erfinders.</p>
<p>Hab mal getestet und das macht mich ganz durcheinander.</p>
<pre><code>#include &lt;iostream&gt;
using namespace std;

class Foo
{
   public:
      Foo() {}
      virtual ~Foo() {test();}
      virtual void flush()= 0;

   private:
      void test(){flush();}
};
void Foo::flush(){
        cout&lt;&lt;&quot;fooflush\n&quot;;
}

class Bar{
    virtual void flush(){
        cout&lt;&lt;&quot;barflush\n&quot;;
    }
};

int main(){
    cout&lt;&lt;&quot;start\n&quot;;
    {
        Bar *b=new Bar;
        delete b;//flusht gar nicht? 
    }
    cout&lt;&lt;&quot;fertig\n&quot;;
}
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/2300545</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2300545</guid><dc:creator><![CDATA[volkard]]></dc:creator><pubDate>Thu, 21 Feb 2013 08:10:52 GMT</pubDate></item><item><title><![CDATA[Reply to 2 Fragen ... on Thu, 21 Feb 2013 09:26:56 GMT]]></title><description><![CDATA[<p>Ableitung von Foo vergessen.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2300562</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2300562</guid><dc:creator><![CDATA[camper]]></dc:creator><pubDate>Thu, 21 Feb 2013 09:26:56 GMT</pubDate></item><item><title><![CDATA[Reply to 2 Fragen ... on Thu, 21 Feb 2013 09:31:42 GMT]]></title><description><![CDATA[<p>Naja, leuchtet mir ein. Dass man im Konstr. keine virtuellen Methoden aufrufen kann, war klar, die abgeleiteten Klassen sind <strong>noch nicht</strong> konstruiert.</p>
<p>Im Gegenzug sind sie dann im Destr. <strong>nicht mehr</strong> konstruiert ...</p>
<p>Demnach lässt sich die Aufgabenstellung nicht erfüllen. Es ist stattdessen notwendig, in den abgeleiteten Klassen explizit flush() aufzurufen.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2300563</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2300563</guid><dc:creator><![CDATA[Belli]]></dc:creator><pubDate>Thu, 21 Feb 2013 09:31:42 GMT</pubDate></item><item><title><![CDATA[Reply to 2 Fragen ... on Thu, 21 Feb 2013 12:23:37 GMT]]></title><description><![CDATA[<p>Alternative: Zerlege das Ganze in zwei Klassen(-hierarchien), analog zu den iostreams mit ihren streambufs. Damit sorgst du dafür, dass das was auch immer da geflusht werden muss, im DTor von Foo noch existiert:</p>
<pre><code>class Flushable {
public: 
  virtual void flush() = 0;
};

class Foo
{
    Flushable* f_;
public:
    Foo(Flushable* f) : f_(f) {}
    virtual ~Foo() { f_-&gt;flush();}
};
</code></pre>
]]></description><link>https://www.c-plusplus.net/forum/post/2300593</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2300593</guid><dc:creator><![CDATA[pumuckl]]></dc:creator><pubDate>Thu, 21 Feb 2013 12:23:37 GMT</pubDate></item><item><title><![CDATA[Reply to 2 Fragen ... on Thu, 21 Feb 2013 22:57:48 GMT]]></title><description><![CDATA[<p>pumuckl schrieb:</p>
<blockquote>
<p>Alternative: Zerlege das Ganze in zwei Klassen(-hierarchien), analog zu den iostreams mit ihren streambufs. Damit sorgst du dafür, dass das was auch immer da geflusht werden muss, im DTor von Foo noch existiert:</p>
<pre><code>class Flushable {
public: 
  virtual void flush() = 0;
};

class Foo
{
    Flushable* f_;
public:
    Foo(Flushable* f) : f_(f) {}
    virtual ~Foo() { f_-&gt;flush();}
};
</code></pre>
</blockquote>
<p>Eine Frage, we hat hier die Verantwortung für die Lebenszeit des Flushables? Sonst könnte die abgeleitete Klasse nacher meinen, das Objekt im Destruktor zu zerstören, da währ der Sinn des ganzen dahin. Beim std::filebuf wird das Objekt im eigenen Destruktor &quot;geflusht&quot;, der std::fstream hat ja da nichts mehr mit zu tun, besonders da sein Destruktor implizit deklariert ist.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2300855</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2300855</guid><dc:creator><![CDATA[Cachus]]></dc:creator><pubDate>Thu, 21 Feb 2013 22:57:48 GMT</pubDate></item></channel></rss>