OOP + Globale Variablen



  • Hallo

    Die musst du für die entsprechende Variable schon selber schreiben.

    chrische



  • Achso meinst du das,....
    Ok verständlich, aber das Problem ist dass ich ja eben innerhalb meiner klasse nicht auf die gloabel variable zugreifen kann....
    Da nützt mir doch sogar eine SetFunktion nichts oder ?



  • Hallo

    Das sind ja dann auch keine globalen Variablen mehr. Warum kannst du denn eigentlich nicht auf globale Variablen zugreifen? Was kommt da für eine Fehler?

    chrische



  • [BCC32 Fehler] main.h(57): E2231 Element TForm1::test kann nicht ohne ein Objekt verwendet werden

    class TForm1 : public TForm
    {
    
    public:		// User declarations
    	__fastcall TForm1(TComponent* Owner);
    
    	TForm *ActiveForm;
    	TImage *ActiveImage;
    	AnsiString SavePath;
    	int test;
    
    class Picture{
    	private:
    		void __fastcall aktiv(TObject *Sender)
    		{
    			test=10;
    		}....
    


  • Hallo

    Das ist doch auch keine globale Variable, sondern ein Member von TForm1.

    int test;
    
    class TForm1 : public TForm
    {
    
    public:        // User declarations
        __fastcall TForm1(TComponent* Owner);
    
        TForm *ActiveForm;
        TImage *ActiveImage;
        AnsiString SavePath;
    
    class Picture{
        private:
            void __fastcall aktiv(TObject *Sender)
            {
                test=10;
            }....
    

    Das ist hässlich, aber dürfte funktionieren.

    chrische



  • Stimmt,...
    Doch dann kann ich aus einer anderen Form nicht mehr auf die (jetzt,.. wirklich globale Variable zugreifen!)

    Gibt es keinen Weg von meiner unterklasse picture auf die oberklasse TForm zuzugreifen ?



  • Woher soll die Unterklasse denn wissen, auf welchen Objektes Variablen sie zugreifen soll? Du mußt ihr schon eines übergeben.



  • Hallo

    Du könntest die globale Variable in eine Datei schreiben, die von allen Datein inkludiert wird. Du könntest aber der Klasse picture auch einfach eine Variabel im Konstruktor mitgeben:

    TForm1
    
    -> member int test = 01;
    
    Picture
    
    -> member int _test;
    c'tor: 
    public Picture(int test)
    {
    _test = test;
    }
    

    chrische



  • audacia schrieb:

    Woher soll die Unterklasse denn wissen, auf welchen Objektes Variablen sie zugreifen soll? Du mußt ihr schon eines übergeben.

    Form1->test

    funktioneirt ja leider auch nicht 😞

    Danke für die Vorschläge aber !



  • Hallo

    Übergib' der Klasse doch Picture doch einfach im Konstruktor den Wert den es bekommen soll. Genauso, wie ich es geschrieben habe. Wenn es dabei Probleme gibt, dann helfen wir dir sehr gerne.

    chrische



  • Konstruktor

    Picture(AnsiString dir,TForm *ActiveForm){
    

    und die Funktion

    private:
    
    		void __fastcall aktiv(TObject *Sender)
    		{
    			ActiveForm=Window;
    		}
    

    Würde mir meine Logik nun sagen, der Compiler widerspricht mir leider 😕
    undef. Symbol...



  • Hallo

    Was ist Window und was machst du im Konstruktor mit den Parametern?

    chrische



  • Hier alles...

    class Picture{
    	private:
    
    		void __fastcall aktiv(TObject *Sender)
    		{
    			ActiveForm=Window;
    		}
    
    	public:
    
    		TForm *Window;
    		TImage *Image;
    		TStatusBar *bar;
    		int m_Width;
    		int m_Height;
    
    		__property int Height ={read=m_Height};
    		__property int Width ={read=m_Width};
    		//-------------------------------------------->>>>>>
    
    		Picture(AnsiString dir,TForm *ActiveForm){
    
    		Window = new TForm(Application);
    		Image = new TImage(Window);
    		bar = new TStatusBar(Window);
    
    		Image->Picture->LoadFromFile(dir);
    		Image->AutoSize=true;
    		Image->Width=Image->Picture->Width;
    		Image->Height=Image->Picture->Height;
    		Image->Align=alClient;
    		Image->Parent=Window;
    
    		Window->Caption=ExtractFileName(dir);
    		Window->BorderStyle=bsToolWindow;
    		Window->Width = Image->Picture->Width;
    		Window->Height = Image->Picture->Height;
    		Window->Position=poMainFormCenter;
    
    		Window->OnActivate=aktiv;
    
    		m_Width=Window->Width;
    		m_Height=Window->Height;
    
    		bar->SimpleText=IntToStr(Width)+" x "+IntToStr(Height);
    		bar->SimplePanel=true;
    		bar->Parent=Window;
    
    		Window->Show();
    		}
    
    		//-------------------------------------------->>>>>>
    
    		~Picture(){
        	delete bar;
    		delete Image;
    		delete Window;
    		}
    
    	};
    

    Window ist dass durch die Klasse erzeugte neue Form,..



  • Hallo

    Zuerst solltest du deine Membervariablen private machen, vor allem, wenn du dann noch Properties dafür schreibst. Der zweite Punkt ist der, dass du nun eine Variable an den Konstruktor übergibst, aber gar nichts damit machst. Du solltest dir vielleicht noch einmal die Grundlagen von OOP reinziehen.

    chrische



  • Die Frage ist wohl eher wie ich meinen Übergebene Wert an die Funktion übergebe, da ich bei

    Window->OnActivate=aktiv;
    

    Keine Variablen übergeben darf,...



  • Hallo

    Ich kenne mich mit VCL nicht aus, aber was du machst, ist Quatsch. Du übergibst den Konstruktor einen Parameter und lässt diesen links liegen.

    chrische



  • Global nun richtig:

    TForm *ActiveForm;
    TImage *ActiveImage;

    void __fastcall aktiv(TObject *Sender)
    		{
    			ActiveForm 	= Window;
    			ActiveImage = Image;
    		}
    

    Funktioniert nun 😉
    Lediglich das Zugreifen auf die MEthoden von TForm bzw. TImage der beiden funktioniet nicht 😕

    Der Debugger z.B. liest schön und gut die richtige Caption raus, verändere ich diese und quittiere ich die änderung mit einem
    ActiveForm->Update();
    Kommt eine FEhlermeldung

    Zugrissverletzung bei Adresse 20139079 in Modul vcl100.bpl
    Lesen von Adresse 0000 004C nicht möglich... 😕
    Find ich skuril!



  • 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é


Anmelden zum Antworten