Observer Pattern im BCB



  • Hallo

    Bin grad dabei ein ErrorHandling - System über das Observer Pattern zu implementieren, sprich:

    Wenn irgendein Objekt einen Fehler erzeugt, wird dieser an alle registrierten Objekte gesendet.

    Also eine Klasse CListener geschrieben:

    class CListener
    {
    	public:
    		virtual void GetError(eError e,AnsiString text)=0;
    };
    

    Jetzt wollte ich 4 andere Klassen davon erben lassen, aber das geht nur bei Klassen, welche nicht von VCL Objekten abgeleitet werden.

    class Rod4Handler : public TThread , public CListener
    

    Leider bringt er da immer folgenden Fehler:

    [C++ Fehler] Rod4Handler.h(69): E2278 VCL-Klassen dürfen nicht mehrere Basisklassen haben.
    

    Gibts irgendeinen Workaround für?

    Die einzige Möglichkeit, die mir noch einfallen würde, wäre das ganze über Funktionspointer zu implementieren, wäre aber unschön.

    Mfg

    Reinhold Fischer



  • Hallo

    Wie die Fehlermeldung schon sagt kann auf die VCL-Klassen keine Mehrfachableitung angewendet werden. Du must eine Komposition verwenden : Leite von CListener ab und las diese Klasse einen Pointer auf ein TThread als Member bekommen. Nun kannst du in der Thread-Klasse eine Membervariable von der CListener-Variable erzeugen die in der Initialisierungliste this für den Thread-Parameter bekommt.

    Btw : Wenn du schon wie in der VCL Präfixe benutzt dann bitte einheitlich, nicht T und noch C mischen.

    bis bald
    akari



  • Danke für die Antwort, hab das aber noch net so richtig verstanden 😉

    Bis jetzt hab ich das so verstanden:

    class meinThreadListener : public CListener
    {
         public:
            CListener(alteThreadKlasse* mklasse);
    
            void GetError(eError e,AnsiString msg)
            {
               meineKlasse->GetError(e,msg);
            }
         ....
         public:
          meinealteThreadKlasse* meineKlasse;
    };
    class meinealteThreadKlasse : public TThread
    {
          ......
          public:
           meinThreadListener* listener; <-- diesese Element übergebe ich dann dem Observer
    };
    

    Keine Ahnung ob du das so meinst, aber falls ja, dann muß ich ja für jede Klasse welche ich von TThread ableite, einen eigenen ThreadListener implementieren.

    Danke

    Reinhold Fischer



  • Hallo

    Fast

    class meinThreadListener : public CListener
    {
         public:
            CListener(alteThreadKlasse* mklasse);
    
            void GetError(eError e,AnsiString msg)
            {
               meineKlasse->GetError(e,msg);
            }
         ....
         public:
          meinealteThreadKlasse* meineKlasse;
    };
    class meinealteThreadKlasse : public TThread
    {
          ......
          public:
           meinThreadListener listener; // wird automatisch vom Thread angelegt
    };
    
    // Konstruktor vom Thread
    meinealteThreadKlasse(...) : TThread(...), listener(meinThreadListener(this)) // Initialisierungsliste
    

    Da ich nicht weiß wieviele Threadklassen du hast oder was der Listener für Methoden aufrufen muß kann ich nicht einschätzen ob das optimal ist. Wenn du allerdings noch eine Polymorphe Basisklasse zwischen TThread und <NutzklasseThread> setzt, die sich nur um den Einbau des Listeners kümmert, kannst du auch so flexibel erweitern.

    bis bald
    akari



  • Hi

    Also, wollte das jetzt so implementieren, erstmal nur zum ausprobieren, uns besserem Verständniss.

    Was ich/wir aber nicht beachtet haben, das ich folgendes garnicht aufrufen kann:

    meineKlasse->GetError(..);
    

    Da meinealteThreadKlasse in meinThreadListener ja noch garnicht bekannt ist.

    Man könnte zwar ein class meinealteThreadKlasse; davor hinzufügen, dann kennt er es zumindest, aber dann kann ich GetError immernoch nicht aufrufen.

    Irgendwelche Ideen?

    Mfg

    Reinhold Fischer



  • Hallo

    Dann must du die Thread-Klasse bekannt machen. Mit Forward-Declarations kann man die Abhängigkeiten dabei minimieren.
    Das heißt in die jeweiligen Headerdateien gehört nur jeweils

    class <NameDerAnderenKlasse>;
    

    Das reicht um in der Headerdatei Pointer und Referenzen von der anderen Klasse zu benutzen.
    In der jeweiligen Implementationsdatei kannst du dann den jeweils nötigen include auf die andere Headerdatei einbauen.

    bis bald
    akari



  • Ahh danke, der Tip mit dem Implementieren in der cpp datei und includieren der passenden .h datei hat mir gefehlt.

    Hab das ganze jetzt folgendermaßen implementiert:

    class ThreadListener : public CListener
    {
    public:
    	ThreadListener(Rod4Handler* mRod4)
    	{
    		m_Rod4Handle=mRod4;
    		m_KommunikationHandle=NULL;
    		m_FormHandle=NULL;
    	}
    
    	ThreadListener(Kommunikation* mk)
    	{
    		m_KommunikationHandle=mk;
    		m_Rod4Handle=NULL;
    		m_FormHandle=NULL;
    	}
    
    	ThreadListener(TForm1* mf)
    	{
    		m_FormHandle=mf;
    		m_Rod4Handle=NULL;
    		m_KommunikationHandle=NULL;
    	}
    
    	void GetError(eError e,AnsiString msg);
    private:
    	Rod4Handler* m_Rod4Handle;
    	Kommunikation* m_KommunikationHandle;
    	TForm1* m_FormHandle;
    };
    

    cpp-datei:

    void ThreadListener::GetError(eError e,AnsiString msg)
    {
    	if(m_Rod4Handle!=NULL)
    		m_Rod4Handle->GetError(e,msg);
    	if(m_KommunikationHandle!=NULL)
    		m_KommunikationHandle->GetError(e,msg);
    	if(m_FormHandle!=NULL)
    		m_FormHandle->GetError(e,msg);
    }
    

    Zwar net ganz so dynamisch, aber für meine Zwecke vollkommen ausreichend.

    Mfg

    Reinhold Fischer



  • Hallo

    da würde ich lieber für die Klassen Rod4Handler, Kommunikation und TForm1 jeweils eine eigene Klasse von ThreadListener ableiten, wo nur diese spezielle Klasse behandelt wird. Das ist wesentlich eleganter und auch Geschwindigkeitsoptimiert (betrifft die mehrfachen unnötigen if-Abfragen)

    bis bald
    akari


Anmelden zum Antworten