Template probleme
-
so ähnlich.
Hab an so was gedacht:template <class Eigenschaft1, class Eigenschaft2> Unterklasse1:Basis { ... Eigenschaft1 e1; Eigenschaft2 e2; };ja durch die Parameter soll ein anders Verhalten erzeugt werden. Hierführ sollen unterschiedliche Klassen exesterien, die dieses über eine vordefinierte Schnitstelle erzeugen sollen.
Um eine benutzerfreundliche Schnitstelle zu erhalten und die Klassen gut zu Kapseln habe ich an eine Klasse gedacht die mir die entsprechende Klasse zusammenbastelt (ist glaub eine factory Klasse). Wie die Klasse aussehen soll, sollte durch die 3 Parameterfestgelegt werden
Da kannst du entweder verschiedene Klassen mit gleicher Schnittstelle als Template-Argumente übergeben
Dies ist ja das was ich erreichen will aber nicht hinbekomme
Basis* Erzeuger::getClass(string Klassentyp, string Eigenschaft1, string Eigenschaft2) { //hier soll die Eigenschaftsklassen bestimmt werden und das ist mein Problem //sucht die Abgeleitete Klasse und gibt diese zurück return new Unterklasse1<Eigenschaftsklasse1,Eigenschaftsklasse2>; } //im code Erzeuger erzeuger; Basis* test = erzeuger.getClass("Unterklasse1","Eigenschaft1","Eigenschaft2");vll wirds jetzt klar. Bei Vorschläge für ein anderes Design nur her damit.
-
ich denk das ich das über Polymorphielösen werde
indem ich entsprechende Klassen im ctor übergeben werde und mir die Laufzeitpolymorphie zunutzen mach, wobei mich das mit den Templates interressieren würde wie das geht.
-
In Modern C++ Design von Andrei Alexandrescu war glaub ich ein ähnliches Problem mit Lösung beschrieb. Leider hab ich das Buch zurzeit nicht mehr. Wenn es jemand hat kann er vll mal nachschaun ober er sowas in der Art findet.
Würd mich wirklich interressieren.
Noch ne frage wie stark ist der Performance verlust bei Laufzeitpolymorthie? Kann man das sagen bzw. welche größen spielen hier eine Rolle. Zwar kommt es in dieser Anwendung nicht unbeding auf Performance an aber es interressiert mich halt.
-
123 schrieb:
Dies ist ja das was ich erreichen will aber nicht hinbekomme
So wie ich das sehe, brauchst du den ersten Template-Parameter, um eine neue Klasse zu erstellen und eindeutig zu identifizieren. Das ist aber unnötig, die Klasse ist schon durch die anderen Parameter genau definiert.
Ich hatte ungefähr sowas im Sinn:
template <class Eigenschaft1, class Eigenschaft2> class Klasse { Eigenschaft1 a; Eigenschaft2 b; void FunktionX() { a.TueDas(); a.TueDies(); b.TueDas(); } void FunktionY() { b.TueNichts(); b.BeginneEtwasZuTun(); } };Wie du siehst, müssen die Klassen, die für die Template-Parameter
Eigenschaft1undEigenschaft2eine Schnittstelle erfüllen.Eigenschaft1erfordert die MethodenTueDas()undTueDies(), der TypEigenschaft2muss die MemberfunktionenTueDas(),TueNichts()undBeginneEtwasZuTun()bereitstellen.Demzufolge kannst du alle Typen übergeben, die diese Anforderungen erfüllen und so deine Klassen leicht auswechseln.
-
Nexus danke für deine Bemühungen, aber
ich glaub wier werden gerade aneinander vorbei.
Bei mir ist nicht das Problem die Klasse, die ich erstellen will
und wie ich die Templates einsetzen muss
das Problem liegt in der Erzeugerklasse, die aus den Parametern die Klasse zusammen basteln soll.
Dies ist mein Ziel:... Erzeuger erzeuger; Basis* test = erzeuger.getClass("Unterklasse1","Eigenschaft1","Eigenschaft2"); //die zu erzeugende Klasse soll so aussehen //Unterklasse1<Eigenschaft1,Eigenschaft2> Basis* test1 = erzeuger.getClass("Unterklasse2","Eigenschaft1","Eigenschaft2"); //die zu erzeugende Klasse soll so aussehen //Unterklasse2<Eigenschaft1,Eigenschaft2> ...Der erste Parameter ist genauso Wichtig wie die andern beiden Parameter, da dieser die entsprechende Unterklasse ausgewählt wird.
Demzufolge kannst du alle Typen übergeben, die diese Anforderungen erfüllen und so deine Klassen leicht auswechseln.
Ich will die Typen "übergeben lasse", also von der Erzeuger Klasse
ich will sowas verhindernBasis* Erzeuger::getClass(string Klassentyp, string Eigenschaft1, string Eigenschaft2) { if(Klassentyp=="Unterklasse1") { if(Eigenschaft1=="Eigenschaft1") { if(Eigenschaft2=="Eigenschaft2") { return new Unterklasse1<Eigenschaftsklasse1,Eigenschaftsklasse2>; } if(Eigenschaft2=="Eigenschaft2X") { return new Unterklasse1<Eigenschaftsklasse1,Eigenschaftsklasse2X>; } } if(Eigenschaft1=="Eigenschaft1X") { if(Eigenschaft2=="Eigenschaft2") { return new Unterklasse1<Eigenschaftsklasse1X,Eigenschaftsklasse2>; } if(Eigenschaft2=="Eigenschaft2X") { return new Unterklasse1<Eigenschaftsklasse1X,Eigenschaftsklasse2X>; } } }Wie man sehen kann ist hier sehr viel Coderedundanz enthalten, macht dies Unwartbar bei allein einer Unterklasse und zu jedem Template eine auswahl von zwie verschieden Argumenten
Es geht also nicht um die von dier vorgestellte Klasse. Diese stelt für mich so kein Problem da
-
Sorry, aber ich glaube, jetzt habe ich es ein wenig besser verstanden. Du hast ja vorhin Folgendes geschrieben:
123 schrieb:
@Nexus die klassen könne ja schon zur laufzeit fertig sein, also zur kompalierungszeit kann schon feststehen wie die klasse zusammen gesetzt ist.
Wie sieht das nun aus? Sind die Typen zur Kompilierzeit bekannt? Falls ja, kannst du das nicht über Strings machen, sondern musst konstante Ausdrücke wie
enums verwenden. Dann stellt sich allerdings wieder die Frage, wieso überhaupt ein Mapping notwendig ist und nicht gleich der richtige Typ eingesetzt werden kann (indem mangetClass()zu einem Funktionstemplate macht).Ansonsten muss man eine völlig andere - und wohl eher unflexible - Herangehensweise wählen. Das Problem ist, dass man keine Typen zur Laufzeit speichern kann. Wenn du den Typ also nicht zur Kompilierzeit weisst, musst du eine Fallunterscheidung mit
ifmachen (oder evtl.switch). Mir fallen im Moment nur gerade Makros ein, die die Codeduplizierung verringern könnten.
-
Hier eine Methode zur Laufzeit, zwar auch mit Templates, die aber nicht vom String direkt abhängen. Am besten, du versuchst, das Ganze von unten her nachzuvollziehen.
template <typename TX, typename TY, typename TZ> Basis* MapType() { return new Klasse<TX, TY, TZ>(); } template <typename TX, typename TY> Basis* MapType(const std::string& StringZ) { if (StringZ == "schnelles Z") { return MapType<TX, TY, SchnellZ>(); } else if (StringZ == "langsames Z") { return MapType<TX, TY, LangsamZ>(); } } template <typename TX> Basis* MapType(const std::string& StringY, const std::string& StringZ) { if (StringY == "rotes Y") { return MapType<TX, RotY>(StringZ); } else if (StringY == "blaues Y") { return MapType<TX, BlauY>(StringZ); } else if (StringY == "gelbes Y") { return MapType<TX, GelbY>(StringZ); } } Basis* MapType(const std::string& StringX, const std::string& StringY, const std::string& StringZ) { if (StringX == "einfaches X") { return MapType<EinfachX>(StringY, StringZ); } else if (StringX == "schwieriges X") { return MapType<SchwierigX>(StringY, StringZ); } }Das Problem momentan ist, dass du immer noch relativ viel ändern musst, wenn eine vierte Klasse (neben X, Y und Z) dazukommt. Mit Präprozessormagie könnte man sicher noch einige Dinge flexibler machen. Aber mit meinem oberen Code hast du wenigstens jede Abfrage nur einmal.
-
leider auch nicht ganz das was ich suche.
denk ich muss das über die Pholymorthie machen
und es zur laufzeit entscheiden,
dann muss der ctor halt zwei Zeiger übernehmen, für jede eigenschaft einen,
das sollte dann funktionieren.
-
123 schrieb:
leider auch nicht ganz das was ich suche.
denk ich muss das über die Pholymorthie machen
und es zur laufzeit entscheiden,
dann muss der ctor halt zwei Zeiger übernehmen, für jede eigenschaft einen,
das sollte dann funktionieren.Dann bist du aber in etwa dort, was ich bereits vorgeschlagen habe, nicht?
-
naja so ähnlich.
Die strings werden in der erzeuger klasse zu der entsprechenden Klasse aufgelöst.
Die übergeb ich dann dem Konstruktor
spricht das was ich über templates zur kompiler zeit machen wollte mach ich jetzt mit Polymorthie zur laufzeit
ich versuchs jetzt mal umzusetzen und wenns tut kann ich ja mal postenhab mir deins noch mal angeschaut.
Erfüllt zwar doch die aufgabe die ich lösen wollte, bloß schaut das, naja
nicht so übersichtlich aus. Ich muss dann halt mit der Laufzeitpolyorthie leben.
Dafür sollte der Quellcode lesbarer sein und einen geringeren overhead sollte dies auch erzeugen wobei ich mir hier nicht sicher bin.
Bei der Template Methode wird dann doch zur Kompailerzeit jede denkbare klasse die sich ergeben könnte erstelt also jede kombination?aber noch mals danke
auf die Lösung wär ich von alleine glaub nicht gekommen (Template)
-
Ich weiss jetzt nicht genau, welche Lösung du meinst, aber ja templates erzeugen mehr Code, allerdings ohne Nachteile zur Laufzeit. Die Laufzeitpolymorphie ist wessentlich flexibler, jedoch hat es Nachteile in der Geschwindigkeit zur Laufzeit. (jedoch sollten diese Aspekte vernachlässigt werden und eher auf das Problem, welches du lösen willst ausgerichtet sein).
Bei der Template Methode wird dann doch zur Kompailerzeit jede denkbare klasse die sich ergeben könnte erstelt also jede kombination?
Wenn nötig ja.
-
hab mir jetzt sowas vorgestellt
Basis { virtual void doSomething(); //... } Unterklasse1:Basis { //... Unterklasse1(Eigenschaft1*,Eigenschaft2*); void doSomething(); //... Eigenschaft1* e1; Eigenschaft2* e2; } Baisi* Erzeuger::getClass(string Klasse,sting eigenschaft1, string eigenschaft2) { Eigenschaft1* e1=NULL; Eigenschaft1* e2=NULL; //... else if(eigenschaft1=="Eigenschaft1X") e1=new Eigenschaft1X; //... else if (eigenschaft2=="Eigenschaft2X") e2=new Eigenschaft2X; //... else if (Klasse=="UnterKlasse1") return Unterklasse1(e1,e2); //... } //Eigenschaften1X ist von Eigenschaften1 abgeleitetDas was ich hier jetzt über die Polymorthie gemacht hab war am anfang mein ziel durch Tamplets zu machen.
-
123 schrieb:
leider auch nicht ganz das was ich suche.
denk ich muss das über die Pholymorthie machenIch habe ja extra gesagt, dass mein Code zur Laufzeit funktioniert. Die Funktionstemplates dienen nur zur Verhinderung der Codeduplizierung.
Wo liegt also das Problem?
-
nirgends

ich implementier beide Möglichkeiten mal und untersuch dan mal das Laufzeitverhalten (Geschwindigkeit etc.) und Größe, wobei größe heute weniger das Problem ist.
Kennst du einen guten Profiler auser CodeAnalyst von AMD der auch gut auf Intel Prozesoren funktioniert. Sollte aber kostenlos sein