Hallo zusammen,
ich habe da eine Frage: Es gibt eine Klasse Paint. Von dieser Klasse
werden mehrere Instanzen erzeugt. Jetzt benötige ich eine Variable, die
in allen Instanzen gelesen und geschrieben werden kann. Also wenn
Instanz 1 der Klasse Paint eine 10 in die Variable myVar schreibt, soll
auch Instanz 2 in myVar eine 10 stehen haben.
Bisher habe ich es so gelöst, dass ich mir außerhab der Klasse Speicher
hole und die Adresse dem Konstruktor von Paint übergebe. Aber das kann
man sicher eleganter machen?!
Danke für eure Hilfe!
Grüße Pit
Pit schrieb:> Jetzt benötige ich eine Variable, die in allen Instanzen gelesen und> geschrieben werden kann.
Darf man fragen, welchen Sinn dies haben soll?
Dass alle anderen diesen Wert lesen können: Ja, meinetwegen. Aber warum
sollten alle anderen diesen Wert verändern können? Das wäre dann ja
quasi eine globale Variable innerhalb dieser Klasse. Ist vielleicht
nicht unbedingt das, was man will.
> Das wäre dann ja quasi eine globale Variable
ja aber die kann man privat machen.
> welchen Sinn dies haben soll?
Grund könnte sein wenn man z.B. einen alle Instanzen der Klasse zählen
will: Im Kostruktor Variable +1, im Destruktor -1.
Andreas Richter schrieb:> Grund könnte sein wenn man z.B. einen alle Instanzen der Klasse zählen> will: Im Kostruktor Variable +1, im Destruktor -1.
Nicht dass man das bei realer Software jemals machen würde ;-) aber
okay.
Hallo Pit,
Pit schrieb:> ich habe da eine Frage: Es gibt eine Klasse Paint. Von dieser Klasse> werden mehrere Instanzen erzeugt. Jetzt benötige ich eine Variable, die> in allen Instanzen gelesen und geschrieben werden kann. Also wenn> Instanz 1 der Klasse Paint eine 10 in die Variable myVar schreibt, soll> auch Instanz 2 in myVar eine 10 stehen haben.>> Bisher habe ich es so gelöst, dass ich mir außerhab der Klasse Speicher> hole und die Adresse dem Konstruktor von Paint übergebe. Aber das kann> man sicher eleganter machen?!
Ja, mit einer Klassenvariablen -- also einer Variablen, die "static"
deklariert ist:
Hallo Mark,
Mark Brandis schrieb:> Darf man fragen, welchen Sinn dies haben soll?
Inwiefern hilft Dir Deine Gegenfrage dabei, die Frage des OP zu
beantworten?
Liebe Grüße,
Karl
Hi,
immer noch nicht ganz richtig:
Dings() { this->count++; }
es muss
Dings() { Dings::count++; } heissen, 'count' wird ja eben gerade
nicht über 'this' referenziert.
LG Karl
Hallo Karl,
Karl M. schrieb:> Hi,> immer noch nicht ganz richtig:> Dings() { this->count++; }>> es muss> Dings() { Dings::count++; } heissen, 'count' wird ja eben gerade> nicht über 'this' referenziert.> LG Karl
Dat kannste innerhalb der Klasse halten wie die Maurer. Da kannst Du
1
Dings(){this->count++;}
oder
1
Dings(){Dings::count++;}
oder sogar nur
1
Dings(){count++;}
schreiben. Das "Dings::" wird außerhalb der Klasse Dings nur gebraucht,
um dem Compiler mitzuteilen, wo er das entsprechende Symbol findet;
innerhalb der Klasse kann man das Dings:: benutzen, es weglassen, oder
-- ich mache das immer zur Verbesserung der Lesbarkeit -- es explizit
mit "this->" qualifizieren.
LG,
Karl
Karl M. schrieb:> Hi,> immer noch nicht ganz richtig:
Ist egal.
Beides geht. Aus einer Memberfunktion heraus kann man auch komplett
darauf verzichten.
Der Compiler weiss ja sowieso, dass der Member static ist.
Karl Käfer schrieb:> Achtung: das ist NICHT thread-safe. Dazu müssten die Schreibzugriffe> auf Dings::count atomar gemacht werden (etwa mit std::mutex).
wenn es eine zahl ist, gibt es auf jedem System passende atomare befehle
ohne das man einen mutex braucht.
interlockedincrement usw.
Karl Käfer schrieb:> Mark Brandis schrieb:>> Darf man fragen, welchen Sinn dies haben soll?>> Inwiefern hilft Dir Deine Gegenfrage dabei, die Frage des OP zu> beantworten?
Wir haben hier des öfteren Leute, die sich in eine spezifische Lösung zu
einem bestimmten Problem verrannt haben. Anstatt aber die eigentliche
Aufgabenstellung zu beschreiben, kommen sie bereits mit ihrem
spezifischen (und meistens ungeeigneten) Lösungsansatz an.
Deshalb die Frage "wozu soll das eigentlich gut sein". Nicht ganz selten
stellt sich dann heraus, dass der Themenersteller gar nicht wirklich das
haben will, wonach er gefragt hat.
Mark Brandis schrieb:> Andreas Richter schrieb:>> Grund könnte sein wenn man z.B. einen alle Instanzen der Klasse zählen>> will: Im Kostruktor Variable +1, im Destruktor -1.>> Nicht dass man das bei realer Software jemals machen würde ;-) aber> okay.
Natürlich macht man das in ganz realer Software. Natürlich nicht als
Selbstzweck, die Zahl der lebenden Instanzen einer Klasse (im
allgemeinen) interessieren normalerweise tatsächlich wirklich kein
Schwein.
Aber der Unterschied, ob es Null oder eine von Null verschiedene Zahl
von Instanzen gibt, ist sehr oft sogar überaus interessant, z.B. wenn
die Klasse in statischen Methoden und Membern eine wertvolle Resource
verwaltet, die von allen Instanzen dieser Klasse genutzt wird, dann
entscheidet nämlich der Übergang Null<->nicht Null darüber, ob diese
Resource alloziert werden muß oder freigegeben werden kann.
Tja, und die einfachste und effizienteste Methode, das zu erreichen, ist
tatsächlich, stumpf die Instanzenzahl hoch-/runterzuzählen (natürlich
mit den entsprechenden Prüfungen "erreicht null" nach dem Runterzählen
und "ist null" vor dem Hochzählen mit den entsprechenden Aufrufen von
"FreeValuableResource" und "AllocValuableResource" als Folge.
Bei "managed"-Sprachen, z.B. im Java- und .net-Dunstkreis funktioniert
sogar die gesamte Speicherverwaltung nach genau diesem Prinzip. Wobei
hier die Instanz einer Klasse der "wertvollen Resource" entspricht
(nämlich dem von ihr benötigten Speicher) und jede Referenz auf die
Klasseninstanz einer Instanz dieser "Speicherbereichs-Klasse"
entspricht.
Zusammenfassend kann man sagen, daß so ein Designpattern de facto
grundlegende Basis aller objektorientierten Sprachen darstellt.
Mark Brandis schrieb:> Deshalb die Frage "wozu soll das eigentlich gut sein". Nicht ganz selten> stellt sich dann heraus, dass der Themenersteller gar nicht wirklich das> haben will, wonach er gefragt hat.
Ich zeichne ein paar Seiten mit der Klasse Paint. Die Logik, welche
Seite gezeichnet werden soll ist in einer anderen Klasse implementiert.
Bei Paint handelt es sich quasi um eine dumme Klasse, die das tut, was
sie gesagt bekommt. Nun wäre es für mich aber hilfreich, wenn ich einen
Seitenwechsel innerhalb von paint mitbekomme. Daher wollte ich eine
Variable aktuelleSeite und eine Variable alteSeite. Ich habe es nun über
eine Get und Set-Funktion realisiert. Ist vielleicht schöner so?!
Pit schrieb:> Ich habe es nun über> eine Get und Set-Funktion realisiert. Ist vielleicht schöner so?!
Definitiv.
Denn es ist nicht einzusehen, warum alle Instanzen der Paint Klasse
immer dieselbe Seite malen sollen.
Eine Instanz malt zb auf den Monitor, während eine andere Instanz alle
Seiten einzeln malt um sie am Drucker ausgeben zu können.
> Daher wollte ich eine Variable aktuelleSeite und eine Variable alteSeite.
Und die von aussen public zugreifbar, damit die andere Klasse da
rankommt?
Ui, ui. Damit unterläufst du genau das, warum man die ganze OOP
überhaupt aufgezogen hat.
Karl Heinz schrieb:> Ui, ui. Damit unterläufst du genau das, warum man die ganze OOP> überhaupt aufgezogen hat.
So ist das keineswegs, schliesslich gibt es Klassenvariablen, die für
eine Klasse nur einmal vorkommen, waren denn die Leute blöd, die das
implementiert haben? Im Gegenteil, gerade für Initialisierungen wird
sowas gebraucht, und es gibt eine klare Trennung zwischen diesen und
Variablen, die für jede Instanz extra angelegt werden - klarer gehts
nicht. Es ist halt nicht alles suspekt was man nicht kennt.
Georg
Georg schrieb:> Karl Heinz schrieb:>> Ui, ui. Damit unterläufst du genau das, warum man die ganze OOP>> überhaupt aufgezogen hat.>> So ist das keineswegs, schliesslich gibt es Klassenvariablen, die für> eine Klasse nur einmal vorkommen, waren denn die Leute blöd, die das> implementiert haben?
Davon hab ich nicht gesprochen.
Ich rede von public Variablen, die jeder andere dahergelaufene Code
einfach ändern kann, ohne dass die Klasse dies mitkriegt. Das ist um
keinen Deut besser, als haufenweise globalen Variablen zu haben.
Ob die static sind oder nicht, ist da ausnahsweise überhaupt nicht von
Belang.
> Es ist halt nicht alles suspekt was man nicht kennt.
Wir können ja gerne mal testen, was du alles kennst was ich in C++ nicht
kenne.
Hallo Karl Heinz,
Karl Heinz schrieb:> Ich rede von public Variablen, die jeder andere dahergelaufene Code> einfach ändern kann, ohne dass die Klasse dies mitkriegt. Das ist um> keinen Deut besser, als haufenweise globalen Variablen zu haben.
Es ist eher wie eine globale Struct und insofern trotzdem besser als ein
Haufen globaler Variablen. Dieser Unterschied mag zwar graduell sein,
ist aber trotzdem vorhanden. ;-)
Darüber hinaus bietet C++ natürlich wunderbare Möglichkeiten, so etwas
auch ohne public-Membervariablen zu lösen -- für sowas hat der liebe
Bjarne das Schlüsselwort "friend" erfunden.
Liebe Grüße,
Karl
Karl Käfer schrieb:> Das "Dings::" wird außerhalb der Klasse Dings nur gebraucht,> um dem Compiler mitzuteilen, wo er das entsprechende Symbol findet;
Warum da aber die andere Variante nicht funktioniert, habe ich noch
nicht verstanden, also:
1
Dingsd;
2
d.count++;
> innerhalb der Klasse kann man das Dings:: benutzen, es weglassen, oder> -- ich mache das immer zur Verbesserung der Lesbarkeit -- es explizit> mit "this->" qualifizieren.
Aber gerade die Lesbarkeit verschlechtert sich dadurch doch. Das this
suggeriert - wie man an der Diskussion sieht - daß es zum Objekt gehört
und nicht zur Klasse.
Karl Käfer schrieb:> Das> "Dings::" wird außerhalb der Klasse Dings nur gebraucht, um dem Compiler> mitzuteilen, wo er das entsprechende Symbol findet; innerhalb der Klasse> kann man das Dings:: benutzen, es weglassen, oder -- ich mache das immer> zur Verbesserung der Lesbarkeit -- es explizit mit "this->"> qualifizieren.
Manchmal muss man es auch verwenden. Wenn es z.B. eine Member-Variable
mit dem Namen x gibt und man sowas hier à la Setter-Methode macht:
1
voidMyClass::setValue(intx)
2
{
3
this->x=x;
4
}
Wobei man natürlich die zu übergebende Variable auch anders nennen kann
als gerade x.
Rolf Magnus schrieb:> Karl Käfer schrieb:>> Das "Dings::" wird außerhalb der Klasse Dings nur gebraucht,>> um dem Compiler mitzuteilen, wo er das entsprechende Symbol findet;>> Warum da aber die andere Variante nicht funktioniert, habe ich noch> nicht verstanden, also:>>
1
>Dingsd;
2
>d.count++;
3
>
Weil
1
private:
2
staticintcount;
count private ist.
Wenn es public wäre, könntest du selbstverständlich auch über das Objekt
auf einen static Member zugreifen.
>> -- ich mache das immer zur Verbesserung der Lesbarkeit -- es explizit>> mit "this->" qualifizieren.>> Aber gerade die Lesbarkeit verschlechtert sich dadurch doch.
Ist zwar Geschmackssache, aber ich seh das auch so.
Zumal in Memberfunktionen eigentlich so gut wie alle Zugriffe auf
Variablen, äh, Zugriffe auf Membervariablen sein sollten. Ich seh da
wenig Sinn darin, praktisch alle Zugriffe mit einer Erwähnung des this
Pointers zu spicken und so massenhaft Character-Noise zu erzeugen.
Gerade in Member-Funktionen ist es eigentlich der Default Fall, dass
eine benutzte Variable zum Objekt (bzw hier eben zur Klasse) gehört. Die
Umkehrung ist das, was selten der Fall sein sollte und kenntlich gemacht
gehört: wenn eine Variable eben nicht zum Objekt bzw. Klasse gehört.
Karl Heinz schrieb:> Wenn es public wäre, könntest du selbstverständlich auch über das Objekt> auf einen static Member zugreifen.
Ah richtig, da hatte ich gerade in die falsche Richtung gedacht. Bei
Objekten get das, nur bei Typen nicht. Also sowas geht nicht:
1
std::map<std::string,std::string>m;
2
// ...
3
m.const_iteratorresult=m.find("foo");
Man muß stattdessen den ganzen Rattenschwanz vom Typ nochmal
hinschreiben. Nun ist das ja seit C++11 durch Dinge wie auto und
decltype nicht mehr nötig.