(MFC mit dem...) template und virtual functionen



  • @HumeSikkins

    was will ich machen -> nicht ganz einfach zu beantworten.

    die klassenhierarchie ist die mfc und das ist schon das erste problem.

    die hierarchie:

    CWnd
    |
    CEdit
    |
    CEditD -- meine erweiterte klasse

    CWnd
    |
    CComboBox
    |
    CComboBoxD -- meine erweiterte klasse

    warum will und brache ich virtual functionen.

    1. die fensterklasse combobox hat einen 3D border der in der Win-Fensterklasse bei WM_Paint gezeichnet wird. ich habe WM_Paint soweit bearbeitet das dieser border nicht mehr gezeichnet wird (funktioniert).

    2. GetWindowRect(hWnd, &rc) gibt mir die grösse zurück

    3. da ich aber den border (ausschneide) brauche ich eine virtuale function, die mir die korrekte grösse zurückgibt.

    3. SetWindowPos && MoveWindow werden genauso bearbeitet

    meine momentane klassenhierarchie mit den oben genannte eigenschaften funktioniert, der nachteil ich prüfe zur laufzeit die jeweilige klasse und cast sie dementsprechend (performents verlust).

    in der mfc bekomme ich über CWnd* pWnd=CWnd::FromHandle(hWnd); die basisklasse

    CWnd
    |
    CComboBox
    |
    CComboBoxD

    ich habe mir gedacht mit template

    CWnd
    |
    CComboBox
    |
    TWndD
    |
    CComboBoxD ->class CComboBox: public TWndD<CComboBox>

    gibt es eine möglichkeit im template TWndD virtuale functionen unterzubringen,
    die ich über *einen* aufruf von FromHandle(hWnd); aufrufen kann ????

    volker



  • Hallo,
    sorry ich kann nicht folgen. Kannst du vielleicht ein kleines Beispiel zusammenbasteln (am Besten ohne MFC) das dein Problem bzw. dein Ziel verdeutlicht?

    gibt es eine möglichkeit im template TWndD virtuale functionen unterzubringen,
    die ich über *einen* aufruf von FromHandle(hWnd); aufrufen kann ????

    Natürlich kann eine Templateklasse eine virtuelle Methode einer Basisklasse überschreiben. Warum betonst du das *einen*?

    Sehe ich es richtig, dass du dir über FromHandle ein Basisklassenpointer (CWnd) holen möchtest, über den du dann eine virtuelle Methode aufrufen willst mit dem Ergebnis das die Methode in der Templateklasse TWnd<T> aufgerufen werden soll?



  • hallo,

    Sehe ich es richtig, dass du dir über FromHandle ein Basisklassenpointer (CWnd) holen möchtest, über den du dann eine virtuelle Methode aufrufen willst mit dem Ergebnis das die Methode in der Templateklasse TWnd<T> aufgerufen werden soll?

    genau so ist es.

    das problem ist

    CWnd -basisklass kann vom inhalt nicht mehr verändert werden-
    |
    [eine klasse z.b CEdit]
    die klasse beschreibt z.b die eigenschaften von einem Eingabefeld
    und kann ebenfals nicht mehr verändert werden

    |
    und hier beginnt meine arbeit. wie du schon oben erwähnt hast gibt mir eine statische function die basisklasse CWnd anhand eines Fensterhandle zurück.

    class CWnd
    {
      //hier stehen nur standartzugriffe z.b
      DWORD GetStyle()
      {
        return ::GetWindowLong(m_hWnd, GWL_STYLE);
      }
    };
    
    // template
    template <class BASE> class TWndD : public BASE
    {
      virtual void meineVirtualFunction()
      {
        //hier bearbeite ich standart
      };
    };
    

    mein template kann sowohl direkt

    class CAbgeleitet_von_CWnd: public TWndD<CWnd>
    {
      virtual void meineVirtualFunction()
      {
      //diese will ich nutzen
      };
    
    };
    

    als auch z.b von CEdit abgeleitet werden.

    class CEdit: public CWnd
    {
      //hier stehen nur allgemeine zugriffe für ein eingabefeld drin
    };
    
    class CEditD: public TWndD<CEdit>
    {
     virtual void meineVirtualFunction()
      {
      //diese will ich nutzen
      };
    };
    

    mein ziehl wäre es

    [cpp]
    //hwnd ist mein fensterhandle
    TWndD<void/*weis ich ja nicht*/>* pClass=TWndD<void>::FromHandle(hwnd);

    //pClass soll jetzt meine klasse (basis) sein wo ich meine virtual functionen
    //schreiben und ansprechen kann. es ist ja vorstellbar, das ich ein
    //pointer von pClass erhalte obwohl in meiner klassenhierarchie kein template
    //existiert.

    pClass->meineVirtualFunction(); //und jetzt auf die virtual function zugreifen

    DWORD n=pClass->GetStyle(); //steht in CWnd[/cpp]

    hast du eine idee ??

    [ Dieser Beitrag wurde am 05.06.2003 um 15:35 Uhr von vdittrich editiert. ]

    [ Dieser Beitrag wurde am 05.06.2003 um 15:36 Uhr von vdittrich editiert. ]



  • @HumeSikkins

    kann ich dich noch mal zu meinen problem befragen ?
    brauchst du vom mir noch zuarbeit oder kannst du meine vorstellung bzw. vorgehensweise nicht nachvollziehen.

    volker



  • Hallo,
    sorry. Ich habe gestern abend zwar drüber nachgedacht, bin aber nicht wirklich dahinter gekommen wo genau der Schuh dich drückt.

    wie du schon oben erwähnt hast gibt mir eine statische function die basisklasse CWnd anhand eines Fensterhandle zurück.

    Also so:

    class CWnd
    {
    public:
    static CWnd* FromHandle( HWND hWnd );
    
    };
    

    class CAbgeleitet_von_CWnd: public TWndD<CWnd>
    {
    virtual void meineVirtualFunction()
    {
    //diese will ich nutzen
    };

    };

    Was bedeutet "meineVirtualFunction" in diesem Fall. Ist das eine beliebige virtuelle Funktion, die in CWnd deklariert ist und die du in deinen abgeleiteten Klassen überschreiben möchtest oder ist das eine *neue* virtuelle Funktion, die es in CWnd nicht gibt und erst in der Templateklasse zur Hierarchie hinzugefügt wird?

    TWndD<void/*weis ich ja nicht*/>* pClass=TWndD<void>::FromHandle(hwnd);

    Das kann nicht gehen. void ist keine gültige Basisklasse. Was soll hier stehen? Und vorallem wo tritt dieser Code auf?



  • hallo, entschulige der aufbau und hierarchie habe ich vieleicht doch etwas umständlich erklärt.

    Also so: --> korrekt

    class CWnd
    {
    public:
    static CWnd* FromHandle( HWND hWnd );
    
    };
    

    Was bedeutet "meineVirtualFunction" in diesem Fall. Ist das eine beliebige virtuelle Funktion, die in CWnd deklariert ist und die du in deinen abgeleiteten Klassen überschreiben möchtest oder ist das eine *neue* virtuelle Funktion, die es in CWnd nicht gibt und erst in der Templateklasse zur Hierarchie hinzugefügt wird?

    //auszug aus CWnd
    class CWnd
    {
    public:
      static CWnd* FromHandle( HWND hWnd );
    
      DWORD GetStyle() const;
      BOOL ModifyStyle(DWORD dwRemove, DWORD dwAdd, UINT nFlags = 0);
      void GetWindowRect(LPRECT lpRect) const;
    
     //..
    };
    
    //auszug template
    template <class BASE> class TWndD : public BASE
    {
      virtual DWORD GetStyle() const
      {
        return BASE::GetStyle();     //wird standartmäßig weitergeleitet 
      };
    
      virtual BOOL ModifyStyle(DWORD dwRemove, DWORD dwAdd, UINT nFlags = 0)
      {
        return BASE::ModifyStyle(DWORD dwRemove, DWORD dwAdd, UINT nFlags = 0);
      };
    
      virtual void GetWindowRect(LPRECT lpRect) const
      {
        BASE::GetWindowRect(LPRECT lpRect);
      };
    
      enum cTyp
      {
        CEditD=0,
        CComboBoxD,
      };
    
      cTyp GetTyp()
      {
        //..
      }; 
    
      virtual SetClip(bool bClip)
      {
        //..
      };
    };
    
    //z.b teil hierarchie
    class CEditD: public TWndD<CEdit>    //class CEdit:public CWnd; 
    {
    
      virtual DWORD GetStyle() const
      {
        //..
      };
    
      virtual void GetWindowRect(LPRECT lpRect) const
      {
        //..
      };
    
    };
    
    class CComboBoxD:public TWndD<CComboBox>  //class CComboBox:public CWnd;
    {
     virtual DWORD GetStyle() const
      {
        //..
      };
    
      virtual BOOL ModifyStyle(DWORD dwRemove, DWORD dwAdd, UINT nFlags = 0)
      {
        //..
      };
    
      virtual void GetWindowRect(LPRECT lpRect) const
      {
        //..
      };
    
    };
    
    //und jetzt noch codebeispiel was ich in template umwandeln will
    
    // extern CWndD class
    #define CEditD_CWnd         "CEditD"
    #define CComboBoxD_CWnd     "CComboBoxD"
    
    class CWndD: public CWnd
    {
    public:
    void CWndD::GetWindowRect(LPRECT lpRect) const
    {
      CRuntimeClass* prt = this->GetRuntimeClass();
      char *sRet, *sClass=(char*)prt->m_lpszClassName;
      if ((sRet=strstr(sClass, CEditD_CWnd))!=0 && (sRet-sClass)==0)
      {
        ((CEditD*)this)->GetWindowRect(lpRect);
        return;
      }
      if ((sRet=strstr(sClass, CComboBoxD_CWnd))!=0 && (sRet-sClass)==0)
      {
        ((CComboBoxD*)this)->GetWindowRect(lpRect);
        return;
      }
      this->CWnd::GetWindowRect(lpRect);
    }
    
    //..
    
    private:
    
    struct eParam
    {
      HRGN rgn;
      HWND hwnd;
    };
    
    BOOL CWndD::EnumChildProc(HWND hwndChild, LPARAM lParam) 
    {
      eParam* tParam=(eParam*)lParam;
      if ((tParam->hwnd==::GetParent(hwndChild)) && ::IsWindowVisible(hwndChild))
      {
        CWndD* pWnd=(CWndD*)CWnd::FromHandle(hwndChild);
        #ifdef _DEBUG
        {  
          ASSERT(pWnd && pWnd->m_hWnd); 
          //CRuntimeClass* prt = pWnd->GetRuntimeClass();
          //TRACE("CALLBACK EnumChildProc %x class:%s\n", hwndChild, prt->m_lpszClassName);
        }
        #endif
        RECT rc; pWnd->GetWindowRect(&rc);      //hier jetzt bitte die richtige grösse
        HRGN rgn=::CreateRectRgnIndirect(&rc);
        ::CombineRgn(tParam->rgn, tParam->rgn, rgn, RGN_DIFF);   
        ::DeleteObject(rgn); 
      }
      return 1;
    }
    
    //..
    
    };
    

    ich habe das jetzt alles mal in einander kopiert, hoffenlich ist es für dich jetzt etwas übersichtlicher

    [ Dieser Beitrag wurde am 06.06.2003 um 13:14 Uhr von vdittrich editiert. ]



  • scheint also doch keine lösung zu geben ?



  • scheint also doch keine lösung zu geben ?

    Keine Ahnung. Ich für meinen Teil bin noch nicht mal dazu gekommen, dein letztes Posting zu lesen. Neben dem Forum erfordern schließlich auch andere Dinge meine Aufmerksamkeit.



  • Original erstellt von HumeSikkins:
    [quote] scheint also doch keine lösung zu geben ?

    **
    Keine Ahnung. Ich für meinen Teil bin noch nicht mal dazu gekommen, dein letztes Posting zu lesen. Neben dem Forum erfordern schließlich auch andere Dinge meine Aufmerksamkeit.**[/QUOTE]

    das ist doch klar @HumeSikkins, ich bin doch froh wenn mir jemand helfen kann,
    ich finde keine lösung.

    wenn du zeit hast, ich wäre dir sehr dankbar.

    volker



  • Hallo,
    also ich verstehe nicht viel von der MFC, aber so wie ich das sehe machst du einiges verkehrt.

    Erste Beobachtung:
    Die Methoden GetStyle(), ModifyStyle(), und GetWindowRect() sind in der Basisklasse als *nicht* virtuell deklariert. Sie können also *nicht* überschrieben werden und es macht überhaupt keinen Sinn sie in abgeleiteten Klassen als virtuelle Methoden zu implementieren. Ein Aufruf über eine CWnd::Referenz (CWnd) wird *immer* die Methoden von CWnd aufrufen.

    Die virtuellen Methoden in deinen abgeleiteten Klassen überdecken die Basisklassen-Methoden. Das virtuell gilt erst für weiter abgeleitete Klassen.

    Zweite Beobachtung:
    Die Implementationen deiner neuen virtuellen Methoden forwarden eh nur zur Basisklasse. Sie sind also überflüssig und können weg.

    Dritte Beobachtung:
    Die Implementation von CWnd::GetWindowRect() sieht so aus:

    _AFXWIN_INLINE void CWnd::GetWindowRect(LPRECT lpRect) const
    { ASSERT(::IsWindow(m_hWnd)); ::GetWindowRect(m_hWnd, lpRect); }
    

    Es wird also nur die globale GetWindowRect-Funktion aufgerufen. Ein Überschreiben war wohl nie geplant. Der Aufruf ist unabhängig vom Window-Typ.

    Vierte Beobachtung:
    Deine Implementation von CWndD::GetWindowRect macht unter Berücksichtung meiner ersten drei Beobachtungen überhaupt keinen Sinn.

    Fünfte Beobachtung:
    Mir scheint du bist auf dem völlig falschen Dampfer.
    Kann es sein, dass du viel eher die virtuelle Funktion CalcWindowRect überschreiben musst?

    Sechste Beobachtung:
    Was du hier brauchst und versuchst zu implementieren ist *dynamische* Polymorphie. Ein Template hilft dir hier also nicht weiter.

    Siebte Beobachtung:
    Mir scheint das ganze ist eher ein MFC-Problem bzw. eine Frage danach, wie man ein bestimmtes Ziel zusammen mit der MFC erreicht.
    Ein Standard-C++ Problem sehe ich zumindest nicht. Insofern denke ich, du wärst im MFC-Forum besser aufgehoben.


Anmelden zum Antworten