Forum: PC-Programmierung C++ Eine Variable lesen/schreiben von mehreren Instanzen


von Pit (Gast)


Lesenswert?

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

von CPP (Gast)


Lesenswert?

Wie wär's mit einem static Klassenmember?

von Mark B. (markbrandis)


Lesenswert?

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.

: Bearbeitet durch User
von Andreas R. (andreasr)


Lesenswert?

> 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.

von Mark B. (markbrandis)


Lesenswert?

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.

von Karl Käfer (Gast)


Lesenswert?

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:
1
#include <iostream>
2
3
class Dings {
4
private:
5
    static int count;
6
public:
7
    Dings() { this->count++; }
8
    ~Dings() { this->count--; }
9
    int counter(void) { return this->count; }
10
};
11
int Dings::count = 0;
12
13
int main(void) {
14
    Dings* a = new Dings();
15
    Dings* b = new Dings();
16
    Dings* c = new Dings();
17
    std::cout << "a.counter(): " << a->counter() << std::endl;
18
    std::cout << "b.counter(): " << b->counter() << std::endl;
19
    std::cout << "c.counter(): " << c->counter() << std::endl;
20
    delete(a);
21
    delete(b);
22
    std::cout << "c.counter(): " << c->counter() << std::endl;
23
}

Achtung: das ist NICHT thread-safe. Dazu müssten die Schreibzugriffe 
auf Dings::count atomar gemacht werden (etwa mit std::mutex).

HTH,
Karl

von Karl Käfer (Gast)


Lesenswert?

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

von Karl M. (Gast)


Lesenswert?

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

von Karl Käfer (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

von Peter II (Gast)


Lesenswert?

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.

von Mark B. (markbrandis)


Lesenswert?

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.

von c-hater (Gast)


Lesenswert?

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.

von Pit (Gast)


Lesenswert?

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?!

von Karl H. (kbuchegg)


Lesenswert?

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.

von Georg (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

: Bearbeitet durch User
von Volle (Gast)


Lesenswert?

erstelle eine Klasse "Seite" die verwaltet wer alles auf ihr zeichnet
und die hat dann z.B.  auch  Methoden  wie
redraw
clear

von Karl Käfer (Gast)


Lesenswert?

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

von Rolf M. (rmagnus)


Lesenswert?

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
Dings d;
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.

von Mark B. (markbrandis)


Lesenswert?

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
void MyClass::setValue(int x)
2
{
3
    this->x = x;
4
}

Wobei man natürlich die zu übergebende Variable auch anders nennen kann 
als gerade x.

von Karl H. (kbuchegg)


Lesenswert?

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
> Dings d;
2
> d.count++;
3
>

Weil
1
private:
2
    static int count;
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.

: Bearbeitet durch User
von Rolf M. (rmagnus)


Lesenswert?

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_iterator result = 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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.