{"id":16,"date":"2008-12-11T11:46:30","date_gmt":"2008-12-11T09:46:30","guid":{"rendered":"http:\/\/blog.familie-heming.de\/?p=16"},"modified":"2014-09-04T07:01:32","modified_gmt":"2014-09-04T06:01:32","slug":"static-attribute-in-c-klassen","status":"publish","type":"post","link":"https:\/\/blog.familie-heming.de\/?p=16","title":{"rendered":"static-Attribute in C++ Klassen"},"content":{"rendered":"<p>An dieser Stelle soll die Aussage<\/p>\n<p align=\"center\"><em>&#8222;Statische Klassenattribute m\u00fcssen au\u00dferhalb der Klassendefinition initialisiert werden.&#8220;<\/em><\/p>\n<p>ein wenig n\u00e4her untersucht werden. Betrachtet sei dazu die folgende Klassendefinition:<br \/>\n<code><br \/>\nclass KlasseMitStaticElement {<br \/>\npublic:<br \/>\nstatic int anzahl;<br \/>\nKlasseMitStaticElement() {<br \/>\ncout &lt;&lt; \"Konstruktor aufgerufen\" &lt;&lt; endl;<br \/>\nKlasseMitStaticElement::anzahl++;<br \/>\n}<br \/>\n};<br \/>\n<\/code><br \/>\nGeht man nun nach der oben genannten Regel vor, so w\u00fcrde die naive Initialisierung (eigentlich eine Zuweisung, siehe Zusatz unten) so aussehen: <code>KlasseMitStaticElement::anzahl = 0;<\/code>. Leider resultiert diese Zeile in einen Kompilerfehler, es wird \u00fcber das <em>undefined symbol &#8222;KlasseMitStaticElement::anzahl&#8220;<\/em> gemeckert. Faszinierenderweise gelingt die Initialisierung aber mit\u00a0 <code>int KlasseMitStaticElement::anzahl = 0;<\/code> warum?<\/p>\n<p>Dazu m\u00fcssen Deklaration, Definition und Initialisierung Begrifflich sauber voneinander getrennt werden. Ich verweise dazu auf ein <a href=\"http:\/\/www.c-plusplus.de\/forum\/viewtopic-var-t-is-61231.html\" title=\"Unterschied Deklaration, Definition, Initialisierung\">C++-Forum<\/a>, in dem von Benjamin Kaufmann folgendes geschrieben ist:<\/p>\n<ul>\n<li><span style=\"font-weight: bold\">Deklaration: <\/span>Ein Programmausdruck der einen Namen in einen Scope ein- bzw. wiedereinf\u00fchrt.<\/li>\n<li><span style=\"font-weight: bold\">Definition:<\/span> Eine Deklaration die die Details einer Entit\u00e4t bekannt macht oder, im Fall von Variablen, die dazu f\u00fchrt, dass Speicher f\u00fcr die Entit\u00e4t reserviert wird. Eine Deklaration einer Klasse (struct, class, enum, union) Funktion oder Methode wird zu einer Definition, wenn auf die Deklaration ein in geschweiften Klammern eingeschlossener Block folgt.<br \/>\nVariablendeklarationen sind immer auch Definitionen es sei denn, der Deklaration ist ein <span style=\"font-style: italic\">extern<\/span> vorangestellt. <span style=\"font-weight: bold\"><\/span><\/li>\n<li><span style=\"font-weight: bold\">Initialisierung:<\/span> Eine Definition mit expliziter Anfangswertzuweisung.<\/li>\n<\/ul>\n<p>Nach obigen Versuchen stellen wir also fest, dass auch die Voranstellung von <em>static<\/em> im Klassenkontext dazu f\u00fchrt, dass eine urspr\u00fcngliche Definition nur eine Deklaration darstellt. In dem Beispielprogramm <a href=\"http:\/\/blog.familie-heming.de\/wp-content\/uploads\/2008\/12\/matstatic.zip\" title=\"matstatic.zip\">matstatic.zip<\/a> habe ich als statisches Attribut keinen einfachen Datentyp genutzt, sondern eine Klasse mit Standardkonstruktor verwendet. So kann man sehen, dass die Definition der Variable nach der Klassendefinition dazu f\u00fchrt, dass der Standardkonstruktor aufgerufen wird.<\/p>\n<p>Bezogen auf das obige Beispiel stellt man also fest, dass die explizite Initialisierung (und damit implizite Definition) der Variable <code>anzahl<\/code> nicht notwendig ist. Eine Definition wie\u00a0 <code>int KlassenMitStaticElement::anzahl;<\/code> w\u00e4re ausreichend, da die integer-Variable damit automatisch vom Compiler mit 0 initialisiert wird.<\/p>\n<p>Ob die automatische Initialisierung einen allgemeinen C++-Standard oder nur eine Laune meines Compilers darstellt, ist mir zwar nicht bekannt &#8212; eventuell kann ohne Anfangszuweisung der Schwachsinn, der vorher an der Speicherstelle der Variable stand, von uns weiter genutzt werden &#8212; aber die anfangs erw\u00e4hnte Aussage muss korrigiert werden.<\/p>\n<p align=\"center\"><em>&#8222;Statische Klassenattribute m\u00fcssen au\u00dferhalb der Klassendefinition DEFINIERT werden.&#8220;<\/em><\/p>\n<p>Zusatz:<\/p>\n<p>\u00dcber Initialisierungen zu sprechen, stellt sich als nicht ganz einfach heraus, da das Verhalten des Compilers nicht nur von der Anweisung selbst, sondern auch von ihrer Position im Quelltext abh\u00e4ngt. Eine implizite Initialisierung mit 0 wird f\u00fcr die Anweisung <code>int a;<\/code> als globale Definition vorgenommen, w\u00e4hrend die gleiche Anweisung im Funktionskontext einen undefinierten Wert f\u00fcr a beh\u00e4lt.<\/p>\n<p>Man k\u00f6nnte nun auf der einen Seite eine implizite und eine explizite Initialisierung unterscheiden (nach der Definition aus dem Forum w\u00e4re nur die explizite Initialisierung \u00fcberhaupt eine Initialisierung), oder man geht dem Problem aus dem Weg, indem man jede Variablendefinition auch gleichzeitig mit einer expliziten Initialisierung im Quelltext versieht. Da nur Variablen mit eindeutig zugewiesenen Werten semantischen Sinn ergeben, kann man die ganz oben genannte Aussage als Merkregel sehr gut f\u00fcr die Praxis verwenden. Doch sollten wir ein wenig verallgemeinern:<\/p>\n<p align=\"center\"><em>&#8222;MERKREGEL: Alle Variablen m\u00fcssen initialisiert werden. Bei statischen Klassenattributen geschieht dies au\u00dferhalb der Klassendefinition.&#8220;<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>An dieser Stelle soll die Aussage &#8222;Statische Klassenattribute m\u00fcssen au\u00dferhalb der Klassendefinition initialisiert werden.&#8220; ein wenig n\u00e4her untersucht werden. Betrachtet sei dazu die folgende Klassendefinition: class KlasseMitStaticElement { public: static int anzahl; KlasseMitStaticElement() { cout &lt;&lt; &#8222;Konstruktor aufgerufen&#8220; &lt;&lt; endl; &hellip; <a href=\"https:\/\/blog.familie-heming.de\/?p=16\">Weiterlesen <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[5],"tags":[],"_links":{"self":[{"href":"https:\/\/blog.familie-heming.de\/index.php?rest_route=\/wp\/v2\/posts\/16"}],"collection":[{"href":"https:\/\/blog.familie-heming.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.familie-heming.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.familie-heming.de\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.familie-heming.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=16"}],"version-history":[{"count":1,"href":"https:\/\/blog.familie-heming.de\/index.php?rest_route=\/wp\/v2\/posts\/16\/revisions"}],"predecessor-version":[{"id":185,"href":"https:\/\/blog.familie-heming.de\/index.php?rest_route=\/wp\/v2\/posts\/16\/revisions\/185"}],"wp:attachment":[{"href":"https:\/\/blog.familie-heming.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=16"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.familie-heming.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=16"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.familie-heming.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=16"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}