Wie?: Klassenvariable, die für jedes Objekt global ist.



  • 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 size mit sizeof(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. Dein operator 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.
    statt

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



  • eine Frage bitte schrieb:

    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ß

    Bestand ist keine Eigenschaft der Bücher oder Videos, sondern des Dings (Laden/Bücherei) in dem sie sind. Vergiss das mit dem new überladen, mach dir eine Klasse die die Medien hält und beim hinzufügen oder entfernen den Bestand aktualisiert.



  • Ach, und wenn du dir sicher bist, dass es immer nur genau eine Bücherei gibt, dann kannst du die als Google: Singleton machen.



  • eine Frage bitte schrieb:

    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?

    private Member werden vererbt, die erbende Klasse hat nur keinen direkten Zugriff darauf, aber vererbte Funktionen dürfen trotzdem normal darauf zugreifen, wäre das nicht so würden ja einzellne Funktionen uU nichtmehr funktionieren. Deine 2 Funktionen greifen auf die Variable zu die zu ihrer Klasse gehört, da sie zu Medium gehören greifen sie auch auf die Variable aus Medium zu.

    Ich weiß hier leider nicht genau ob man die static wirklich überall einzelln haben muß oder ob eine statische Bestand Variable in Medium nicht reichen würde, weil ich nicht weiß ob sie danach 3x oder trotdzem nur 1x existieren würde.

    eine Frage bitte schrieb:

    Und vor allem: Warum geht es überhaupt? Dachte, auf statische Klassenvariablen könne man nur mit statischen Methoden zugreiffen.

    Du denkst da leider falsch. Nicht statische Funktionen dürfen auf statische Member und Funktionen zugreifen, nur umgedreht geht es nicht.

    eine Frage bitte schrieb:

    Definiere ich die Methoden in jeder Klasse jeweils als static, funktioniert alles, wie es soll.

    Siehe erster Quote.



  • eine Frage bitte schrieb:

    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.

    Den Aufruf des Konstruktors vermeidest du indem du einfach operator new[] selber aufrufst. Schnellerklärung zum Thema: C++ unterscheidet zwischen der Funktion operator new[] und dem Operator new . Das, was wir normalerweise im Quellcode schreiben, ist der Operator new . Der Compiler macht daraus einen Aufruf des operator new[] , gefolgt von entsprechend vielen Konstruktoraufrufen für die ganzen Elemente des Arrays. Ähnliches gilt für den Operator delete : Hier wird erst der Destruktor aufgerufen, danach dann operator delete , der nurnoch den Speicher freigibt.
    Dein Versuch, operator new[] zu überladen wäre also wirkungslos, die konstruktoren würden immernoch aufgerufen wenn du den Aufruf nicht änderst.

    Unskilled hatte eigentlich schon den richtigen Hinweis geliefert:

    X* blankerSpeicher = operator new[](n*sizeof(X)); //Speicher für n Xe
    for (int i = 0; i < n; ++i)
      new (blankerSpeicher + i) X(); //placement new
    
    //freigeben:
    //delete[] blankerSpeicher;   //ruft alle Destruktoren auf und dann operator delete[]
    
    for (int i = n-1; i >= 0; --i)
      blankerSpeicher[i].~X();  //manueller Dtoraufruf
    operator delete[] (blankerSpeicher);
    

    Der Fehler bei deinem überladenen operator new war übrigens, dass du ihn nicht static deklariert hast. Wenn man sichs genau überlegt kann er garnicht anders als static sein, schließlich gibts kein Objekt, das ihn aufruft um Speicher für ein anderes Objekt zu beschaffen.


Anmelden zum Antworten