OOP + Globale Variablen



  • Wie chrische5 schon sagte, wenn du einen passenden Parameter im Konstruktor hats, verwende ihn auch. da du hier einen Pointer ändern willst musst du ihn natürlich als Referenz übergeben.

    Picture(AnsiString dir,TForm*& activeForm, TImage*& activeImage)
    {
    // Deine Initialisierung
      activeForm = Window;
      activeImage = Image;
    


  • Es funktioniert nun ja...
    Eine "active"-Klasse von meiner klasse initlisieren und das global,..
    funktioniert prächtig,..

    In der Form1 (main.cpp) kann ich nun per

    ActivePic->Window->Caption="Test";
    

    Jederzeit auf das zuletzt aktive Element zugreifen,...
    Soweitsogut,..

    Wenn ich nun in der Form2 das selbe machen möchte 1:1,..
    Bekomm ich den fehler, OBWOHL die Adresse der beiden Elemente gleich ist ?



  • christianz schrieb:

    ...

    Du solltest dir wirklich erst einmal die Grundlagen der Objektorientierten Programmierung aneignen. Zudem sind globale Variablen mit ganz wenigen Ausnahmen (und selbst die kann man meistens Vermeiden) weder gute Programmierung noch ohne Probleme...

    Punkt 1: Klasse vs. Objekt
    Eine Klasse ist eine abstrakte Beschreibung, Objekte sind konkrete Instanzen von den Klassen. Jede Instanz (= Objekt) belegt einen eigenen Speicherbereich.

    Punkt 2: Datenkapselung & Wartbarkeit
    Ein Objekt sollte möglichst Eigenständig für sich arbeiten. Es ist nicht verboten es aus mehreren Teilen (Objekten) aufzubauen, aber diese sollten Teil des Ganzen sein. Alles was ein Objekt von Außen benötigt sollte über seine Schnittstelle übergeben werden. Alles was Teil des Objektes ist, sollte ebenso nur über wohldefinierte Schnittstellen bereitgestellt werden, und das auch nur wenn es sinnvoll ist (private Member, ggf. Setter/Getter...).

    Wenn du dir einen DVD-Spieler anschaust, wirst du auch nicht ohne Gewalt an seinen "Innereien" rumspielen können, und er besitzt nach außen hin eine saubere Schnittstelle über die du mit ihm interagierst. Wenn du eine DVD anschauen willst, machst du dies über die Schnittstelle.

    Vereinfacht gesprochen:

    dvdspieler.Open();
      dvdspieler.SetDVD(const DVD& dvd);
      dvdspieler.Play();
    

    Der DVD spieler hält dabei die DVD (= Membervariable, wird im SetDVD gesetzt)...

    Die Fernbedienung greift nun auch nicht global auf den dvdspieler zu. Wenn die Fernbedienung erstellt wird (Konstruktor) wird sie auf den DVD-Spieler eingestellt (z.B. Parameter des Konstruktors).

    So dies als kurze Einführung. Grundsätzlich solltest du dir merken:
    Definiere immer so lokal wie möglich, aber so global wie nötig.

    Ist dein Aktives Bild nun Applikationsglobal, oder ist es z.B. Teil des Fensters...

    cu André



  • Kurze Frage noch,...

    Habe es nach euren Ratschlägen umstrukturiert,

    Bin momentan soweit dass ich ein Objekt (!) "ActivePic" übergebe und dies anschließend per this zuweise,..
    Somit ist ActivePic immer das zuletzt erzeugt Bild,..
    Funktioniert auch,..
    nun habe ich intern auch ein "ActivePic" dem möchte ich die gleiche Adresse wie dem public ActivePic zuweisen,..

    private:
    Picture* ActivePic;
    Picture(AnsiString dir,Picture* &Active){
    		Active = this;
    		ActivePic = Active;
    

    Nur die Zuweisung funktioniert nicht da ich ja die Adresse zuweisen will,..

    ein

    *ActivePic = Active;
    

    Funktioniert aber auch nicht ?



  • Hallo

    Versuch' dir doch mal anzugewöhnen, dass "geht nicht" nichts aussagt. Sollen wir jetzt raten, wo das Problem ist? Zeig also immer noch die Fehlermeldung oder beschreibe das vermeintliche Fehlverhalten.

    chrische



  • Sorry 😉
    Haste Recht,..

    Das Problem ist dass ich nicht weis wie ich die Adresse(!) zuweisen kann,... ?
    Mittels pointer ok,..
    Nur

    &ActivePic = Active;

    Ergibt
    [BCC32 Fehler] main.h(184): E2277 L-Wert erwartet



  • einfach

    ActivePic = Active;
    

    Belies dich mal über Referenzen.
    http://tutorial.schornboeck.net/referenzen.htm



  • So jetzt bin ichs nochmal,..
    Irgendwie hab ich einen Knoten...

    Also,
    Vorgehensweise:

    1. Ich habe im TForm1 ein Objekt initalisiert,
    public:		// User declarations
    	__fastcall TForm1(TComponent* Owner);
    	Picture *ActivePic;
    
    1. Ich übergebe beim erzeugen eines neuen Objekt dieses
    Picture *pic = new Picture(OpenDialog1->FileName,ActivePic);
    
    1. In meinem Objekt sage ich:
    Picture(AnsiString dir,Picture* &pic){
    ActivePic = pic;
    //und
    Window->OnActivate=aktiv;//Beim anklicken meiner erzeugten Form
    
    1. Beim anklicken wird:
    void __fastcall aktiv(TObject *Sender)
    		{
    			ActivePic = this;
    		}
    

    Das heist bei einem anklicken wird ActivePic auf das momentane objekt gerichtet,..
    Mein Fehler momentan ist dass ich nun über ActivePic->Window bzw. ActivePic->Image
    auf die Eigenschaften und Methoden zugreife um das Bild bzw. das Fenster zu manipulieren.
    z.b. zum invertieren

    void Invert(){
    		Graphics::TBitmap *bmp = ActivePic->Image->Picture->Bitmap;
    
            for(int y=0;y<bmp->Height;y++)
    		{
    			RGB *zeile = (RGB*) bmp->ScanLine[y]; //Width*3
    			for(int x=0; x < bmp->Width; x++)
    			{
    				zeile[x].R=~(zeile[x].R);
    				zeile[x].B=~(zeile[x].B);
    				zeile[x].G=~(zeile[x].G);
    			}
    		}
    		ActivePic->Image->Picture->Bitmap=bmp;
    		}
    

    Beim debuggen erzeugt es mir die Form und das Image und läd auch ein Bild rein, möchte ich nun Invertieren wird ein exception ausgelöst da
    ActivePic nur "???" enthält,...



  • Hallo

    Der Fehler wird schon durch diesen Bezeichnungsfehler hier deutlich

    1. Ich habe im TForm1 ein Objekt initalisiert,
    C/C++ Code:
    public:        // User declarations
        __fastcall TForm1(TComponent* Owner);
        Picture *ActivePic;
    

    Denn hier wird nicht ein Objekt initialisiert, sondern ein Pointer deklariert!
    Es wird (laut dem Coedeauszug) nirgends eine echte Instanz der Klasse angelegt, der Pointer ActivePic bleibt uninitialisiert.
    Das erklärt dann auch die Exception, denn du greifst dann über ActivePic auf ungültigen Speicher zu.

    Grundlagen in C++ und Speicherverwaltung wären hier sehr hilfreich.

    bis bald
    akari



  • Sorry hab ich vergessen zu posten:

    void __fastcall TForm1::FormCreate(TObject *Sender)
    {
    ActivePic = new Picture(ActivePic);
    }
    

    bzw.

    Picture(Picture* &Active){
    			ActivePic = Active;
    			Window = new TForm(Application);
    			Image = new TImage(Window);
    			bar = new TStatusBar(Window);
    		}
    

    Also ist schon wie geschrieben initalisiert !



  • Was soll denn das hier sein?

    ActivePic = new Picture(ActivePic);
    

    eher so

    ActivePic = new Picture(this);
    


  • Habe es nun umgewandelt,
    der Grundkonstruktor erzeugt mir meine Grundobjekte,...

    public:
    		Picture *ActivePic;
    
    		Picture(TComponent* AOwner,Picture *pic)
    		{
    		Window = new TForm(Application);
    		 Image = new TImage(Window);
    		   bar = new TStatusBar(Window);
    
    		ActivePic = pic;
    		pic=this;
            v=0;
    		}
    
    ActivePic = new Picture(this,NULL);
    	Picture *pic = new Picture(this,ActivePic);
    	pic->ActivePic=ActivePic;
        pic->LoadPicture(OpenDialog1->FileName);
    
    	ActivePic->Window->Close();
    

    Demzufolge müsste durch den den "Close()" das gerade geöffnete Window geschlossen werden,.. leider stimmen die Adressen nicht überein ?
    Ich weis mittlerweile wirklich nicht mehr weiter !?



  • Hier die endgültige Version die nun E N D L I C H
    funktioniert!

    Folgendes war zu tun:
    TForm1

    Picture *Active;
    

    deklariert !

    Beim erstellen eines Objekts:

    Picture *pic = new Picture();
    pic->LoadFromFile(OpenDialog1->FileName);
    pic->SetActivePic(&Active);
    

    Konstruktor bzw. SetActivePic

    Picture *ActivePic;
    Picture **pAdresse;
    
    Picture(){
    			Window = new TForm(Application);
    			Image = new TImage(Window);
    			Window->OnActivate=SetActive;
    		}
    
    		void SetActivePic(Picture* *pActive){
    			pAdresse=pActive;
    			SetActive(NULL);
    		}
    

    und bei jedem Mausklick auf das Window

    void __fastcall SetActive(TObject *Sender){
    			if(pAdresse != NULL)
    				*pAdresse=this;
    		}
    

    Somit enthält das Picture *Active immer das momentan aktive Objekt 😉


Anmelden zum Antworten