Virtual template...
-
'void AbstractClass:use(TClass<T> & var)': Vorlagen der Memberfunktion können nicht virtuell sein
Ich hab eine Klasse "Familie", die is Abstrakt, diese Familie hat eine Methode use, aber bei der Klasse Familie macht dies keinen Sinn, weil Familie use nicht mit inhalt füllen kann. Use ist pure virtual, weil das Programm ein Array voller Familie Objekte hat, Vater, Mutter usw und packt die in einen Familie Pointer und ruft use() auf, dies Klasse, weil es virtual ist.
Nun muss ich use aber mit einem Parameter aufrufen der variiert. Ich habe eine Container Klasse hier TClass, die hat eine T var und ein bisschen drum herum, also zusätzlichen Methoden und Attribute.
Das eigentliche Ziel ist es einem Familien Pointer mit use diese TClass instanz zu übergeben, so dass die jeweiligen Implementationen diese verarbeiten.
(Wie diese Klasse erkennen ob T int, string usw ist, ist irrelevant, dass klappt und wird auch alles gebraucht)
So wie es aussieht, muss ich eventuell T in String ändern und falls man einen Int braucht, dann nutzt man halt atoi oder so, ist sehr schlecht, wie ich finde.
-
Da steht der Compiler genau vor dem Problem, das ich oben schon erwähnt habe: er hat die Instanziierung (Aufruf) und Implmenentierung (Methodenrumpf) nicht an einer Stelle - und im Gegensatz zu "normalen" Templates auch keine Möglichkeit, beides miteinander in Verbindung zu setzen. Da bleibt dir wohl nichts anderes übrig als dich auch einige Grundtypen einzuschränken und deine use()-Methode für diese Typen zu überschreiben.
(was für Daten willst du eigentlich an use() übergeben?)
-
Sind verschiedene Objekte, int[], string[], floats[],das gleiche auch ohne Arrays eventuel, das wird wohl alles sein.
Muss gucken, ob ich überladungen machen, aber mit Überladungen hab ich das Problem, dass ich use 3 mal implementieren muss, wobei use ne Menge arbeit machen soll, eigentlich nahe zu die ganze Arbeit und da kann ich auch nicht so gut den Inhalt verpacken, in eine dritte Methode, weil ich ja den Wert noch brauche und der kann mal wieder int[], string[] oder float[] sein
-
Evtl. könntest du auch die Klasse TClass<T> von einer gemeinsamen Basisklasse erben lassen und diese dann bei use angeben:
class TBaseClass { }; template<typename T> class TClass : public TBaseClass { }; class AbstracClass { virtual void use(const TBaseClass &var) = 0; };
Dies funktioniert natürlich nur, wenn innerhalb der Methode use() nicht explizit auf die Template-Variable T zugegriffen wird.
Am besten du zeigst mal, wie deine Beispiel use-Methode aussehen soll?
Wie viele verschiedene (konkrete) Datentypen hast du denn (evtl. reicht ja std::string und int)?
-
Und was willst du mit diesen Typen jeweils machen? (alleinstehende int und float sind sich ähnlich genug, um notfalls von einer Funktion geschluckt zu werden; Array-Verarbeitung kannst du in einer nichtvirtuellen Template-Funktion weiterdelegieren - bleiben nur noch zwei virtuelle Funktionen für Zahlen und Strings:
virtual void use(const string& data) = 0; virtual void use(double data) = 0; template<typename T> void use(T* array,size_t len) { for(int i=0;i<len;++i) use(array[i]); }
-
Seikilos schrieb:
...
Ich tippe eher auf ein falsches Design. Was soll das eigentlich bringen?
Entweder du willst Polymorph arbeiten, dann müssen deine Objekte die gleiche Schnittstelle haben oder du greifst eh auf die konkrete Schnittstelle zu, dann brauchst du aber auch nicht solche Klimmzüge.Wenn du den Unterobjekten allesamt gänzlich andere Parameter übergeben willst, muss ich davon ausgehen das zum Zeitpunkt der Übergabe dein konkretes Objekt bekannt ist, sonst macht die Übergabe ja eh keinen Sinn. Vielleicht ist in deinen Fall ein anderes Konzept besser geeignet...
Aber ohne ein konkreteres Beispiel könnte ich nur grob ins blaue raten (ja, ich habe einen Verdacht, aber nein, ohne das ich mir sicher bin schreibe ich hier jetzt keinen Roman hin).
cu André
-
Was meinst du mit nicht explizit auf T zugreifen? Ich brauch schon in use konkret den inhalt, wenns ein T var[] wäre, hol ich mir die Werte dann zb nach int = var[0], meinst du dies mit auf T zugreifen?
Zu dem Rest, in use soll sich anhand der Klasse des T Typen entscheiden ob es Int oder String ist, oder sonst was und abhängig von internen zuständen werden dann andere Methoden aufgerufen.
Explizit gibts use noch nicht, nur in der Theorie, macht ja kein sinn das zu implementieren, wenn es eh nicht geht
Überladung wäre schlecht, weil ich dann mal hier mal da Methoden aufrufe habe, das ist so, als würd ich ein großes switch in mehrere Methoden auf teilen (auch wenn switch hier nicht geht
)
-
Seikilos schrieb:
Überladung wäre schlecht, weil ich dann mal hier mal da Methoden aufrufe habe, das ist so, als würd ich ein großes switch in mehrere Methoden auf teilen (auch wenn switch hier nicht geht
)
Wieso wäre das schlecht - der Compiler wählt doch je nach Bedarf genau die Methode auf, die er in der aktuellen Situation benötigt.
-
@asc, ich hab einen Event generator, wenn etwas passiert, soll die ganze Familie davon erfahren, der Event generator könnte Zahlen[] generieren, oder nur einen String, alles mögliche an Events. N beispiel was mir einfallen würde, ist wenn der Event generator ein Eingabefeld ist und abhängig was man dort eingibt, wird dies an die Familie gesendet, die muss dann aber damit klarkommen.
Edit: CStoll, naja int, int[] usw und ich hab 6 Überladungen, und diese Switch ding ist eine sinngruppe, aufgeteilt auf irrelevante dinge wie mal int mal float bröselt das Layout auseinander
-
Seikilos schrieb:
@asc, ich hab einen Event generator, wenn etwas passiert, soll die ganze Familie davon erfahren, der Event generator könnte Zahlen[] generieren, oder nur einen String, alles mögliche an Events. N beispiel was mir einfallen würde, ist wenn der Event generator ein Eingabefeld ist und abhängig was man dort eingibt, wird dies an die Familie gesendet, die muss dann aber damit klarkommen.
Und wie sehen die Reaktionen eines Familienmitglieds auf einen String oder ein int-Array typischerweise aus? Da dürfte es schon schwierig werden, das in einen einheitlichen Code-Block (aka Template) zu pressen.
-
Die TClass transportiert mehr als nur die T var, auch ein paar Indikatoren, enum, int wert irgendwas, an dem man unterscheiden kann, was es für ein Wert in der T var erwarten darf und dem gemäß packt man den Inhalt in ein int, string oder sonstiges und ruft evtl eine Methode mit dem int, mit dem String oder float als Parameter auf, oder tut nichts, weil der Wert nicht zu gebrauchen ist usw.
-
Da könnte4st du ja der TClass eine (abstrakte, aber template-freie) Basisklasse geben, die du dann auch an deine Familienmitglieder weitergibst.
(Aber ehrlich: So ganz klar ist mir weder dein Design noch der Sinn dahinter)
-
Müssen diese dann in die Template Klasse casten? Sonst kommen die ja nicht an die T var ran?
Was mir noch auffällt, ich glaub mein Problem ähnelt einer Gui, wenn ich in einer Gui einen Namen, einen Button usw drücken, so kann die Gui der Logik ja immer die passende Methode aufrufen, wie rufeA, rufeB usw, das erzeugt aber in der Logik dutzende minimaler Methoden auf, wenn die Logik aber eine Methode guiAntwort(); hat, so ruft die GUI nur diese Methode der Logik auf und übergibt dort entweder den String, oder das Alter als int oder weiß der geier was weiter, so hat man nur eine Methode und kann dort die trivialen Tätigkeiten sammeln.
Genau das hab ich vor, nur hat es nichts mit ner GUI zutun, aber das Prinzip is ähnlich. Und mit GUI m ruft Logik mein ich nicht, wenn der Button gedrückt wurde, darum kümmert sich die GUI, ich meine die events die von der GUI ausgehen werden an die Logik gesendet.
-
Seikilos schrieb:
Müssen diese dann in die Template Klasse casten? Sonst kommen die ja nicht an die T var ran?
Entweder das, oder sie überlassen die tatsächliche Verarbeitung der Klasse selber.
Was mir noch auffällt, ich glaub mein Problem ähnelt einer Gui, wenn ich in einer Gui einen Namen, einen Button usw drücken, so kann die Gui der Logik ja immer die passende Methode aufrufen, wie rufeA, rufeB usw, das erzeugt aber in der Logik dutzende minimaler Methoden auf, wenn die Logik aber eine Methode guiAntwort(); hat, so ruft die GUI nur diese Methode der Logik auf und übergibt dort entweder den String, oder das Alter als int oder weiß der geier was weiter, so hat man nur eine Methode und kann dort die trivialen Tätigkeiten sammeln.
Wenn ich mir die MFC Library ansehe, läuft das auch so ungefähr ab - man bekommt in erster Linie CWnd-Zeiger und muß dann entweder in den richtigen Typ casten oder die virtuellen Methoden der CWnd Klasse verwenden.