Frame, Mehrfachvererbung: Pointer zu Componenten NULL



  • Wir verwenden oft Mehrfachvererbungen auch im Zusammenspiel mit VCL-Klassen.
    Dabei wählen wir genau denselben Weg, den Du auch gewählt hast, also rein
    virtuelle Klasse, die dann von einer Form geerbt (= implementiert) wird.

    Die von Dir beschriebenen Probleme habe ich dabei noch nicht beobachten
    können. Ich habe das schon mit BCB6, BCB2006 und BCB2007 verwendet - ohne
    Probleme.

    Mit der Behauptung "Bug in der VCL" o.ä. bin ich übrigens im allgemein
    etwas zurückhaltend. Es gibt zwar unbestritten einige Bugs, aber in der
    Regel ist es klüger, den Fehler im eigenen Code zu suchen. Leider findet
    man ihn dort auch meist. 🙂

    Gruß

    Alexander



  • wiite schrieb:

    Wissen wir nicht, wir können keine Ferndiagnosen stellen. Du hast doch nicht irgend eine Member-/Baseinitalisierung entfernt oder so?

    Die Member, die NULL sind, sind in

    __published:	// IDE-managed Components
    

    also sollte sich die IDE drum kümmern, das tut sie auch, solange ich nur vom Frame ableite, sobald ich von meinem Interface ableite, sind alle IDE-managed Components NULL.

    Alexander Kempf schrieb:

    Wir verwenden oft Mehrfachvererbungen auch im Zusammenspiel mit VCL-Klassen.
    Dabei wählen wir genau denselben Weg, den Du auch gewählt hast, also rein
    virtuelle Klasse, die dann von einer Form geerbt (= implementiert) wird.

    Auch bei Frames nicht?

    Alexander Kempf schrieb:

    Die von Dir beschriebenen Probleme habe ich dabei noch nicht beobachten
    können. Ich habe das schon mit BCB6, BCB2006 und BCB2007 verwendet - ohne
    Probleme.

    Ich verwende BCB2006 und da ists der Fall

    Alexander Kempf schrieb:

    Mit der Behauptung "Bug in der VCL" o.ä. bin ich übrigens im allgemein
    etwas zurückhaltend. Es gibt zwar unbestritten einige Bugs, aber in der
    Regel ist es klüger, den Fehler im eigenen Code zu suchen. Leider findet
    man ihn dort auch meist.

    Natürlich kanns an meinem Code auch liegen, nur warum kommt dann kein Compilerfehler?

    Wenn ich beispielsweise zuerst vom Interface und dann im Frame ableite, kommt eine Fehlermeldung, dass Frames immer zuerst von TFrame abgeleitet werden müssen.



  • barristan schrieb:

    [...] solange ich nur vom Frame ableite, sobald ich von meinem Interface ableite, sind alle IDE-managed Components NULL.

    Möglicherweise würde es helfen, wenn Du mal ein wenig mehr Quellcode zeigen würdest, z.B. Header-Datei, Constructor etc.

    barristan schrieb:

    Auch bei Frames nicht?

    Mir fallen im Moment nur Abkömmlinge von TForm ein. Könnte aber sein, dass ich das früher mal für Frames verwendet habe.

    barristan schrieb:

    Natürlich kanns an meinem Code auch liegen, nur warum kommt dann kein Compilerfehler?

    Vielleicht weil der Compiler nur überprüfen kann ob der Code C/C++ konform ist (Syntax), nicht
    aber ob er beispielsweise Sinnlosigkeiten enthält (Semantik)?
    Leider habe ich selten Syntax-Fehler und meine Programme tun öfters zu Beginn nicht das, was ich wollte.

    Gruß

    Alexander



  • Es wird nichts bringen, wenn ich hier weiteren Quellcode poste, weil ich alles wichtige zur Thematik bereits gesagt habe.

    Wo kann ich denn Fehler machen?

    a) Klasse falsch definieren (hab ja den Quellcode gepostet, nur die Namen sind etwas anders)
    b) Ableitung falsch machen (auch das habe geschrieben public EinInterface)
    c) Virtualle Funktionen nicht im Frame implementiert (das motzt der Compiler sofort an, wenn ich versuche eine Instanz der Klasse zu erzeugen und daher habe ich das auch gemacht)

    Ansonsten hat sich an meinem bischerigen Quellext nichts geändert, der ist exakt so wie vorher.

    Wenn ich das ,public EinInterface

    auskommentiere, funktionierts, wenn ichs drinlasse, werden die von der IDE verwalteten Komponenten nicht im Heap angelegt. Und dafür ist die IDE zuständig. Ist ja nicht so, dass ich vorher den Komponenten NULL zuweise.

    edit:
    mir ist gerade aufgefallen, dass nicht alle Pointer der Komponenten auf NULL zeigen, einige haben eine gültige Adresse, andere wiederum nicht.



  • Hast Du eigentlich schon mal das Ganze mit einem Formular
    anstatt einem Frame ausprobiert?

    Gruß

    Alexander



  • Hab das selbe Problem.
    Mit 2 Forms geht es, nur nicht mit einem Frame.
    Da scheint die Kommunikation zur Form, in der es sich befindet, immer wieder Speicherverletzungen herbeizuführen.

    Unit2.h:

    public:		// User declarations
    	__fastcall TFrame2(TComponent* Owner);
    	void bla();
    };
    

    Unit2.cpp:

    void TFrame2::bla() {
    	Button1->Caption="a";
      }
    

    Unit1.h:

    #include "Unit2.h"
    

    Unit1.cpp:

    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
    Frame2->bla();
    }
    

    Das gibt eine schöne Speicherzugriffsverletzung.
    Für Lösungevorschläge wäre ich sehr sehr dankbar.
    Der Compiler sollte für so etwas aber wenigstens eine Warnung rausgeben 😞
    Btw... ein Bug im Compiler kann ich eigentlich ausschließen.
    Hab es mit Borland C++ Builder 6 Enterprise und CodeGear C++ Builder 2007 Enterprise getestet => Selbes deprimierendes Ergebniss.
    Google hilft leider auch nicht weiter...

    Mfg, maZe



  • Hallo

    Wo gibt es da eine Speicherverletzung? Beim Starten des Programms oder beim Klick auf den Button?
    Bei letzerem wäre doch die Frage ob hinter Frame2 überhaupt eine gültige Instanz steht? Denn das Erstellen der automatisch generierten Instanzen kann man ja in den Projektoptionen ein- und ausschalten.

    Ich habe diesen Test jedenfalls mit meinem BCB5 gemacht und konnte keinerlei Probleme feststellen.

    bis bald
    akari



  • Beim klicken des Buttons, als wenn ich von Form1 auf Funkionen von Frame2 zugrifen will, passiert es 😕

    Btw.: Mein OS: Vista



  • Ein Projekt mit einer Form und einem Frame darin erstellen.
    In den Frame ein Shape und in die Form ein Button.
    Jetzt mal als onClick-Anweisung des Buttons angeben: Frame2->Shape1->Top--;

    dann kommt die Verletzung (bei mir...)





  • Hallo,

    ich habe das mal eben mit BDS 2006 Professional ausprobiert und überhaupt keine
    Probleme gehabt.

    Ich bin folgendermaßen vorgegangen:
    1. Neues VCL-Projekt
    2. Neuen Frame innerhalb des Projekts mit 1 Button, 1 Label, 1 Edit
    3. Neue Header-Datei "IDummy.h" (s. unten)
    4. Frame von IDummy erben lassen
    5. Frame in Palette hinzufügen (lassen)
    6. Im Hauptformular Frame einfügen (MyFrame), außerdem 1 Button und 1 Memo
    7. Im Click-Ereignis des Buttons auf Frame-Komponenten zugreifen (s. unten)
    8. In der von IDummy geerbten Funktion foo() auf die Komponenten des Frames zugreifen (s. unten)

    Hier noch ein wenig Source-Code:

    IDummy.h

    #ifndef IDummyH
    #define IDummyH
    
    class IDummy
    {
       public:
          virtual void foo() = 0;
    };
    
    #endif
    

    Header-Datei des Frames

    //---------------------------------------------------------------------------
    
    #ifndef Unit2H
    #define Unit2H
    //---------------------------------------------------------------------------
    #include <Classes.hpp>
    #include <Controls.hpp>
    #include <StdCtrls.hpp>
    #include <Forms.hpp>
    
    #include <IDummy.h>
    //---------------------------------------------------------------------------
    class TFrame2 : public TFrame, public IDummy
    {
    __published:
       TButton *Button1;
       TLabel *Label1;
       TEdit *Edit1;
    public:
       __fastcall TFrame2(TComponent* Owner);
    
       virtual void foo();
    };
    //---------------------------------------------------------------------------
    extern PACKAGE TFrame2 *Frame2;
    //---------------------------------------------------------------------------
    #endif
    

    OnClick des Buttons auf Hauptformular

    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
       IDummy* dummy = MyFrame;
       dummy->foo();
       Memo1->Lines->Add(MyFrame->Button1->Name + "::Caption = " + MyFrame->Button1->Caption);
       Memo1->Lines->Add(MyFrame->Label1->Name + "::Caption = " + MyFrame->Label1->Caption);
       Memo1->Lines->Add(MyFrame->Edit1->Name + "::Text = " + MyFrame->Edit1->Text);
    }
    

    Implementierung von IDummy::foo() im Frame

    void TFrame2::foo()
    {
       AnsiString componentProperties = "";
       componentProperties = Button1->Name + "::Caption = " + Button1->Caption + "\r\n"
                             + Label1->Name + "::Caption = " + Label1->Caption + "\r\n"
                             + Edit1->Name + "::Text = " + Edit1->Text;
       ShowMessage(componentProperties);
    }
    

    Keine Zugriffsverletzung, nichts um die Ohren geflogen.

    Ich habe auch mal eine Instanz des Frames dynamisch per Code erstellt. Auch
    keine Probleme.

    Irgendwas habt ihr wohl anders gemacht. Fragt sich bloß was.

    Gruß

    Alexander



  • hier mal das projekt, bei dem bei mir der fehler kommt:
    http://egaming-bonn.de/users/maze/moo.7z



  • Wie soll das funktionieren?
    Du verwendest nicht die Variable Deines Frames auf dem Formular,
    sondern die im Frame deklarierte globale Variable (die meiner Meinung
    nach standardmäßig nicht erstellt werden sollten).

    Header-Datei Deines Formulars:

    class TForm1 : public TForm
    {
    __published:
    	TFrame2 *Frame21; // <---------- Hier die Variable, die Du verwenden solltest
    	TButton *Button1;
    	void __fastcall Button1Click(TObject *Sender);
    public:
    	__fastcall TForm1(TComponent* Owner);
    };
    

    CPP Deines Formulars:

    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
    Frame2->Button1->Caption="test";  // <------- Falsch verwendet
    }
    

    Gruß

    Alexander



  • Erstes Interface:

    class IBla
    {
    	public:
      	virtual void machWas() = 0;
    };
    

    Zweites Interface:

    class IBlub
    {
    	public:
    		virtual void machMehr() = 0;
    };
    

    Frame 1:

    class TfrmOne : public TFrame, public IBla
    {
    __published:	// IDE-managed Components
    	TMemo *Memo1;
    	TLabel *Label1;
    	TEdit *Edit1;
    	TListBox *ListBox1;
    	TPanel *Panel1;
    private:	// User declarations
    public:		// User declarations
    	__fastcall TfrmOne(TComponent* Owner);
    	virtual void machWas();
    };
    

    Frame 2:

    class TfrmTwo : public TfrmOne, public IBlub
    {
    __published:	// IDE-managed Components
    	TListBox *ListBox2;
    	TRadioButton *RadioButton1;
    private:	// User declarations
    public:		// User declarations
    	__fastcall TfrmTwo(TComponent* Owner);
    	virtual void machMehr();
    };
    

    Frames mit paar Komponenten befüllen und auf ein Form knallen. Was kommt? Er kann die Klasse TfrmTwo nicht finden.

    Entferne ich nun ",public IBlub" von TfrmTwo, läuft das Programm einwandfrei. Entferne ich ",public IBla" von TfrmOne, aber ändere nichts an TfrmTwo, läufts auch. Anscheinend hat Borland Probleme sobald man bereits bei einem Parent Frame ein Interface implementiert hat und nun bei einem Child Frame ein anderes zusätzlich implementieren möchte.



  • ... was allerdings jetzt ein völlig anderes Problem als das eingangs beschriebene ist.
    Vielleicht komme ich heute abend mal dazu das nachzustellen.

    Gruß

    Alexander



  • Alexander Kempf schrieb:

    Wie soll das funktionieren?
    Du verwendest nicht die Variable Deines Frames auf dem Formular,
    sondern die im Frame deklarierte globale Variable (die meiner Meinung
    nach standardmäßig nicht erstellt werden sollten).

    Header-Datei Deines Formulars:

    class TForm1 : public TForm
    {
    __published:
    	TFrame2 *Frame21; // <---------- Hier die Variable, die Du verwenden solltest
    	TButton *Button1;
    	void __fastcall Button1Click(TObject *Sender);
    public:
    	__fastcall TForm1(TComponent* Owner);
    };
    

    CPP Deines Formulars:

    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
    Frame2->Button1->Caption="test";  // <------- Falsch verwendet
    }
    

    Gruß

    Alexander

    mit 2 forms geht das aber... warum nicht mit frame & form ??



  • maehze schrieb:

    mit 2 forms geht das aber... warum nicht mit frame & form ??

    Darüber solltest Du Dir mal in einer ruhigen Minute Gedanken machen.
    Kleine Denkanstöße:
    - Was bezweckt man eigentlich mit Frames?
    - Hast Du schon mal versucht 4 identische Forms auf einer Form im Designer abzulegen?

    Gruß

    Alexander



  • barristan schrieb:

    Er kann die Klasse TfrmTwo nicht finden.
    Entferne ich nun ",public IBlub" von TfrmTwo, läuft das Programm einwandfrei.

    Kann ich mit BCB2006pro nachvollziehen. In der Tat wird ordnungsgemäß kompiliert, aber zur Laufzeit
    wird die Klasse des vom ersten Frame erbenden Frames nicht gefunden.
    Wäre noch interessant herauszufinden, ob beim BCB2007 das Problem auch noch besteht.

    Glücklicherweise habe ich Frames noch nie in dieser Form verwenden müssen.

    Gruß

    Alexander



  • Das Problem besteht auch beim BCB2007. Ich denke man könnt den Fall mal bei QualityCentral reinstellen.



  • Braunstein schrieb:

    Das Problem besteht auch beim BCB2007. Ich denke man könnt den Fall mal bei QualityCentral reinstellen.

    Ja ja, man muss nur feste dran glauben, dass es hilft.
    Mein Bug-Report ist mittlerweile 6 Jahre alt. Passiert ist da allerdings überhaupt nichts...


Anmelden zum Antworten