Instanz greift auf Instanz zu -> Zugriffsverletzung [gelöst]



  • Hallo Gemeinschaft,

    ist es nicht ein herrliches Wetterchen um Programmierprobleme zu haben!?!

    Hier das Problem:

    In meinem Programm gibt es zwei unterschiedliche Formulare, die erst zur Laufzeit instanziiert werden. Nun gibt es den Fall, dass ich das 1. Formular instanziiere (Instanz A) und aus diesem heraus gegebenenfalls das 2. Formular instanziiere (Instanz B), um eine Benutzereingabe einzuholen. Beide Instanzen werden jeweils mit ShowModal() angezeigt.
    Nach einer Eingabe durch den Benutzer, soll nun Instanz B schreibend auf eine public-Variable (AnsiString) der Instanz A zugreifen. Leider erhalte ich dadurch zur Laufzeit eine Zugriffsverletzung!

    TForm1 *pInstanzA= new TForm1(0);
    

    Ich habe doch mit obigem Code einen Zeiger pInstanzA, mit dem ich auf die Instanz zugreifen kann...
    Nun wär ich der Meinung, dass ich hiermit auf die public-Variable von Instanz A zugreifen kann, um einen Edit-Text von Instanz B aus hineinzuschreiben:

    pInstanzA->PublicVariable= Edit1->Text;
    

    Das mag aber der Compiler nicht - er sagt er kennt pInstanzA nicht!

    Wenn ich es nun direkt versuche:

    Form1->PublicVariable= Edit1->Text;
    

    bekomme ich in dieser Zeile, wie gesagt, eine Zugriffsverletzung.

    Wie kann ich die puplic-Variable der Instanz A von Instanz B aus verändern?

    Edit: Nachbesserungen 🙂



  • Hallo,

    Beide Instanzen müssen gültig sein und InstanzA sollte InstanzB kennen. Aus deinem geposteten Code ist der Ablauf aber nicht ersichtlich. Zeig mal etwas mehr.



  • @ Braunstein: Hier mal die relevanten Codeteile, wie sie nacheinander aufgerufen werden:

    Instanziieren von Form1 & Anzeigen von Instanz A:

    void __fastcall TFormMain::Menu1Click(TObject *Sender)
    {
    	TForm1 *pInstanzA= new TForm1(0);     // instanziieren
    	pInstanzA->ShowModal();               // anzeigen
    	delete pInstanzA;                     // Instanz löschen
    	// ...
    }
    

    Instanz A - Instanziieren von Form2 & Anzeigen von Instanz B:

    #include "2.h"    // Header von Form2
    
    // ...
    
    void __fastcall TForm1::BtnInstBClick(TObject *Sender)
    {
    	// ...
    	if(...)
    	{
    		TForm2 *pInstanzB= new TForm2(0);
    		pInstanzB->Caption= " Geben Sie Dies und Das ein:";
    		pInstanzB->BtnTest->Caption= "Test";
    		pInstanzB->ShowModal();
    		delete pInstanzB;
    	}
            // ...
    }
    

    Instanz B - Schreiben in public-Variable von Instanz A:

    #include "1.h"     // Header Form1
    
    void __fastcall TForm2::BtnWriteVarClick(TObject *Sender)
    {
       // ...
       if(...)
       {
          // ...
          // Idee 1:
          Form1->PublicVariable= Edit1->Text;       // Compiler kennt Form1 nicht!!!
          // Idee 2:
          pInstanzA->PublicVariable= Edit1->Text;   // Zugriffsverletzung zur Laufzeit!!!
       }
       this->Close();
    }
    

    Ich hoffe das ist es, was du wissen wolltest.



  • Deine InsatnzA gibt es nur in TFormMain::Menu1Click
    Übergib diesen Pointer doch in ctor für Form2



  • Würde es nicht ausreichen beim Instanziieren des 2. Formulars als Owner this (also Instanz A) anzugeben? Kann ich dann nicht aus Instanz B auf eine public-Variable von Owner (Instanz A) zugreifen? Meinst du das @witte?



  • Das würde theoretisch schon gehen. Du müsstest dann aber den Konstruktor von TForm2 ändern, da der Owner ja eigentlich für das Löschen der from zuständig ist. Ich weiß jetzt aber nicht genau was für Abhängigkeite da noch drinstecken.
    Ich würde aber den Owner für sowas nicht zweckentfremden. Du kannst doch z.Bsp. im Konstruktor von TForm2 einen Zeiger auf TForm1 neben dem Owner mit übergeben und dort einer Membervariablen übergeben. Das erscheint mir etwas sauberer. Du hast da lediglich das Problem, dass du innerhalb von TForm2 nicht weißt, ob der Zeiger immer gültig ist.



  • Alternativ könntest Du dem dynmaischen Form einen aussagekräftigen Namen geben und über TApplication::Components iterieren um das gewünschte Form zu finden.



  • Braunstein schrieb:

    [...] Du kannst doch z.Bsp. im Konstruktor von TForm2 einen Zeiger auf TForm1 neben dem Owner mit übergeben und dort einer Membervariablen übergeben. [...]

    Ja, das habe ich schon versucht - das ist sicherlich auch das, was witte meint. Allerdings bekomme ich das nicht so recht hin...

    Für Form2 müsste das so aussehen:

    // .h:
    class TForm2 : public TForm
    {
    __published:
       // ...
    private:
    	TForm* pForm1;
    public:
    	__fastcall TForm2(TComponent* Owner, TForm* InstanzA);
    };
    
    // .cpp - Konstruktor:
    __fastcall TForm2::TForm2(TComponent* Owner, TForm* InstanzA)
    	: TForm(Owner)
    {
       pForm1= &InstanzA;
       //...
    }
    

    richtig?

    Dann müsste ich in der InstanzB-Funktion mit

    *pForm1->PublicVariable= Edit1->Text;
    

    die Variable von Instanz A ändern können, richtig?

    Nur, wie übergebe ich beim Instanziieren den Zeiger an den Konstruktor?



  • Na, indem Du einen weiteren Konstruktor anlegst:

    public:		// Anwender-Deklarationen
    	__fastcall TForm1(TComponent* Owner);
    	__fastcall TForm1(TComponent* Owner, TForm1* pCallingForm1);
    

    Den übergebenen Zeiger musst Du dann in einer Membervariablen speichern um ihn in anderen Methoden nutzen zu können. Im Standardkonstruktor solltest Du diese Membervariabel auf NULL setzen.



  • @Joe_M: Ok, ich muss also den Konstruktor überladen, das ist soweit klar. Allerdings verwirrt mich jetzt, dass du den Konstruktor von Form1 überladen hast. Ist das Absicht oder meintest du Konstruktor von Form2?

    Meine grosse Frage ist jetzt, wie ich den Zeiger richtig übergebe - sprich:

    void __fastcall TForm1::BtnInstBClick(TObject *Sender)
    {
        // ...
        if(...)
        {
            TForm2 *pInstanzB= new TForm2(0);                     // <==== !!!!
            // wird zu:
            TForm2 *pInstanzB= new TForm2(0, &pInstanzA);         // ????
            pInstanzB->Caption= " Geben Sie Dies und Das ein:";
            pInstanzB->BtnTest->Caption= "Test";
            pInstanzB->ShowModal();
            delete pInstanzB;
        }
        // ...
    }
    

    So?



  • Weiß nicht, hab den Überblick verloren. 😉 In welchem Form möchtest Du welche dynamische Forminstanz verwenden?



  • Prinzipiell richtig. Du solltest nur den Adressoperator weglassen. pInstanzA ist doch schon ein Zeiger.

    TForm2 *pInstanzB= new TForm2(0, pInstanzA);
    

    Damit das Löschen der Zeiger kein Problem mehr ist solltest du irgendwann mal was über Smartpointer lesen. Dann geht auch sowas.

    void __fastcall TForm1::BtnInstBClick(TObject *Sender)
    {
        // ...
        if(...)
        {
            std::auto_ptr<TForm2> pInstanzB(new TForm2(0, pInstanzA));
            pInstanzB->Caption= " Geben Sie Dies und Das ein:";
            pInstanzB->BtnTest->Caption= "Test";
            pInstanzB->ShowModal();
    //        delete pInstanzB; // delete kann jetzt entfallen
        }
        // ...
    }
    


  • Joe_M. schrieb:

    Weiß nicht, hab den Überblick verloren. 😉 In welchem Form möchtest Du welche dynamische Forminstanz verwenden?

    Bei mir ists auch gleich soweit mit dem Überblick 🙂
    * Ich erzeuge vom Hauptprogramm aus eine dynamische Forminstanz von Form1.
    * Von dieser dynamischen Forminstanz (Instanz A) aus erzeuge ich eine dynamische Forminstanz von Form2 (Instanz B).
    * Dann möchte ich in einer Methode von Instanz B schreibend auf eine public-Variable von Instanz A zugreifen.



  • Dann brauchst Du in Form2 einen Zeiger auf Form1.
    Siehe auch Braunsteins Post. Vermutlich hast Du aber an dieser Stelle die Variable pInstanzA nicht mehr, aber Du willst ja aus dem neuem Form2 auf die (dynamisch erzeugte) Instanz zugreifen, in der Du Dich gerade befindest (richtig?), dann kannst Du dort this übergeben.



  • Joe_M. schrieb:

    Dann brauchst Du in Form2 einen Zeiger auf Form1.
    Siehe auch Braunsteins Post.

    Genau.

    Joe_M. schrieb:

    Vermutlich hast Du aber an dieser Stelle die Variable pInstanzA nicht mehr...

    Naja, "nicht mehr" stimmt so nicht - pInstanzA ist eben scheinbar nur in der Klick-Methode des Hauptprogramms gültig, die ich ja mit pInstanzA->ShowModal() temporär verlasse.

    Joe_M. schrieb:

    ... Du willst ja aus dem neuem Form2 auf die (dynamisch erzeugte) Instanz zugreifen, in der Du Dich gerade befindest (richtig?)...

    Fast, aktuell befinde ich mich per ShowModal() in Instanz B (dynamische Instanz von Form2) und möchte auf Instanz A (vorher erstellte dynamische Instanz von Form1) zugreifen, welche ebenfalls aktuell noch mit ShowModal() angezeigt wird. Das geht aber einfach mit der Zeile in Instanz B

    pInstanzA->publicVariable= Edit1->Text;
    

    nicht (Zugriffsverletzung).

    Schema: Hauptprogramm ➡ Klick ➡ Erzeugen pInstanzA(Form1) ➡ ShowModal() ➡ Button-Klick auf pInstanzA ➡ Erzeugen pInstanzB(Form2) ➡ ShowModal() ➡ Button-Klick auf pInstanzB ➡ ändern von Public-Variable von pInstanzA

    Joe_M. schrieb:

    ...dann kannst Du dort this übergeben.

    Wo jetzt?

    Ich glaube ich habs schon halbwegs kapiert, Instanz B kennt halt Instanz A nicht, und deswegen brauch ich nen Zeiger auf Instanz A, den ich beim Erzeugen von Instanz B an den (überladenen) Konstruktor übergeben kann. Damit ich innerhalb Instanz B mit dem Zeiger arbeiten kann, muss ich den übergebenen Zeiger in eine Member-Variable von Instanz B packen und zwar im Konstruktor. Und da ist momentan noch mein Problem: Wie muss die Member-Variable aussehen, in die ich den Zeiger "packe"? Ist das eine public-Variable von Instanz B? Ist es ebenfalls ein Zeiger? Wenn ja, welchen Typ muss dieser "Member-Zeiger" haben? Und was "packe" ich in den hinein? Die Adresse? Ich raffs nicht...
    Hat mal einer nen Codeschnipsel bitte, wie das "Packen des übergebenen Zeigers in eine Member-Variable" im überladenen Konstruktor aussehen muss?

    Edit: Rechtschreibung 🙄



  • Kolumbus schrieb:

    Wie muss die Member-Variable aussehen, in die ich den Zeiger "packe"? Ist das eine public-Variable von Instanz B? Ist es ebenfalls ein Zeiger? Wenn ja, welchen Typ muss dieser "Member-Zeiger" haben? Und was "packe" ich den hinein? Die Adresse? Ich raffs nicht...

    Es sollte eine membervariable im private-Bereich von TForm2 sein. Der Typ wäre dann Zeiger auf TForm1.

    // .h:
    class TForm2 : public TForm
    {
    __published:
       // ...
    private:
        TForm1* pForm1;
    public:
        __fastcall TForm2(TComponent* Owner, TForm1* InstanzA);
    };
    
    // .cpp - Konstruktor:
    __fastcall TForm2::TForm2(TComponent* Owner, TForm1* InstanzA)
        : TForm(Owner), pForm1(InstanzA)
    { 
    }
    


  • Braunstein schrieb:

    Es sollte eine membervariable im private-Bereich von TForm2 sein. Der Typ wäre dann Zeiger auf TForm1.

    Schön, dann bin ich ja doch nich so doof - so hab ich mir das gedacht.

    Braunstein schrieb:

    // .cpp - Konstruktor:
    __fastcall TForm2::TForm2(TComponent* Owner, TForm1* InstanzA)
        : TForm(Owner), pForm1(InstanzA)
    { 
    }
    

    Das hat mir gefehlt, Danke - wird sofort getestet! 🙂



  • __fastcall TForm2(TComponent* Owner, TForm1*/**/ pInstanzA);
    

    [C++Fehler] 2.h(27): ) expected.

    Hilfe schrieb:

    Am Ende einer Parameterliste wird eine abschließende rechte Klammer erwartet.

    Is doch eine da??? 😕

    Edit: da wo ich die Kommentar-Zeichen gemacht habe, steht der Cursor bei der Fehlermeldung, falls das was zu bedeuten hat!?!



  • Ich schätze mal er kennt TForm1 nicht. Mach einfach mal eine Forwarddeklaration oben in der Headerdatei.

    class TForm1;
    


  • Na, haste denn den header von TForm1 in den header von TForm2 eingebunden?


Anmelden zum Antworten