Klassen: Zähler für Objekete
-
Bitte achte beim nächsten Posting darauf, dass du deinen Quelltext vernünftig einrückst. So, wie er jetzt formatiert ist, ist er kaum zu lesen.
Vermutlich hat der Aufgabensteller an sowas hier gedacht:
class SomeClass { static unsigned int Counter; public: SomeClass() { ++Counter; } ~SomeClass() { --Counter; } } unsigned int SomeClass::Counter = 0;Über den Sinn und Unsinn kann man sich streiten. Der "Trick" an der Lösung ist, dass der Zähler
Counterein statisches Klassenelement ist, d.h. es gibt ihn genau ein einziges Mal und alle Objekte der Klassen teilen ihn sich.
Den read-only Zugriff darauf zu implementieren sollte kein Problem sein, das solltest du hinkriegen. Ebenso das korrekte Verhalten des Kopierkonstruktors.Edit:
Initialisierung korrigiert.
-
class foo { private: // static variable belongs to the class, not to a specific instance static int counter_; public: // on object creation increase the counter foo(void) { ++counter_; } // on object deletion decrease the counter ~foo(void) { --counter_; } // with this method you can query the counter... // call it this way: // foo::get_counter() static int get_counter(void) { return counter_; } }; // definition and initialization of the counter int foo::counter_ = 0;EDIT: unsigned int als Typ geht natürlich auch^^
@DocShoe: Deine Initialiserung direkt in der Klasse funktioniert IMHO nur bei statischen Konstanten.
Variablen müssen extra initialisiert werden.MSVC würde dir hier z.B. folgenden Fehler bringen:
Compiler Error C2864
'variable' : only static const integral data members can be initialized within a class
-
/////////////////////////////////////////////////////////////////////////////// #include <cstddef> #include <iostream> template <typename T> class object_counter { public: static void print_statistics() { std::cout << "**********************************************************" << std::endl; std::cout << "total " << total_ << " objects of type " << typeid(T).name() << " instantiated" << std::endl; std::cout << "current " << current_ << " objects of type " << typeid(T).name() << " instantiated" << std::endl; std::cout << "**********************************************************" << std::endl; } protected: object_counter() { increment(); } object_counter(const object_counter&) { increment(); } ~object_counter() { decrement(); } private: static void increment() { ++total_; ++current_; } static void decrement() { --current_; } static std::size_t total_; static std::size_t current_; }; template <typename T> std::size_t object_counter<T>::total_ = 0; template <typename T> std::size_t object_counter<T>::current_ = 0; /////////////////////////////////////////////////////////////////////////////// struct A : object_counter<A> { }; struct B : object_counter<B> { }; int main() { A::print_statistics(); B::print_statistics(); { for (std::size_t i = 0; i < 3; ++i) { A a; } A::print_statistics(); B::print_statistics(); { A a; A aa = a; A aaa; aaa = a; aaa; } A::print_statistics(); B::print_statistics(); B b[16]; A::print_statistics(); B::print_statistics(); } A::print_statistics(); B::print_statistics(); } ///////////////////////////////////////////////////////////////////////////////EDIT
Copy- Constructor hinzugefügt
-
@DocShoe: ISO C++ forbids in-class initialization of non-const static member ‘Counter’
@DrakoXP: Auch noch nicht ganz:
int main() { foo a; foo b = a; cout << foo::get_counter() << '\n'; // 1 }edit: @theta: Gleiches Problem wie DrakoXP
Ist wohl doch nicht so ganz einfach
.
-
Verbesserte Version:
class foo { private: // static variable belongs to the class, not to a specific instance static int counter_; public: // on object creation increase the counter foo(void) { ++counter_; } // on object deletion decrease the counter ~foo(void) { --counter_; } // copy constructor foo(foo const & source) { ++counter_; } // with this method you can query the counter... // call it this way: // foo::get_counter() static int get_counter(void) { return counter_; } }; // definition and initialization of the counter int foo::counter_ = 0;
-
Ich habs jetzt so:
#include<iostream> using namespace std; class ABC { public: ABC(); void print(); int getx(); void setx(int); static unsigned int getcounter(); ~ABC(); private: int x; static unsigned int counter; }; ABC::ABC() { x = 255; ++counter; } void ABC::print() {cout << "x = " << x << endl;} int ABC::getx() {return x;} void ABC::setx(int a) {x = a;} static unsigned int ABC::getcounter() {return counter;} ABC::~ABC() {--counter;} unsigned int ABC::counter = 0; int main() { ABC Objekt1; Objekt1.getcounter(); system("Pause"); return 0; }Der Compiler sagt aber, dass ich static nicht für Memberfunktionen verwenden darf, die ausserhalb der Klasse definiert sind.
-
class counted { static int counter; public: counted() { ++counter; } ~counted() { --counter; } counted(const counted&) { ++counter; } static int count() { return counter; } }; int counted::counter = 0;
-
chris911 schrieb:
Der Compiler sagt aber, dass ich static nicht für Memberfunktionen verwenden darf, die ausserhalb der Klasse definiert sind.
Bei der Definition der Funktion außerhalb der Klasse hat das Schlüsselwort static dann auch nichts mehr verloren.
Wer will, kapselt die Zählerfunktionalität in einer Basisklasse:template <typename> class Counted { protected: Counted() { ++counter; } Counted(const Counted&) { ++counter; } ~Counted() { --counter; } public: static unsigned getcounter() { return counter; } private: static unsigned counter; }; template <typename T> unsigned Counted<T>::counter = 0; class ABC : public Counted<ABC> { ...
-
chris911 schrieb:
Der Compiler sagt aber, dass ich static nicht für Memberfunktionen verwenden darf, die ausserhalb der Klasse definiert sind.
in Zeile 34 das static weglassen
-
camper schrieb:
Wer will, kapselt die Zählerfunktionalität in einer Basisklasse:
Wollte ich auch gerade vorschlagen

-
Kapselung vom Zähler in eine Basisklasse will ich eigentlich nicht.
Habs jetzt so:
#include<iostream> using namespace std; class ABC { public: static int counter; ABC(){++counter;} ~ABC(){--counter;} ABC(const ABC&){++counter;} static int count(){return counter;} }; int ABC::counter = 0; int main() { ABC Objekt1; // 1 Objekt wird angelegt cout << Objekt1.counter << endl; // Ausgabe = 1 Objekt1.~ABC(); // 1. Objekt wird wieder gelöscht ABC Objekt2; // 1 Objekt wird angelegt cout << Objekt2.counter << endl; // Ausgabe = 1 system("Pause"); return 0; }Ich musste aber counter in public reinstecken, weil ich sonst keinen Zugriff hätte ausserhalb der Klasse (in Zeile 18), wo ich ihn 0 setzte.
-
Den Destruktor manuell aufrufen ist bei Stackobjekten ganz ganz böse. Und warum nimmst du nicht meine count() Methode, wenn du sie weiterverwendest?
(Übrigens bin ich davon überzeugt, dass es eine Möglichkeit gibt, die Variable private zu lassen. Ich weiß nur nicht wie.)
-
Wenn ich count nehme wird mir nur die Adresse angezeigt.
Wie kann ich die Objektanzahl anders heruntersetzen, bzw. was bingt mir dann das Heruntersetzen im Destruktor?
-
chris911 schrieb:
Wie kann ich die Objektanzahl anders heruntersetzen, bzw. was bingt mir dann das Heruntersetzen im Destruktor?
Wenn du den Destruktor manuell aufrufst, nur um den Zähler herunterzusetzen, stimmt die gesamte Zählung nicht mehr (zumal das Objekt am Ende der Funktion nochmal zerstört wird). Normalerweise verläßt man sich darauf, daß das Objekt sich am Ende des Scope selbst zerstört:
int main() { { // eigener Scope ABC Objekt1; cout<<ABC::count()<<endl; } // Ende des Scope - Objekt1 wird zerstört cout<<ABC::count()<<endl; }
-
chris911 schrieb:
Wie kann ich die Objektanzahl anders heruntersetzen,
Guck dir mal Gültigkeitsbereiche an:
int main() { { ABC Objekt1; // 1 Objekt wird angelegt cout << ABC::counter << endl; // Ausgabe = 1 } // 1. Objekt wird wieder gelöscht ABC Objekt2; // 1 Objekt wird angelegt cout << ABC::counter << endl; // Ausgabe = 1 system("Pause"); return 0; }Wenn ich count nehme wird mir nur die Adresse angezeigt.
Du hast die Klammern beim Funktionsaufruf vergessen.
-
Ich hab jetzt zum Testen mal 100 Objekte mit einem array angelgt.
Jetzt würde ich gerne ein Objekt davon löschen. Kann ich das nicht mit delete machen?So hab ichs mir gedacht:
#include<iostream> using namespace std; class ABC { public: static int counter; ABC(){++counter;} ~ABC(){cout << "Objekt zerstört!" << endl; --counter;} ABC(const ABC&){++counter;} static int count(){return counter;} }; int ABC::counter = 0; int main() { ABC meineObjekte[100]; // Anlegen von 100 Objekten delete meineObjekte[3]; // Löschen eines Objektes ABC Objekt1; // Objekt 101 cout << Objekt1.count() << endl; // Ausgabe = 1 system("Pause"); return 0; }Compiler-Fehler: 'ABC' kann nicht in void konvertiert werden.
-
Nein, mit delete löscht man Heap-Speicher...
Am besten holst du dir mal ein gutes C++-Buch und arbeitest es durch.
-
edit: @theta: Gleiches Problem wie DrakoXP
Welches Problem?
EDIT
Ah, i see...EDIT2
Code im orginal Post korrigiert.