Die Anzahl der Objekte abfragen?
-
Hallo zusammen,
ich sitze seit einiger Zeit und komme einfach nicht weiter....
Ich habe eine Klasse "Fraction", jetzt muss ich eine Memberfunktion erstelle, die mir die Anzahl der Objekten dieser Klasse abfragt und am Ende ausgibt. Das Problem ist dass ich in C++ sehr wenig Ahnung habe und ich weiß grad nicht wie ich da vorgehen soll. Kann mir vielleicht jemand helfen. Danke im Voraus!!!
-
Sehr einfach. Statische Ganzzahl-Variable erstellen, im Konstruktor In- und im Destruktor De-krementieren.
Dazu (d)eine statische Methode, die einfach die Variable zurückgibt.
Yeah.
-
Du koenntest wie folgt vorgehen:
- Einen Counter einfuehren (die Variable muss statisch sein), der die Anzahl der Objekte speichert
- Bei Erzeugen eines Objekts wird der Konstruktor aufgerufen. Dort inkrementierst du den Counter bei jedem Aufruf.
- Beim Zerstoeren eines Objekts wird der Destruktor aufgerufen. Dort dekremtenrierst du den Counter bei jedem Aufruf.
- Schreibe eine Funktion, die den Counter zurueckgibt
-
class foo { private: static unsigned number; public: static void output() { cout << number; } foo() // Konstruktor { ++number; } }; unsigned foo::number = 0;
-
Gugelmoser schrieb:
class foo { private: static unsigned number; public: static void output() { cout << number; } foo() // Konstruktor { ++number; } }; unsigned foo::number = 0;Es koennen auch Objekte zerstoert werden. Das fehlt in deinem Code.
Ausserdem waere es wohl besser gewesen, cobb haette zuerst selber etwas probiert.
-
Erst mal vielen Danke für die schnelle Antwort, ich bin wie folgt vorgegangen.
Ich habe eine statische Variable erstellt, dann im meinem Standard Konstruktor diese Variable inkrementiert genau das gleiche habe ich auch in meinem Copy Konstruktor und überladendem Konstruktor gemacht und in Destruktor habe ich die Variable dekrementiert. Am ende eine funktion erstellt die mir die statische Variable ausgibt.// Header Datei class Fraction private: static int counter; public: //Standard Konstruktor Fraction(); //Überladener Konstruktor Fraction(int z, int n); //Copy Konstruktor Fraction(const Fraction& b); //Destruktor ~Fraction(); static void getNumberofObjects(){cout << counter;}// cpp. Datei Fraction::Fraction(){++counter;} ~Fraction::Fraction(){--counter;} int Fraction::counter = 0; // Dieses Punkt verstehe ich nicht, warum ich die Variable ausserhalb der Klasse initialisieren soll???Und noch eine Frage muss ich in Copy Konstruktor und im überladendem Konstruktor die Variable "counter" inkrementieren???
Ah und noch eins kann mir vielleicht jemand sagen wieso die Funktion getNumberOfObjects statisch sein muss??? Danke!!!
-
cobb schrieb:
Und noch eine Frage muss ich in Copy Konstruktor und im überladendem Konstruktor die Variable "counter" inkrementieren???
Ja. In jedem Konstruktor.
cobb schrieb:
Ah und noch eins kann mir vielleicht jemand sagen wieso die Funktion getNumberOfObjects statisch sein muss??? Danke!!!
Muß sie nicht. Ist aber oft praktischer, daß man Fraction::getNumberofObjects() aufrufen darf, ohne ein konkretes Objekt in Händen zu halten. Dazu das static.
-
cobb schrieb:
Und noch eine Frage muss ich in Copy Konstruktor und im überladendem Konstruktor die Variable "counter" inkrementieren???
Ja, denn in beiden Fällen wird ein neues Objekt erzeugt, der Standardkonstruktor wird dabei gar nicht angefasst.
Ah und noch eins kann mir vielleicht jemand sagen wieso die Funktion getNumberOfObjects statisch sein muss??? Danke!!!
Muss nicht, aber sollte. Die Eigenschaft wie viele Objekte einer Klasse es gibt, ist eine Eigenschaft der Klasse, nicht eines einzelnen Objekts. Das merkst du z.B. daran, dass in der Methode nur auf statische Eigenschaften der Klasse zugegriffen wird.
edit: Zu langsam, mal wieder, leider. Jetzt habe ich neben cooky und seldon auch noch volkard, der immer einen Tick schneller ist.
-
Vielen Dank ihr habt mir sehr geholfen!!!
-
SeppJ schrieb:
edit: Zu langsam, mal wieder, leider. Jetzt habe ich neben cooky und seldon auch noch volkard, der immer einen Tick schneller ist.
// ==UserScript== // @name SeppJ's Posting Helper // @namespace SeppJ // @description Adds "edit: Zu langsam mal wieder." // @include http://www.c-plusplus.net/forum/quote* // ==/UserScript== // Code geklaut von http://userscripts.org/scripts/review/118944 String.prototype.startsWith = function(s) { return this.substr(0, s.length) == s; } var edit = document.getElementsByTagName("textarea")[0]; if(edit.innerHTML.startsWith("[quote=")) { edit.innerHTML += "\n\n\nedit: Zu langsam mal wieder.\n"; edit.focus(); }
-
template <typename> struct tracked { tracked() { ++object_count_; } tracked(tracked const&) { ++object_count_; } tracked(tracked&&) { ++object_count_; } ~tracked() { --object_count_; } static std::size_t object_count() { return object_count_; } private: static std::atomic<std::size_t> object_count_; };struct foobar : tracked<foobar> { ... };Mal so ein Vorschlag. Was haltet ihr davon?
-
314159265358979 schrieb:
Was haltet ihr davon?
Möchtest du gelobt werden? Mal davon abgesehen, dass es keine wahnsinnige Leistung ist:
- Der Move-Konstructor wird eh nicht implizit erstellt -> Zeile 6 ersatzlos löschen.
- Der Konstruktor sollte wohl protected sein, da es zu Problemen führt, wenn die Klasse nicht als CRTP verwendet wird.
- Die Vererbung sollte privat sein.
- Ohne Grund thread-safe ist wohl eine schlechte Idee.
-
davonhalter schrieb:
Möchtest du gelobt werden? Mal davon abgesehen, dass es keine wahnsinnige Leistung ist:
Jo, das stimmt. Aber ein Lob schadet nie, davon gibts eh viel zu wenige :p
davonhalter schrieb:
Der Move-Konstructor wird eh nicht implizit erstellt -> Zeile 6 ersatzlos löschen.
Aber es wäre denkbar, dass in der abgeleiteten Klasse einer geschrieben wird.
davonhalter schrieb:
Der Konstruktor sollte wohl protected sein, da es zu Problemen führt, wenn die Klasse nicht als CRTP verwendet wird.
Okay, da hast du Recht. Der Dtor allerdings auch.
davonhalter schrieb:
Die Vererbung sollte privat sein.
Und wie rufst du dann T::object_count() auf?

davonhalter schrieb:
Ohne Grund thread-safe ist wohl eine schlechte Idee.
Finde ich nicht. Wenn, dann wird sowas doch sowieso nur zu Debuggingzwecken verwendet. Da sollte man einen Fehler durch mehrere Threads von vornherein ausschließen.
-
314159265358979 schrieb:
davonhalter schrieb:
Möchtest du gelobt werden? Mal davon abgesehen, dass es keine wahnsinnige Leistung ist:
Jo, das stimmt. Aber ein Lob schadet nie, davon gibts eh viel zu wenige :p
Ich bin mal nicht so. Gratulation für die Leistung, eine so simple wie geniale Möglichkeit gefunden zu haben, das Tracking in eine Basisklasse auszulagern. Und dabei noch die Nötigkeit von CRTP festgestellt zu haben

314159265358979 schrieb:
davonhalter schrieb:
Der Move-Konstructor wird eh nicht implizit erstellt -> Zeile 6 ersatzlos löschen.
Aber es wäre denkbar, dass in der abgeleiteten Klasse einer geschrieben wird.
Genauer: Der Move-Konstruktor wird u.a. dann nicht erstellt, wenn die Klasse einen Kopierkonstruktor hat. Das heisst, tracked ist nicht und wird nie verschiebbar sein. In den Fällen wird dann immer der Kopierkonstruktor aufgerufen, der in diesem Fall das richtige erledigt.
Was in foobar passiert interessiert nicht.
314159265358979 schrieb:
davonhalter schrieb:
Der Konstruktor sollte wohl protected sein, da es zu Problemen führt, wenn die Klasse nicht als CRTP verwendet wird.
Okay, da hast du Recht. Der Dtor allerdings auch.
Stimmt. Sogar alle Member ausser object_count_.
314159265358979 schrieb:
davonhalter schrieb:
Die Vererbung sollte privat sein.
Und wie rufst du dann T::object_count() auf?

Mit einem
using tracked<foobar>::object_count;Die Gefahr ein tracked<foobar> aus foobar zu erhalten stufe ich schlimmer ein.
314159265358979 schrieb:
davonhalter schrieb:
Ohne Grund thread-safe ist wohl eine schlechte Idee.
Finde ich nicht. Wenn, dann wird sowas doch sowieso nur zu Debuggingzwecken verwendet. Da sollte man einen Fehler durch mehrere Threads von vornherein ausschließen.
Gut, das kann man sehen, wie man will.
-
davonhalter schrieb:
Die Gefahr ein tracked<foobar> aus foobar zu erhalten stufe ich schlimmer ein.
Bleib mal realistisch.
-
So, nach nun einer Stunde Überlegen hab ich so ziemlich alles umgekrempelt. Das Problem mit dem bisherigen Ansatz ist, dass er mit Vererbungshierarchien nicht zurechtkommt. Beispiel: 2 Klassen base und derived, beide ebenfalls von tracked<T> abgeleitet. In dervied wäre object_count nun ambigious.
Der neue Ansatz düfte mit allen denkbaren Hierarchien funktionieren.
template <typename> std::size_t object_count(); template <typename Derived> struct tracked { friend std::size_t object_count<Derived>(); protected: tracked() { ++object_count; } tracked(tracked const&) { ++object_count; } ~tracked() { --object_count; } private: static std::atomic_size_t object_count; }; template <typename Derived> std::atomic_size_t tracked<Derived>::object_count; template <typename T> std::size_t object_count() { static_assert(std::is_base_of<tracked<T>, T>::value, "instances of this type are not tracked"); return tracked<T>::object_count; }object_count ist nun zu einer freien Funktion geworden. Außerdem hat die Klasse tracked keine public Member mehr, was bedeutet, dass man auch einfach private von ihr erben kann und sie somit nicht mehr in ein tracked konvertierbar ist.

Verwendet sich dann so:
struct base : private tracked<base> {}; struct derived : base, private tracked<derived> {}; int main() { derived d; std::cout << object_count<base>() << '\n' << object_count<derived>() << '\n'; }http://ideone.com/ltR7q
Gar nicht mal so einfach, wenn man es ordentlich machen will.