Wie?: Klassenvariable, die für jedes Objekt global ist.
-
Hallo!
Ich habe da ein kleines Programm: Gegeben ist eine Basisklasse Medium.
Von Medium werden zwei Klassen, Video und Buch abgeleitet.
Die Klassen (Video und Buch) werden dann zur Programmlaufzeit instanziert und in einem Array gespeichert.
Nun möchte ich folgendes machen: Die Klassen Video und Buch sollen eine Klassenvariable "Bestand" beinhalten, die, wie der Name ja sagt, den aktuellen Bestand an Videos und Büchern speichert. "Bestand" wird also genau dann inkrementiert, wenn ein Objekt von der jeweiligen Klasse angelegt wird.
Der Punkt ist: Wird die Variable "Bestand" inkrementiert, so soll sie in allen Objekten "Buch" oder "Video" gleichzeitig aktualisiert werden, ohne dass ich explizit jedes Objekt aufrufen und dort die Variable verändern muss.Geht das und wenn ja, wie?
Gruß
-
Ja das geht, schau dir mal das Schlüsselwort static an.
-
Was du suchst, sind
static-Variablen.class Video { public: ... private: static unsigned int AnzahlVideos; }; // Definition in .cpp-Datei unsigned int Video::AnzahlVideos = 0;Die kannst du dann von der Klasse aus wie normale Membervariablen benutzen. In jedem Konstruktor inkrementierst du sie, und im Destruktor dekrementierst du sie. Du musst aber beachten, dass
AnzahlVideosdie gesamte Anzahl existierender Instanzen angibt, also auch eventuelle temporäre Objekte.
-
Danke sehr.

-
Hallo nochmal!
Ich versuche gerade mein Array voller Medienelemente dynamisch zu gestalten, komme aber nicht voran. Weiß einer, wies richtig geht?
void create(Medium* medium){ if(medium==NULL){ medium = new Medium[1]; medium->incBestand(); } else{ Medium *p = new Medium[medium->getBestand()+1]; for(int i=0;i<medium->getBestand();i++) p[i] = medium[i]; delete [] medium; medium = p; medium[medium->getBestand()] = new Medium; medium->incBestand(); } }Error 1 error C2679: binary '=' : no operator found which takes a right-hand operand of type 'Medium *' (or there is no acceptable conversion)
-
eine Frage bitte schrieb:
Hallo nochmal!
Ich versuche gerade mein Array voller Medienelemente dynamisch zu gestalten, komme aber nicht voran. Weiß einer, wies richtig geht?
void create(Medium* medium){ if(medium==NULL){ medium = new Medium[1]; medium->incBestand(); } else{ Medium *p = new Medium[medium->getBestand()+1]; for(int i=0;i<medium->getBestand();i++) p[i] = medium[i]; delete [] medium; medium = p; medium[medium->getBestand()] = new Medium; medium->incBestand(); } }Error 1 error C2679: binary '=' : no operator found which takes a right-hand operand of type 'Medium *' (or there is no acceptable conversion)
ja, du meinst
private: Medium(Medium const&);//zur sicherheit verbieten Medium operator=(Medium const&);//zur sicherheit verbieten public: Medium(){ ++bestand; } ~Medium(){ --bestand; }mehr ist da nicht.
das dynamische array ist dann ne ganz andere sache. und sollte nur zeiger auf medien halten.
vielleicht
vector<Medium*> medien;geht aber auch mit nem eigenen dynamischen array. aber mach das array erstmal als ganz eigenes projekt und verwalte double-werte. steig erst am ende nach Medium* um.
-
Ich habs zwar auch ohne vector hinbekommen, nur das Blöde ist, dass beim Anlegen des Zwischenspeichers new den Konstoruktor der Klasse aufruft. - Ideen?
-
eine Frage bitte schrieb:
Ich habs zwar auch ohne vector hinbekommen, nur das Blöde ist, dass beim Anlegen des Zwischenspeichers new den Konstoruktor der Klasse aufruft. - Ideen?
operator new[sizeof(asd)*length]
und dann mit placement new den ctor aufrufen#btw:
void create(Medium* medium){ if(medium==NULL){ medium = new Medium[1]; /*...*/ } }das funzt? Oo
Ich glaube eher nicht... ^^
der Pointer wird nämlich kopiert -> du veränderst nur die kopie...
richtig wäre eine referenz auf einen zeiger - dann kannst du dem auch (wirkungsvoll) was zuweisen...
btw: new Medium**[1]** ist doch hässlich... vor kurzem war hier scho ma jmd, der ständig ne 1 als dimension gewählt hat - ist das jetzt in, sowas zu machen?new Mediumsieht wohl zu übersichtlich aus?
bb
PS: (offtopic)
wieso kann man noch immer nicht fett courir schreiben? -.- also so: [c]bla[/c]
-
unskilled schrieb:
operator new[sizeof(asd)*length]Du meinst wohl
operator new[] (sizeof(asd) * length);Das gibt allerdings nur einen
void*zurück und muss noch in den Zieltypen gecastet werden. Statt Placement New kann man auch die C++-Funktionenstd::unitialized_copy(),std::unitialized_fill()oderstd::unitialized_fill_n()verwenden.Allerdings kann man die []-Klammern eigentlich auch weglassen (und gleich
operator neweinsetzen), wenn man Allokation und Konstruktion trennt. Bei der Freigabe sollte man vorsichtig sein, da man zuerst für jedes Element den Destruktor aufrufen muss. Ich hatte das selber schon benötigt und eine entsprechende Funktion geschrieben:// Ruft für alle Elemente in der Zeiger-Range [first, last[ den Destruktor auf. template <typename T> void destroy_range(T* first, T* last) { for (; first != last; ++first) { first->~T(); } }Wieso gibt es diese Funktion eigentlich in der Standardbibliothek nicht? Die Gegenstücke bei der Konstruktion sind ja auch vorhanden...
-
Nexus schrieb:
unskilled schrieb:
operator new[sizeof(asd)*length]Du meinst wohl
operator new[] (sizeof(asd) * length);japp - in letzter zeit hab ichs iwie nich so mit dem nachdenken

Nexus schrieb:
Das gibt allerdings nur einen
void*zurück und muss noch in den Zieltypen gecastet werden.Jopp - wo ist das Problem?
Nexus schrieb:
Statt Placement New kann man auch die C++-Funktionen
std::unitialized_copy(),std::unitialized_fill()oderstd::unitialized_fill_n()verwenden.hatte ich ja noch nie gehört - ich seh jz auch nicht wirklich nen vorteil darin - überseh ich was? ^^
Nexus schrieb:
// Ruft für alle Elemente in der Zeiger-Range [first, last[ den Destruktor auf. template <typename T> void destroy_range(T* first, T* last) { for (; first != last; ++first) { first->~T(); } }Wieso gibt es diese Funktion eigentlich in der Standardbibliothek nicht?
Gute Frage - ich habs bis jz aber auch immer selbst geschrieben ^^
bb
-
unskilled schrieb:
Jopp - wo ist das Problem?
Wo sagte ich etwas von Problem? Ich wollte es nur erwähnen, da das vielleicht hilfreich sein könnte.

Nexus schrieb:
hatte ich ja noch nie gehört - ich seh jz auch nicht wirklich nen vorteil darin - überseh ich was? ^^
Keinen Vorteil? Na gut, wenn du dir immer alles selbst schreiben willst.

Nehmen wir an, du hast einen
vector-ähnlichen Container.template <typename T> class dynamic_array { public: // separater Ctor statt Defaultparameter wäre besser, hier aber irrelevant... dynamic_array(size_t num_elements, const T& value = T()); dynamic_array(const dynamic_array& origin); private: size_t m_size; // mal ohne capacity T* m_array; }; // Konstruktor mit Grösse und Default-Element als Parameter template <typename T> dynamic_array<T>::dynamic_array(size_t num_elements, const T& value) : m_size(num_elements) , m_array(static_cast<T*>(operator new(sizeof(T) * m_size))) { std::uninitialized_fill_n(m_array, m_size, value); } // Kopierkonstruktor template <typename T> dynamic_array<T>::dynamic_array(const dynamic_array<T>& origin) : m_size(origin.m_size) , m_array(static_cast<T*>(operator new(sizeof(T) * m_size))) { std::uninitialized_copy(origin.m_array, origin.m_array + m_size, m_array); }Nur so als Beispiel. Man könnte die Funktionalität natürlich noch mehr kapseln, mindestens als freie Funktionen oder sogar als Allokatoren. Aber grundsätzlich sind die
std::uninitialized_...-Funktionen relativ nützlich. Nur reichen sie nicht ganz aus. Ich habe bei mir einen Header, bei dem mehr oder weniger sinnvolle Raw-Memory-Funktionen vorhanden sind (darunter oben genanntesdestroy_range()).
-
Also irgendwas mach ich eindeutig falsch.
class Medium{ protected: ... public: ... void* operator new[] (std::size_t size); };Aufruf:
Medium* create(Medium* medium){ // medium stets != NULL void *p = new Medium[medium->getBestand()+1]; }Und das quitiert mir VS08 mit:
Error 1 error LNK2019: unresolved external symbol "public: static void * __cdecl Medium::operator new[](unsigned int)" (??_UMedium@@SAPAXI@Z) referenced in function "class Medium * __cdecl create(class Medium *)" (?create@@YAPAVMedium@@PAV1@@Z) functions.obj
Error 2 fatal error LNK1120: 1 unresolved externals C:\Dokumente und Einstellungen\IM\Eigene Dateien\Visual Studio 2008\Projects\Medienbib2\Debug\Medienbib2.exe 1
-
Wenn du den
operator new[]deklarierst, musst du auch dafür sorgen, eine eigene Implementierung (Funktionsdefinition) zur Verfügung zu stellen. Meistens besteht aber kein Grund, die Speicheranforderungs-Operatoren zu überladen. Also versuch mal, die Deklaration wegzulassen.
-
Ups.
void* operator new[](std::size_t size){ return (void*) (size*sizeof(Medium)); }Was er mir nun liefer ist eine excess violation.
Bzw., eigentlich ist es wirklich unnötig und die Aufgabenstellung schreit ja gerade zu nach einer verketteten Liste aber ich hätts tortzdem gern hinbekommen.
-
eine Frage bitte schrieb:
excess violation.
Hehe...

void* operator new[](std::size_t size){ return (void*) (size*sizeof(Medium)); }Weisst du, was du hier machst? Du multiplizierst
sizemitsizeof(Medium). Weil du einen überaus gefährlichen und bösen C-Cast anwendest, merkst du nicht, was du castest. Nämlich einen Integer zu einem Zeiger. Deinoperator new[]tut also so, als wäre das Ergebnis der Multiplikation eine Adresse. Und als wäre an dieser Adresse ein schöner, neu angelegter Speicherbereich für dich.Ich denke, der Rest ist klar.

-
Nexus schrieb:
Weil du einen überaus gefährlichen und bösen C-Cast anwendest, merkst du nicht, was du castest. Nämlich einen Integer zu einem Zeiger.

-
Na wenn ich schon dabei bin, C-Funktionen zu benutzen, kann ich den Speicher wohl auch gleich mit malloc allokieren...
Oder bietet mir C++ bessere Alternativen?
-
eine Frage bitte schrieb:
Na wenn ich schon dabei bin, C-Funktionen zu benutzen, kann ich den Speicher wohl auch gleich mit malloc allokieren...
Oder bietet mir C++ bessere Alternativen?ja.
stattBla* p=malloc(15*sizeof(Bla));sollte man
Bla* p=new Bla[15];schreiben.
die version mit new ruft zusätzlich den konstruktor von Bla für jedes array-element auf. also nix wenn es simple typen sind, und dann ist new auch genausoschnell. aber wenn der konstruktor von Bla code ausführen muß, macht new[] das austomatisch.
deswegen sollte man in c++ grundsätzlich new benutzen, damit man nicht nachdenken muß, ob der typ gerade einer war, der keinen konstruktor hat oder einer, der soch mal einen hat.zum anlegen rohen speichers gibt es operator new(size_t) versus malloc(size_t), die genau gleich sind. naja, fast. operator new ist gerne mal auf kleine objekte optimiert.
-
eine Frage bitte schrieb:
Na wenn ich schon dabei bin, C-Funktionen zu benutzen, kann ich den Speicher wohl auch gleich mit malloc allokieren...
Oder bietet mir C++ bessere Alternativen?Wieso willst du unbedingt
operator new[]selber implementieren? Du kannst doch den vorgefertigten nutzen. Es ist unwahrscheinlich, dass du für den Alltag etwas anderes brauchst. Also entferne endlich dessen Deklaration in deiner Klasse.Und ja, C++ bietet bessere Möglichkeiten. Sieh dir bei Gelegenheit mal STL-Container an.
-
Ja, aber den Aufruf des Konstruktors wollte ich doch unbedingt vermeiden, weil ich vorhatte, mein Array von Medien-Objekten dynamisch zu verwalten. Und dazu musste ich dann neuen Speicher anlegen und es wäre wirklich nicht so toll, wenn dabei stets der Konstruktor aufpoppt.
-
Nun ja, ist auch egal. Ich komme im Moment damit, new zu überladen, sowieso auf keinen grünen Zweig mehr.
Mal was anderes:
class Medium{ private: static int bestand; public: void incBestand(); int getBestand(); }; class Book : public Medium{ private: static int bestand; public: }; class Video : public Medium{ private: static int bestand; public: };Wie kommt es, dass void incBestand() und int getBestand() in den Klassen Book und Video immerzu auf die static-Variable "bestand" aus der Klasse Medium zugreiffen, obwohl die Variable private ist, damit nicht vererbt und sowieso redefiniert wird? Und vor allem: Warum geht es überhaupt? Dachte, auf statische Klassenvariablen könne man nur mit statischen Methoden zugreiffen.
Definiere ich die Methoden in jeder Klasse jeweils als static, funktioniert alles, wie es soll.