Probleme beim Schreiben von abstrakten Basisklassen bzw. deren Ableitungen



  • Hallo Leute,

    ich habe mir eine abstrakte Basisklasse und deren Ableitungen geschrieben. Leider
    schlägt mein Programm zur Laufzeit sofort auf wenn so eine polymorphe Methode
    aufgerufen wird.

    Ich habe den Verdacht das nicht die Methode in der abgeleiteten Klasse, sondern
    die abstrakte Methode der Basisklasse aufgerufen wird.

    Beim Aufruf der Methode GetTabString wird eine Exception EAccessViolation
    ausgelöst. Die letzte Zeile die mir der Debugger vor dem Absturz anzeigt, ist
    folgender Constructur der Klasse AnsiString:

    __fastcall AnsiString(): Data(0) {}
    
    // Dies ist die Basisklasse :
    
    class TCustomTabFilterDataSource
    {
    public:
            virtual AnsiString GetTabString() = 0;
            virtual void SetFilter(AnsiString TabName) = 0;
            virtual void DeleteItem(AnsiString TabName) = 0;
            virtual void AddItem(AnsiString TabName) = 0;
            virtual void SaveItem(AnsiString TabName) = 0;
    };
    
    // Und hier die abgeleitete Klasse
    
    class TNotizenTabFilterDataSource : public TCustomTabFilterDataSource
    {
    public:
            TNotizenTabFilterDataSource(TNotizen * Notizen);
            AnsiString GetTabString();
            void SetFilter(AnsiString TabName);
            void DeleteItem(AnsiString TabName);
            void AddItem(AnsiString TabName);
            void SaveItem(AnsiString TabName);
    private:
            TNotizen * FNotizen;
    };
    
    // Cpp:
    
    TNotizenTabFilterDataSource::TNotizenTabFilterDataSource(TNotizen * Notizen)
      : FNotizen(Notizen)
    {
    }
    
    AnsiString TNotizenTabFilterDataSource::GetTabString()
    {
      return(DatenModul->Einstellungen->FieldByName("Notizregister")->AsString);
    }
    
    void TNotizenTabFilterDataSource::SetFilter(AnsiString TabName)
    {
      FNotizen->Filter = Format("Name = '%s'", ARRAYOFCONST((TabName)));
      FNotizen->Filtered = true;
    }
    
    void TNotizenTabFilterDataSource::DeleteItem(AnsiString TabName)
    {
      if(!FNotizen->IsEmpty())      //ToDo: Eof / Bof statt IsEmpty ??
        FNotizen->Delete();
    }
    
    void TNotizenTabFilterDataSource::AddItem(AnsiString TabName)
    {
      TStringList * Notizregister = new TStringList();
    
      Notizregister->CommaText = DatenModul->Einstellungen->FieldByName("Notizregister")->AsString;
      Notizregister->Add(TabName);
    
      DatenModul->Einstellungen->Edit();
      DatenModul->Einstellungen->FieldByName("Notizregister")->Value = Notizregister->CommaText;
      DatenModul->Einstellungen->Post();
    
      delete(Notizregister);
    }
    
    void TNotizenTabFilterDataSource::SaveItem(AnsiString TabName)
    {
      if(FNotizen->IsChanged)
      {
        FNotizen->Name->Value = TabName;
        FNotizen->Post();
      }
    }
    

    Für einen hilfreichen Tip wäre ich sehr dankbar.

    Thanks

    Brainchild



  • Dass die Methode der Abstrakten Klasse aufgerufen wird, kann eigentlich nicht sein, denn die Implementierungen der abgeleiteten Klasse, sehen auf den ersten Blick korrekt aus.

    Der Fehler liegt aber auch nicht am Konstruktor von AnsiString.

    Kannst Du mal den code posten wo der Fehler auftritt und was für eine Fehlermeldung angezeigt wird. Es könnte eigentlich auch sein dass es keine Spalte mit dem Namen Notizregister gibt.



  • AnsiString TNotizenTabFilterDataSource::GetTabString() 
    {   
     try 
     {
    
      if(DatenModul->Einstellungen->Active &&DatenModul->Einstellungen->RecordCount )
    {
     TField* Field= FindField(const AnsiString FieldName);
    if(Field)
      return(Field->AsString); 
    }
    else
    return ""; 
    }
    catch(...)
    {return "";}
    }
    

    sowas wäre besser.



  • bIce schrieb:

    Dass die Methode der Abstrakten Klasse aufgerufen wird, kann eigentlich nicht sein, denn die Implementierungen der abgeleiteten Klasse, sehen auf den ersten Blick korrekt aus.

    Der Fehler liegt aber auch nicht am Konstruktor von AnsiString.

    Kannst Du mal den code posten wo der Fehler auftritt und was für eine Fehlermeldung angezeigt wird. Es könnte eigentlich auch sein dass es keine Spalte mit dem Namen Notizregister gibt.

    Zu Absatz 1+2: Das sehe ich ähnlich
    Zu Abs. 3: Ich kann Dir den Code morgen posten. Die Exception ist auf jeden Fall vom Typ EAccessViolation. Der Fehler tritt auch in einer anderen abgeleiteten Klasse auf, diese verwendet andere Felder und Tabellen. Bei dieser tritt der Fehler auch auf. Das Feld Notizregister gibt es auf jeden Fall. Würde dieses fehlen wäre die Exception auch eine ganz andere. Fehler diesen Grades in den erwähnten Klassen halte ich für ausgeschlossen.

    Möglicherweise liegt der Fehler in der Formular Klasse, welche die Klasse(n) instanziert von der die geposteten Klassen aufgerufen wurden.

    Ich poste Dir den Code auf jeden Fall morgen.

    Bis dahin, danke soweit!



  • Was mich ein wenig wundert: wieso hast Du eine Basisklasse, wenn Du darin gar nichts machst? Ist die Deklaration vollständig oder hast Du da noch Klassenvariablen? Da ein Konstruktor der Basisklasse fehlt, könnte hier vielleicht noch ein Fehler versteckt sein?

    Edit: wenn ich's mir so recht überlege, kann man das von mir oben geschriebene eigentlich vergessen....

    Ich frage mich aber, ob an der angegebenen Stelle tatsächlich eine AnsiString Klasse steht oder ob da nur Datenmüll vorhanden ist....?



  • AndreasW schrieb:

    AnsiString TNotizenTabFilterDataSource::GetTabString() 
    {   
     try 
     {
    
      if(DatenModul->Einstellungen->Active &&DatenModul->Einstellungen->RecordCount )
    {
     TField* Field= FindField(const AnsiString FieldName);
    if(Field)
      return(Field->AsString); 
    }
    else
    return ""; 
    }
    catch(...)
    {return "";}
    }
    

    sowas wäre besser.

    Der Constructor von TEinstellungen sorgt dafür das die DatenMenge auf dem ersten Datensatz steht bzw. dieser ggf. angelegt wird.

    Das ist doch auch eine gute Lösung, oder nicht?



  • JFK schrieb:

    Was mich ein wenig wundert: wieso hast Du eine Basisklasse, wenn Du darin gar nichts machst? Ist die Deklaration vollständig oder hast Du da noch Klassenvariablen? Da ein Konstruktor der Basisklasse fehlt, könnte hier vielleicht noch ein Fehler versteckt sein?

    Edit: wenn ich's mir so recht überlege, kann man das von mir oben geschriebene eigentlich vergessen....

    Ich frage mich aber, ob an der angegebenen Stelle tatsächlich eine AnsiString Klasse steht oder ob da nur Datenmüll vorhanden ist....?

    Diese abstrakte Basisklasse definiert die gemeinsame Schnittstelle für zwei abgeleitete Klassen. Diese implementieren die Funktionalität jeweils auf vollkommen andere Weise.

    Dies nennt man doch auch Polymorphie.



  • Ich hab' den Fehler gefunden!

    Die Exception wurde durch eine fehlerhafte Initialisierung und Instanzierung in den aufrufenden Formularklassen verursacht.

    Folgender Hilfe Eintrag enthielt die entscheidenden Informationen:

    Initialisierung von Klassen

    [...]
    Wie bereits oben erwähnt, werden die Basisklassen in der Reihenfolge ihrer Deklaration initialisiert. Anschließend ***erfolgt die Initialisierung der Elemente (ebenfalls in der Deklarationsreihenfolge)***, unabhängig von der Initialisierungsliste.

    Hier ist der Code der Klassen:

    TfrmNotizen
    -> TTabFilter
    -> TNotizenTabFilterDataSource

    // Header Forumlar Klasse
    //---------------------------------------------------------------------------
    
    #ifndef NotizenH
    #define NotizenH
    //---------------------------------------------------------------------------
    
    .....
    
    //---------------------------------------------------------------------------
    class TfrmNotizen : public TMDIChild
    {
    __published:	// Von der IDE verwaltete Komponenten
    
    ................
    
    private:
            /* Achtung!! Reihenfolge der Deklaration entscheidet über Instanzierungsreihenfolge */
    
            TNotizen * FNotizen;
            TNotizenTabFilterDataSource * FNotizenTabFilterDataSource;
            TTabFilter * FTabFilter;
    public:		// Anwender-Deklarationen
            __fastcall TfrmNotizen(TComponent* Owner);
            __fastcall ~TfrmNotizen();
    };
    //---------------------------------------------------------------------------
    extern PACKAGE TfrmNotizen *frmNotizen;
    //---------------------------------------------------------------------------
    #endif
    
    // Cpp Formular Klasse
    //---------------------------------------------------------------------------
    
    #include <vcl.h>
    #include "pch.h"
    #pragma hdrstop
    
    #include "Notizen.h"
    //---------------------------------------------------------------------------
    #pragma package(smart_init)
    #pragma link "ChildWin"
    #pragma resource "*.dfm"
    TfrmNotizen *frmNotizen;
    //---------------------------------------------------------------------------
    __fastcall TfrmNotizen::TfrmNotizen(TComponent* Owner)
            : TMDIChild(Owner), FNotizen(new TNotizen(this, DatenModul->kdbMainDB)),
              FNotizenTabFilterDataSource(new TNotizenTabFilterDataSource(FNotizen)),
              FTabFilter(new TTabFilter(tbcAktionsplaene, FNotizenTabFilterDataSource,
                                        TNotizenTabFilterIdentCollection()))
    {
      dscNotizen->DataSet = FNotizen;
    
      FNotizen->Open();
      FNotizen->First();
    }
    //---------------------------------------------------------------------------
    
    ........
    
    //---------------------------------------------------------------------------
    
    __fastcall TfrmNotizen::~TfrmNotizen()
    {
      delete(FTabFilter);
      delete(FNotizenTabFilterDataSource);
    }
    
    // Header TTabFilter
    
    //---------------------------------------------------------------------------
    
    #ifndef TTabFilterH
    #define TTabFilterH
    
    ............
    
    //---------------------------------------------------------------------------
    
    class TTabFilter
    {
    public:
            __fastcall TTabFilter(TTabControl * TabControl,
                       TCustomTabFilterDataSource * TabFilterDataSource,
                       TCustomTabFilterIdentCollection IdentCollection);
            __fastcall ~TTabFilter();
            void __fastcall CreatePage();
            void __fastcall DeletePage();
            __property AnsiString ActiveTab  = { read=GetActiveTab };
    private:
            TTabControl * FTabControl;
            TCustomTabFilterDataSource * FTabFilterDataSource;
            TCustomTabFilterIdentCollection FIdentCollection;
            void __fastcall FilterTab();
            void __fastcall TabControlChange(TObject * Sender);
            void __fastcall TabControlChanging(TObject * Sender, bool & AllowChange);
            AnsiString __fastcall GetActiveTab();
    };
    #endif
    
    // Cpp TTabFilter
    //---------------------------------------------------------------------------
    
    #include <vcl.h>
    #include "pch.h"
    #pragma hdrstop
    
    #include "TTabFilter.h"
    
    //---------------------------------------------------------------------------
    
    #pragma package(smart_init)
    
    __fastcall TTabFilter::TTabFilter(TTabControl * TabControl, TCustomTabFilterDataSource * TabFilterDataSource, TCustomTabFilterIdentCollection IdentCollection)
      : FTabControl(TabControl), FTabFilterDataSource(TabFilterDataSource),
        FIdentCollection(IdentCollection)
    {
      AnsiString Register = FTabFilterDataSource->GetTabString(); // Hier schlug das Programm auf, wenn FTabFilterDataSource fehlerhaft instanziert wurde
    
      FTabControl->OnChange = TabControlChange;
      FTabControl->OnChanging = TabControlChanging;
    
      if(Register != "")
        FTabControl->Tabs->CommaText = Register;
    
      FilterTab();
    }
    
    .................
    
    // Den Code von TNotizenTabFilterDataSource kennt Ihr ja schon.
    // Dieser hat sich nicht geändert!
    

    PS: Kennt jemand von Euch einen Style Guide für die Klassen Initialisierung???

    David


Anmelden zum Antworten