Templates und Polymorphie; Klasse von Templateklasse aberben
-
Typie schrieb:
Aber das funktioniert nicht so wie ich das vorhabe.
Was erhältst du denn für eine Fehlermeldung (ich nehme mal naiverweise an, die Tippfehler sind in deinem Programm nicht vorhanden)?
P.S.:
Typie schrieb:
aberben
Wer sagt denn so etwas?

-
Ok ich bin der Threaderöffner, hab mich nun registriert
(also: Hi :D)Und ja, das mit den verschiedenen Bezeichnern war ein Tippfehler... Man sollte doch direkt den Code kopieren und nicht noch im Feuerfuchs was dran rumbasteln -.-
Also nochmal der Code in jetzt richtig:template <int N, int TimeMod, class FT> class pDGL { public: FT u[N][TimeMod]; pDGL(double adx, double adt) : time(1), dx(adx), dt(adt) { // ... } // ... }; template<int N, int SolitonCount> class SolitonSolver: public pDGL<N,3,double> { ////////<<<<<<<<<<<< public: SolitonSolver(double adx, double adt) : pDGL<N,3,double>(adx, adt) { // ... } // ... }; int main () { SolitonSolver<256,3> Sol(0.18,0.002); // ... return 0; }Die genauen Fehlermeldungen brauch ich glaub ich eher nicht zu posten, weil das einfach zu viele sind. Aber so wie ich das sehe, laufen die meisten darauf hinaus, dass er in der Klasse SolitonSolver die ganzen public-Variablen aus pDGL nicht kennt: "'dx' was not declared in this scope" etc, wobei dx halt ein public double in pDGL ist.
(und ich finde ab-erben ein durchaus verständliches Wort
)Ach ja und mir ist klar dass zur Compiletime alles fest gelegt ist; aber das ist in diesem Fall egal. Das Programm wird ne numerische Simulation von ner pDGL , und da brauche ich denk ich nicht auf ein benutzerfreundliches Interface zu achten

-
BlackJackPB schrieb:
(und ich finde ab-erben ein durchaus verständliches Wort
)ich kenne be-erben und ver-erben. ich habe keine ahnung, was ab-erben sein soll.
Abhängige Basisklassen werden beim unqualifizierten Lookup nicht durchsucht. Also musst du qualifizierte Bezeichner oder this benutzen oder den Bezeichner explizit sichtbar machen (using). typedefs können auch nützlich sein.
-
BlackJackPB schrieb:
Hi
Hi! ^^
mehr quelltext?
template <int N, int TimeMod, class FT> class pDGL { public: FT u[N][TimeMod]; pDGL(double adx, double adt) : time(1), dx(adx), dt(adt) { // ... } // ... }; int main () { pDGL <256,3, double> test (0.18, 0.002); // ... return 0; //kannst du weglassen }geht wohl? oder kannst du SolitonSolver jz nicht mal so einfach mit nem schönen #if und #endif ausklammern? ^^
bb
-
camper schrieb:
BlackJackPB schrieb:
(und ich finde ab-erben ein durchaus verständliches Wort
)ich kenne be-erben und ver-erben. ich habe keine ahnung, was ab-erben sein soll.
Naja in diesem Fall meine ich damit einfach dass die Klasse SolitonSolver von der Klasse pDGL "abgeerbt" wird. Aber mit solchen Spitzfindigkeiten wollte ich mich eigentlich nicht rumärgern.
Abhängige Basisklassen werden beim unqualifizierten Lookup nicht durchsucht. Also musst du qualifizierte Bezeichner oder this benutzen oder den Bezeichner explizit sichtbar machen (using). typedefs können auch nützlich sein.
D.h. ich müsste jede Variable, die ich in der Basisklasse pDGL definiert habe und in der Klasse SolitonSolver benutzen möchte, in der neuen Klasse entweder mit using "bekannt" machen, oder immer pDGL<N,3,double>::var statt var schreiben, oder immer this.var statt var schreiben?! Das kanns ja find ich nicht sein; dann gehen mir ja die ganzen Vorteile der OO flöten, oder ich müsste z.B. ständig überall pDGL<N,3,double> verändern wenn ich meinetwegen floats statt doubles benutzen möchte

@unskilled:
naja die Sache ist dass pDGL ne abstrake Basisklasse ist, dann wird das leider nichts.Aber ich hab jetzt einfach mal testweise
template<int N, int SolitonCount> class SolitonSolver: public pDGL<N,3,double> { ////////<<<<<<<<<<<<durch
template<int N, int SolitonCount> class SolitonSolver: public pDGL<256,3,double> { ////////<<<<<<<<<<<<ersetzt, dann hat er ohne Probleme kompiliert... Das ist irgendwie ganz schön panne wenn man nur dadurch, dass man N "variabel" lässt, solche Probleme bekommt... Oder hab ich in Bezug auf Templates was vercheckt?
-
BlackJackPB schrieb:
Aber mit solchen Spitzfindigkeiten wollte ich mich eigentlich nicht rumärgern.
Aber du kommunizierst auch mit anderen Menschen und möchtest, dass sie dich verstehen. Also versteh das einfach als gut gemeinten Hinweis und nicht als Korinthenkackerei.
Btw - aberben steht nicht im Duden 
BlackJackPB schrieb:
D.h. ich müsste jede Variable, die ich in der Basisklasse pDGL definiert habe und in der Klasse SolitonSolver benutzen möchte, in der neuen Klasse entweder mit using "bekannt" machen, oder immer pDGL<N,3,double>::var statt var schreiben, oder immer this.var statt var schreiben?! Das kanns ja find ich nicht sein; dann gehen mir ja die ganzen Vorteile der OO flöten, oder ich müsste z.B. ständig überall pDGL<N,3,double> verändern wenn ich meinetwegen floats statt doubles benutzen möchte

Ja genau. OO-Vorteile - das kann man nun wirklich nicht sagen. Du brauchst hier halt qualifiziertes Name-Lookup.
Das liegt ganz einfach dadran, so wie ich es verstehe, dass die Basisklasse beliebig spezialisiert werden kann und somit jeder Name in der Basisklasse nur Schall und Rauch ist. Deshalb wird die Basisklasse bei unqualifiziertem Name-Lookup nicht durchsucht und du musst ein qualifiziertes Name-Lookup durchführen oder dafür sorgen, dass die Namen für unqualifiziertes NL sichtbar werden (und zwar so wie von camper beschrieben).
-
BlackJackPB schrieb:
@unskilled:
naja die Sache ist dass pDGL ne abstrake Basisklasse ist, dann wird das leider nichts.Moment, wie machst du das? eine abstrakte Klasse in C++ ist eine Klasse mit pur virtuellen Methoden. auf der anderen Seite ist pDGL ein Klassentemplate, somit sind alle Methoden nur Methodentemplates - und Methodentemplates können nicht virtuell sein, oder? Wie soll pDGL dann eine abstrakte Klasse sein? Kann natürlich sein dass das jetzt Spitzfindigkeiten sind, aber wenn man die Sprache zu "unspitzfindig" benutzt muss man damit rechnen (bzw. kann davon ausgehen) dass man falsch oder garnicht verstanden wird

bzgl. ab-erben: es gibt
- beerben: Eine Klasse beerbt ihre Basisklasse(n)
- vererben: eine Basisklasse vererbt ihre nicht-privaten Attribute und Methoden an ihre Kindklassen
- ableiten: man leitet eine (neue) Klasse von einer anderen Klasse ab, die ist dann die (eine) Basisklasse der neuen Klasse, manchmal sagt man auch dass die neue klasse sich von der Basisklasse ableitet, das kommt deinem Gebrauch von "aberben" wohl am nächsten
PS: das soll jetzt keine Klugscheißerei dir gegenüber sein, es soll dir nur die übliche Sprache in diesem Metier etwas näher bringen, so dass du Missverständnisse besser vermeiden kannst (und dadurch produktivere Antworten bekommst)

-
bzgl. ab-erben: es gibt
- beerben: Eine Klasse beerbt ihre Basisklasse(n)
- vererben: eine Basisklasse vererbt ihre nicht-privaten Attribute und Methoden an ihre Kindklassen
- ableiten: man leitet eine (neue) Klasse von einer anderen Klasse ab, die ist dann die (eine) Basisklasse der neuen Klasse, manchmal sagt man auch dass die neue klasse sich von der Basisklasse ableitet, das kommt deinem Gebrauch von "aberben" wohl am nächsten
PS: das soll jetzt keine Klugscheißerei dir gegenüber sein, es soll dir nur die übliche Sprache in diesem Metier etwas näher bringen, so dass du Missverständnisse besser vermeiden kannst (und dadurch produktivere Antworten bekommst)

Ach das hab ich schon richtig verstanden, danke

Und ich selber komme eher aus der Delphi bzw. Java-Ecke... Und da haben mich die Leute meistens verstanden, wenn ich aberben im Sinne von ableiten oder beides durcheinander benutzt habe. Aber wenn C++-Menschen bei sowas eher präzise Ausdrucksweisen gewohnt sind, werd ich mich da wohl dran gewöhnen müssen
pumuckl schrieb:
BlackJackPB schrieb:
@unskilled:
naja die Sache ist dass pDGL ne abstrake Basisklasse ist, dann wird das leider nichts.Moment, wie machst du das? eine abstrakte Klasse in C++ ist eine Klasse mit pur virtuellen Methoden. auf der anderen Seite ist pDGL ein Klassentemplate, somit sind alle Methoden nur Methodentemplates - und Methodentemplates können nicht virtuell sein, oder? Wie soll pDGL dann eine abstrakte Klasse sein? Kann natürlich sein dass das jetzt Spitzfindigkeiten sind, aber wenn man die Sprache zu "unspitzfindig" benutzt muss man damit rechnen (bzw. kann davon ausgehen) dass man falsch oder garnicht verstanden wird

Ja genau, die Basisklasse hat pur virtuelle Funktionen (in Delphi heisst das dann abstrakte Klasse, ich bin einfach mal davon ausgegangen dass das in C++ genauso ist).
Aber so wie ich Klassentemplates bisher verstanden habe, dachte ich dass das wohl möglich sein sollte; durch eine explizite Angabe von Parametern in <> hinter dem Klassennamen wird doch aus dem Klassentemplate eine spezielle Templateklasse erzeugt. Nur dass diese Templateklasse dann abstrakt ist. Oder sehe ich das falsch?
Vielleicht sollte ich mal etwas weiter ausholen was ich mit den Templateklassen vor habe.
pDGL soll Funktionalitäten zur Verfügung stellen, um partielle Differentialgleichungen der Form numerisch zu lösen. (Gleichung in Textform:
du(t)/dt = F(u(t),t)Dabei soll die Funktion F(u,t) erst durch Ableiten einer speziellen Klasse von der Basisklasse definiert/spezialisert werden. Die pDGL wird nur an N diskreten Punkten betrachtet, wobei ich N als Templateparameter gewählt habe. Viele Sachen zur Berechnung der pDGL lassen sich unabhängig von F(u,t) durchführen (Felder initialisieren, Zeitintegration durchführen etc.).
Da für jede spezielle partielle DGL aber sowohl die rechte Seite F(u,t) der Gleichung als auch die Anfangsbedingungen anders aussehen, hab ich in pDGL pur virtuelle Funktionen
virtual FT solveRightSide(int i, int j) = 0; virtual FT getInitial(int i) = 0;definiert. Wenn man jetzt meine Basisklasse benutzen will, um eine bestimme pDGL zu lösen, leitet man nur eine Klasse von pDGL ab und implementiert solveRightSide() und getInitial() und schon hat man eine Klasse, die die spezielle pDGL numerisch berechnet.
Und ich wollte jetzt halt z.B. mit dem Templateparameter N regeln, mit wie vielen diskreten Schritten die pDGL gelöst wird.
Im Prinzip war das aber auch nur ein Test um mal mit Templateparametern rumzuspielen. Ich könnte genauso gut N als Konstante definieren oder mit "normalen" dynamischen Arrays arbeiten, da ich tendenziell eh nicht mehr als eine Instanz einer von pDGL abgeleiteten Klasse haben werde. Und vor allem, wenn mir durch die Templates die OOP quasi flöten geht, werde ich denke ich eher auf Templates verzichten... Oder denkt einer von euch dass man das doch gescheit damit machen könnte? Vllt. hab ich ja auch nen völlig falschen Denkansatz.Btw. hier mal der Code den ich bisher hab, damit man mein Klassenkonzept etwas nachvollziehen kann. Ich hab jetzt SolitonSolver "qualifizierte Bezeichner" durch das "using pDGL..." erstellt (Richtig?).
Der Code wird dadurch zwar kompiliert, aber das Programm wird mit Rückhabewert 128 beendet... Hab aber auch noch nicht so genau gesucht wo da der Fehler noch sein könnte.#include <iostream> #include <fstream> #include <math.h> using namespace std; template <int N, int TimeMod, class FT> class pDGL { protected: int time; public: double dx, dt; FT x[N]; FT u[N][TimeMod]; pDGL(double adx, double adt) : time(1), dx(adx), dt(adt) { for(int i=0; i<N; i++) x[i] = (i-N/2) * dx; } virtual void doTimeStep() { for(int i=0; i<N; i++) u[i][(time+1) % TimeMod] = 2.0*dt*solveRightSide(i, time) + u[i][(time-1) % TimeMod]; time++; } virtual FT getBoundingCond(int i, int j) { //periodische RB return u[(i+N) % N][j % TimeMod]; } virtual FT solveRightSide(int i, int j) = 0; virtual FT getInitial(int i) = 0; virtual void saveTimeStep(ofstream& fs) { for(int i=0; i<N; i++) fs << i << " " << x[i] << " " << u[i][time % TimeMod] << endl; } protected: virtual FT getu(int i, int j) { if((i<0) || (i>=N)) return getBoundingCond(i, j); else return u[i][j % TimeMod]; } }; template<int N, int SolitonCount> class SolitonSolver: public pDGL<N,3,double> { public: using pDGL<N,3,double>::u; using pDGL<N,3,double>::dx; using pDGL<N,3,double>::getu; SolitonSolver(double adx, double adt) : pDGL<N,3,double>(adx, adt) { for(int i=0; i<N; i++) { u[0][i] = getInitial(i); for(int j=1; j<N; j++) u[j][i] = u[0][i] ; } } virtual double getInitial(int i) { return -SolitonCount * (SolitonCount+1) * sech2((i-N/2)*dx); } virtual double solveRightSide(int i, int j) { //return 6 * u * // * du/dx // - d3u/dx3 double um = (getu(i+1,j) + getu(i,j) + getu(i-1,j)) / 3.0; double dudx = (getu(i+1,j) - getu(i-1,j)) / (2.0*dx); double d3udx3 = (getu(i+2,j) - 2.0*getu(i+1,j) + 2.0*getu(i-1,j) - getu(i-2,j)) / (2.0*dx*dx*dx); return 6.0 * um * dudx - d3udx3; } private: double sech2(double x) { return 1/(cosh(x)*cosh(x)); } }; int main () { SolitonSolver<256,3> Sol(0.18,0.002); for(int i=0; i<150; i++) { Sol.doTimeStep(); } ofstream f("out.txt"); Sol.saveTimeStep(f); f.close(); cout << "Ready\n"; return 0; }edit: hmm scheinbar kann LaTeX-Code nicht angezeigt werden... also mit d u(t)/dt ist die partielle Ableitung von u(t) nach t gemeint.
-
bump
-
wie schon oben angedeutet gehen templates und virtuelle Funktionen nicht zusammen. Dein Lösungsansatz ist also leider nicht umsetzbar.
Aber: soweit ich das sehen kann hast du nicht vor, deine Lösungsklassen zur laufzeit polymorph zu verwenden, es reicht also Compiletime-Polymorphie aus.
Dazu kann man das CRTP* nutzen: statt eine spezielle Klasse von deinem DGL-solver abzuleiten und dort die Eigenschaften der DGL zu definieren, machst du es genau anders herum. übergebe deinem DGL-Solver einen zusätzlichen Template-Parameter, der die Eigenschaften der DGL definiert. Dein solver-template erbt dann privat von der DGL-Klasse und kann auf deren solveRightSide() methode und andere zugreifen. Die DGL-Klassen müssen nichtmal ne gemeinsame Basisklasse haben, die einzige Bedingung ist, dass sie die benötigten Methoden implementieren._______________________________
*Curiously Recurring Template Pattern