(MFC mit dem...) template und virtual functionen
-
hi, ich habe folgendes problem als beispiel
// basis klasse -> kann nicht verändert werden class CWnd { void func(); }; // abgeleitete klasse -> kann nicht verändert werden class CEdit: public CWnd { }; // template template <class BASE> class TWndD : public BASE { virtual void xx() { }; }; // meine klasse class CEditD : public TWndD<CEdit> { CEditD() { //ich habe immer nur die möglichkeit mit der Basisklasse CWnd zu agieren TWndD<CWnd>* pWnd=(TWndD<CWnd>*)this; pWnd->xx(); // und hier ist der fehler, es wird immer eine andere function aufgerufen } void xx() {}; };
kann ich das problem überhaupt lösen, ich muss aber eine template benutzen, den es muss z.b. auch möglich sein:
class CComboBox: : public CWnd { }; class CComboBoxD : public TWndD<CComboBox> { void xx() {}; };
[ Dieser Beitrag wurde am 04.06.2003 um 08:26 Uhr von vdittrich editiert. ]
-
Hallo,
TWndD<CWnd>* pWnd=(TWndD<CWnd>*)this;
Dieser Cast ist schon mal verboten. *this ist ein CEditD. Legal wäre eine Konvertierung in eine der Basisklassen (TWndD<CEdit>, CEdit, CWnd).
TWndD<CWnd> steht aber in *keiner* Beziehung mit CEditD.pWnd->xx();
Mal abgesehen davon, dass der Aufruf hier undefiniertes Verhalten hat würde er auch nicht das tun, was du scheinbar denkst.
Du bist innerhalb eiens Ctors dort gibt es keine dynamische Bindung. Wenn du hier eine virtuelle Methode einer Hierarchie aufrufst, wird immer die Methode der Klasse aufgerufen, in dessen Konstruktor du dich befindest (hier also CEditD::xx).Was willst du eigentlich machen? Ich verstehe das Problem ehrlich gesagt nicht.
[ Dieser Beitrag wurde am 04.06.2003 um 16:50 Uhr von HumeSikkins editiert. ]
-
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 klasseCWnd
|
CComboBox
|
CComboBoxD -- meine erweiterte klassewarum 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
|
CComboBoxDich 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. ]
-
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.