Templates und CAST Überladung



  • Hallo,

    ich bin noch recht neu in C++ und lerne es gerade im Informatik Studium.
    Ich versuche gerade eine Template Klasse in einer anderen Funktion in zwei Datentypen zu kasten, dazu ist der eine Datentyp double und der andere das Template.

    Habe einen kleinen Beispielscode aufgebaut, der wie folgt aussieht:

    #include <cstdlib>
    #include <iostream>
    #include <string>
    
    using namespace std;
    
    template <typename T>
    class Test
    {
    private:
    	T val;
    public:
    	Test(T val){
    		this->val = val;
    	}
    
    	operator double(){
    		return 5.0;
    	}
    
    	operator T(){
    		return this->val;
    	}
    };
    
    template <typename T>
    class Tst
    {
    public:
    	template <typename C>
    	void printVal(Test<T> *v){
    		cout << (C)*v << endl; //EDIT: War vorher cout << (C)v << endl;
    	}
    
    	void print(Test<T> *v){
    		this->printVal<double>(v);
    		this->printVal<T>(v);
    	}
    };
    
    int main()
    {
    	Test<string> *t = new Test<string>("Hello World!");
    	Tst<string> *t2 = new Tst<string>();
    
    	t2->print(t);
    
    	system("PAUSE");
    	return EXIT_SUCCESS;
    }
    

    Von VS selbst bekomme ich keinen Fehler, erst beim kompilieren sagt der Kompiler:

    Fehler 1 error C2440: 'Typumwandlung': 'Test<T> *' kann nicht in 'double' konvertiert werden c:\users\viktor\documents\visual studio 2012\projects\ooap2.2\ooap2.2\main.cpp 34 1 OOAP2.2

    Was mache ich falsch? 😮



  • ViktorM schrieb:

    Was mache ich falsch? 😮

    Du kannst Zeiger und das, worauf sie zeigen, nicht auseinanderhalten.

    Darauf gibt es zwei mögliche Antworten, je nach Philosophie. Die erste ist: Benutze einfach keine Zeiger. Das ist in deinem Fall auch weder nötig noch sinnvoll. Die zweite ist: Lerne erstmal einfache Sachen wie Zeiger, bevor du dich mit kompliziertem Kram wie Templates auseinandersetzt. Such dir eine aus.



  • Haha danke für die coole Antwort 😃

    Zeiger haben wir im ersten Semester gelernt und ich kann sie sehr wohl schon anwenden, habe nur noch nicht viel Übung darin. Mit deinem Hinweis ;), habe ich meinen Fehler aber gefunden:

    template <typename C>
    	void printVal(Test<T> *v){
    		cout << (C)*v << endl;
    	}
    


  • Und damit hälst du dir nur die Augen zu, damit du den (oder die) Fehler nicht sehen musst.

    Und dem Compiler setzt du einen Knebel auf...



  • Welche Fehler denn?

    Wieso seid ihr eigentlich so komisch drauf? Habe doch nur eine Frage gestellt, wenn ihr nicht helfen wollt, dann schreibt am besten einfach gar nichts.



  • ViktorM schrieb:

    Wieso seid ihr eigentlich so komisch drauf? Habe doch nur eine Frage gestellt, wenn ihr nicht helfen wollt, dann schreibt am besten einfach gar nichts.

    Skym0sh0 hat ja geholfen. Um seine Analogie noch deutlicher zu machen: Mit dem C-Cast löst du keine Probleme, sondern bringst höchstens den Compiler zum Schweigen und umgehst Typsicherheit. Du solltest dir lieber überlegen, was du genau tun willst.



  • Der hat einen operator double geschrieben, das Problem war, dass der nicht aufgerufen wurde, weil er einen Pointer hatte und kein Objekt.



  • Verstehe noch nicht ganz, wieso wird da die Typsicherheit verletzt?



  • ViktorM schrieb:

    Verstehe noch nicht ganz, wieso wird da die Typsicherheit verletzt?

    Nirgendwo (außer aus designtechnischen Gründen wegen impliziter Konvertierung und so).
    Nexus und Skymosho dachten, du castest einfach einen Pointer nach double.



  • Da hatten sie auch recht im ersten Eintrag, habe aber gemerkt, dass ich da den * Operator vergessen habe. Also mir fällt auf Anhieb nur ein, dass es dann zu Problemen kommt, wenn die Template Methode (printVal) nur dann gefährlich (schlecht) ist, wenn sie public oder protected ist (sprich, wenn andere Programmierer darauf zugreifen können) aber solange sie private ist, kann darauf sonst keiner zugreifen und der der dann an der Klasse arbeitet muss sich eben daran halten, das außer double und T keine anderen Datentypen da übergeben werden dürfen.

    Habe das im eigentlichen Projekt so umgesetzt und mir eine Kopie der Funktion eben nur für den anderen Datentyp erspart.



  • Nathan schrieb:

    Nexus und Skymosho dachten, du castest einfach einen Pointer nach double.

    Ich glaube nicht, dass das direkt geht, aber C-Casts in generischem Code sind gefährlich. ⚠

    Zumindest solange man die einzelnen Semantiken nicht genaustens kennt, würde ich empfehlen, static_cast einzusetzen. Ich persönlich würde auch nachher auf C- und Function-Style-Casts verzichten. Aber einige Leute beklagen sich dann über zusätzliche Schreibarbeit.



  • Nexus schrieb:

    Nathan schrieb:

    Nexus und Skymosho dachten, du castest einfach einen Pointer nach double.

    ....

    Ok, mein Fehler.
    Ziehe alles zurück, behaupte das Gegenteil und du hast natürlich Recht mit deinen Bedenken.



  • Ehh verstehe ich gerade nicht 😃

    Warum sind die gefährlich? Können damit schnell Sicherheitslücken entstehen?
    Und was bedeutet C-Casts?



  • // C-Cast
    (T) expr
    
    // Function Style Cast (T skalarer Typ)
    T(expr)
    
    // C++-Casts
    static_cast<T>(expr)
    const_cast<T>(expr)
    reinterpret_cast<T>(expr)
    dynamic_cast<T>(expr)
    

    Bei den C++-Castoperatoren ist die Funktionalität aufgeteilt. Du weisst also genau, welche Art von Konvertierung für jeden Operator in Frage kommt, und erkennst diese anhand des Codes. Bei C- und Function-Style-Cast versucht der Compiler, einen oder mehr der ersten drei C++-Äquivalente anzuwenden. Du kannst dadurch sehr schnell ungewollte Konvertierungen haben, besonders in generischem Code.



  • ViktorM schrieb:

    und der der dann an der Klasse arbeitet muss sich eben daran halten, das außer double und T keine anderen Datentypen da übergeben werden dürfen.

    Und da drin siehst du kein Problem? Wenn du den Code in 2 Wochen nochmal benutzen willst hast du es vergessen und übergibst was anderes. Und weil du einen Cast benutzt warnt dich der Compiler nicht, sondern macht den Schwachsinn auch noch den du geschrieben hast. Man kann in C++ einfach hinschreiben, dass man nur double und T übergeben darf und dann hilft der Compiler dir korrekten Code zu schreiben.
    Die Doku, die du nicht geschrieben hast, liest eh keiner™.


Anmelden zum Antworten