Innere Klasse wird bei Templatedeklaration nicht als Typ erkannt



  • Dravere schrieb:

    Nexus schrieb:

    Natürlich nicht. static_cast ist meistens legitim. reinterpret_cast ist manchmal halt nötig. const_cast sollte man möglichst vermeiden, und dynamic_cast ist zwar teilweise praktisch, wird aber von vielen als Designfehler angesehen.

    Da muss ich dir widersprechen Nexus. Bei jeglichem Cast sollte man darauf achten, ob da wirklich alles korrekt abläuft. Ich brauche seit Ewigkeiten keine Casts mehr, erst recht auch wegen dem Einsatz von Templates.
    Bei vielem ist es möglich ohne Casts klar zu kommen, man sollte sie wirklich nur äusserst selten verwenden und immer wenn man sie verwendet, sich überlegen, ob das nicht auch ohne gehen könnte.

    Es ist vielleicht schon tendenziell so, dass man weniger Casts braucht, wenn man bereits länger programmiert. Zum Beispiel, weil static_cast hauptsächlich mit elementaren Typen verwendet wird, und man mit höherer Abstraktionsebene vielleicht weniger "direkt" programmiert.

    So pauschal würde ich dennoch nicht behaupten, es sei nur gut, so wenig Casts wie möglich zu verwenden. Es gibt einige Fälle, bei denen ich Casts einsetze.

    Nur mal ein Anfänger-Beispiel:

    double e = 3.25f;
    double f = 2.67f;
    
    float i = (e + f)/2;                     // (1)
    float j = static_cast<float>(e + f)/2.f; // (2)
    

    Der Cast wäre nicht unbedingt nötig. Trotzdem würde ich ihn an dieser Stelle schreiben, da ich erstens gerade sehe, dass von double zu float umgewandelt wird und zweitens die Warnung beseitige.

    Bei dynamic_cast habe ich eine ähnliche Meinung. Manchmal ist es eben recht praktisch, und für mich gibts da schlimmere Designfehler (was ist denn daran überhaupt so schlimm?). Ein Vermeiden des dynamic_cast s führt manchmal dazu, dass das gesamte Design geändert werden muss (ja, du wirst jetzt sagen, dass das Design schon von Anfang an schlecht war ;)).

    Man hat z.B. eine Basisklasse Base , und mehrere davon abgeleitete Klassen, darunter Derived .

    Base* Ptr;
    // ...
    Ptr = new Derived();
    Ptr->FunctionWhichOnlyExistsInDerived();                         // geht nicht.
    dynamic_cast<Derived*>(Ptr)->FunctionWhichOnlyExistsInDerived(); // geht.
    

    Wie macht man das sonst? Ich kann mir nur noch vorstellen, eine virtuelle Funktion zu schreiben, die dann innerhalb der Klasse die richtigen Funktionen aufruft. Aber das ist auch nicht immer erwünscht, manchmal will man von aussen je nach Klasse unterschiedlich zugreifen. Ist das bereits zwingend schlechtes Design?

    Bei const_cast teile ich deine Meinung uneingeschränkt, den habe ich eigentlich noch nie eingesetzt. reinterpret_cast kommt auch recht selten vor, und dann eher zu Testzwecken. Und es gehört für mich auch dazu, zu überprüfen, ob alles korrekt läuft, wenn ich caste.



  • Nexus schrieb:

    [...](was ist denn daran überhaupt so schlimm?)[...]

    Grundsätzlich kann man das schon machen, aber:
    Der Designbruch besteht darin, dass man damit die IsA-Beziehung aufbricht. Wenn Du ein abgeleitetes Objekt einem Basisklassenzeiger/Referenz zuweist, dann willst Du eigentlich damit sagen: An dieser Stelle will ich nur die Eigenschaften haben, welche die Basisklasse hat. Wenn Du nun das Basisklassenobjekt wieder hochcastest, dann bist Du eigentlich an einer Stelle, wo es besser gewesen wäre, gleich ein abgeleitetes Objekt zu haben, und nicht über ein Basisklassenobjekt zu gehen.



  • Tachyon schrieb:

    ...

    Exakt. Und das impiliziert ja, dass er zur Laufzeit bereits wissen muss, welches/e Objekte da in Frage kommen können. Das heisst, dass er vorher eine Typabfrage (in welcher Form auch immer) machen muss. Was ja schlussendlich (vom Prinzip her) auf das void gecaste zurückführt. 😉



  • Tachyon schrieb:

    Wenn Du nun das Basisklassenobjekt wieder hochcastest, dann bist Du eigentlich an einer Stelle, wo es besser gewesen wäre, gleich ein abgeleitetes Objekt zu haben, und nicht über ein Basisklassenobjekt zu gehen.

    Ja, aber manchmal hat man einen Basisklassenzeiger, um damit mehrere abgeleitete Klassen ansprechen zu können. Und wenn sich die einzelnen Klassen nicht nur in den Definitionen der virtuellen Funktionen unterscheiden, sondern beispielsweise noch weitere, spezifische Funktionen haben, möchte man vielleicht je nach Fall anders auf die Klasse reagieren. Und die spezifischen Eigenschaften einer Klasse kann man von aussen nur mit dynamic_cast modifizieren (man hat nur einen Basisklassenzeiger).



  • Nexus schrieb:

    Tachyon schrieb:

    Wenn Du nun das Basisklassenobjekt wieder hochcastest, dann bist Du eigentlich an einer Stelle, wo es besser gewesen wäre, gleich ein abgeleitetes Objekt zu haben, und nicht über ein Basisklassenobjekt zu gehen.

    Ja, aber manchmal hat man einen Basisklassenzeiger, um damit mehrere abgeleitete Klassen ansprechen zu können. Und wenn sich die einzelnen Klassen nicht nur in den Definitionen der virtuellen Funktionen unterscheiden, sondern beispielsweise noch weitere, spezifische Funktionen haben, möchte man vielleicht je nach Fall anders auf die Klasse reagieren. Und die spezifischen Eigenschaften einer Klasse kann man von aussen nur mit dynamic_cast modifizieren (man hat nur einen Basisklassenzeiger).

    Das bringt nichts. Wie drakon schon sagte, musst Du eh wissen, welches abgeleitete Objekt Du ansprechen willst. Sowas führt meist zu Funktionen in denen dann über irgendwelche Typabfragen das richtige Objekt zurechgecastet wird, und das ist nicht gerade sehr sauber. Da macht es mehr Sinn, z.B. überladene Funktionen für die verschiedenen in Frage kommenden Klassen zu machen, die die Spezialfunktionen darin aufzurufen.



  • drakon schrieb:

    Exakt. Und das impiliziert ja, dass er zur Laufzeit bereits wissen muss, welches/e Objekte da in Frage kommen können. Das heisst, dass er vorher eine Typabfrage (in welcher Form auch immer) machen muss. Was ja schlussendlich (vom Prinzip her) auf das void gecaste zurückführt. 😉

    Stimmt, da hast du Recht. Wahrscheinlich wird mein Beispiel eh auf eine hässliche Fallunterscheidung hinauslaufen.

    Was aber, wenn man von aussen (von mir aus von einer anderen Klasse) auf eine spezifische Funktion zugreifen möchte, während dort nur der Basisklassenzeiger bekannt ist?



  • Nexus schrieb:

    Was aber, wenn man von aussen (von mir aus von einer anderen Klasse) auf eine spezifische Funktion zugreifen möchte, während dort nur der Basisklassenzeiger bekannt ist?

    Dann hast Du ein gutes Beispiel für schlechtes Design. 😉


  • Administrator

    Nexus schrieb:

    Nur mal ein Anfänger-Beispiel:

    double e = 3.25f;
    double f = 2.67f;
    	
    float i = (e + f)/2;                     // (1)
    float j = static_cast<float>(e + f)/2.f; // (2)
    

    Und wieso nicht gleich:

    double e = 3.25;
    double f = 2.67;
    
    double i = (e + f)/2.0;
    double j = (e + f)/2.0;
    

    Auch wenn du sagst, das sei nur ein Beispiel gewesen, aber genau darauf läuft es hinaus. Ich benutze nur ein static_cast , bei solchen Dingen, wenn es irgendeine Inkonsistenz zwischen zwei Bibliotheken gibt.
    Bei deiner eigenen Bibliothek oder Programm, sollte so eine Inkonsistenz erst gar nicht auftauchen 😉

    Nexus schrieb:

    Bei dynamic_cast habe ich eine ähnliche Meinung. Manchmal ist es eben recht praktisch, ...

    Um deine Designfehler zu behben? 🙂

    Nexus schrieb:

    ... und für mich gibts da schlimmere Designfehler (was ist denn daran überhaupt so schlimm?).

    Schlimmere gibt es natürlich schon.

    Nexus schrieb:

    Ein Vermeiden des dynamic_cast s führt manchmal dazu, dass das gesamte Design geändert werden muss (ja, du wirst jetzt sagen, dass das Design schon von Anfang an schlecht war ;)).

    Genau, es war von anfang an nicht korrekt durchdacht. Gut, da kann man dann manchmal nicht nochmals alles auf den Kopf stellen. Aber theoretisch sollte man 😉

    Für das Restliche, siehe Tachyons Erklärung.

    Nexus schrieb:

    Ja, aber manchmal hat man einen Basisklassenzeiger, um damit mehrere abgeleitete Klassen ansprechen zu können. Und wenn sich die einzelnen Klassen nicht nur in den Definitionen der virtuellen Funktionen unterscheiden, sondern beispielsweise noch weitere, spezifische Funktionen haben, möchte man vielleicht je nach Fall anders auf die Klasse reagieren. Und die spezifischen Eigenschaften einer Klasse kann man von aussen nur mit dynamic_cast modifizieren (man hat nur einen Basisklassenzeiger).

    Wieso hast du nur einen Basisklassenzeiger? Wieso übergibst du nicht gleich die abgeleiteten Klassen? Du kannst ja Funktionen überladen. Allenfalls kannst du sowas machen:

    class Base
    {
    public:
      void base_method();
    };
    
    class One : public Base
    {
    public:
      void one_method();
    };
    
    class Two : public Base
    {
    public:
      void two_method();
    };
    
    // Dein vorgehen:
    void foo(Base* base)
    {
      base->base_method();
    
      One* one = dynamic_cast<One*>(base);
    
      if(one)
      { one->one_method(); }
    }
    
    // Mein vorgehen:
    void foo(Base* base)
    {
      base->base_method();
    }
    
    void foo(One* one)
    {
      one->base_method();
      one->one_method();
    }
    

    Grüssli

    PS: SAGT MAL, WAS POSTET HIER SO SCHNELL??? Jedesmall wenn ich auf Vorschau geklickt habe, waren da 2-3 weiter Posts. Geht gefälligst arbeiten! 😃



  • Tachyon schrieb:

    Das bringt nichts. Wie drakon schon sagte, musst Du eh wissen, welches abgeleitete Objekt Du ansprechen willst. Sowas führt meist zu Funktionen in denen dann über irgendwelche Typabfragen das richtige Objekt zurechgecastet wird, und das ist nicht gerade sehr sauber.

    Ja, hab ich eben auch gerade gemerkt. 😉

    Tachyon schrieb:

    Da macht es mehr Sinn, z.B. überladene Funktionen für die verschiedenen in Frage kommenden Klassen zu machen, die die Spezialfunktionen darin aufzurufen.

    Ja, das war ja meine Alternative 2 Posts vorher. Gibt es nicht Fälle, wo man unbedingt von aussen direkt Spezifisches ansprechen will? Weil beispielsweise die aufgerufene Methode je nach Klasse andere Parameter benötigt, was durch eine einheitliche Schnittstelle über eine virtuelle Funktion nicht zu realisieren wäre?



  • ***** OT-Ticker *** OT-Ticker *** OT-Ticker *****

    Dravere schrieb:

    PS: SAGT MAL, WAS POSTET HIER SO SCHNELL??? Jedesmall wenn ich auf Vorschau geklickt habe, waren da 2-3 weiter Posts. Geht gefälligst arbeiten! 😃

    Eigentlich müsste ich das wirklich dringend, aber ich hab hier im Moment echt gräßliches Dokuzeugs. Das ist so ätzend, da verbringt man lieber Zeit mit dem Verbeiwürgen von hartem Stuhl an schmerzenden Hämorrhoiden, als mit dieser Arbeit.
    ***** OT-Ticker *** OT-Ticker *** OT-Ticker *****

    Nexus schrieb:

    Ja, das war ja meine Alternative 2 Posts vorher. Gibt es nicht Fälle, wo man unbedingt von aussen direkt Spezifisches ansprechen will? Weil beispielsweise die aufgerufene Methode je nach Klasse andere Parameter benötigt, was durch eine einheitliche Schnittstelle über eine virtuelle Funktion nicht zu realisieren wäre?

    "Andere Parameter benötigen" und "einheitliche Schnittstelle" beisst sich ja irgendwie schon, oder? 😉



  • Dravere schrieb:

    Um deine Designfehler zu behben? 🙂

    Ähm... Bitte keine Vorurteile. :p

    Dravere schrieb:

    Auch wenn du sagst, das sei nur ein Beispiel gewesen, aber genau darauf läuft es hinaus.

    Grr, man findet immer etwas. 😉
    Naja, das Beispiel sollte das Prinzip erläutern, von daher läuft es nicht genau darauf hinaus. Von mir aus kann man 2.f durch eine float -Variable ersetzen.

    Dravere schrieb:

    Ich benutze nur ein static_cast, bei solchen Dingen, wenn es irgendeine Inkonsistenz zwischen zwei Bibliotheken gibt.

    Teilweise ist man aber auch selber gezwungen, eine Konvertierung durchzuführen (sei es auch nur, um eine Warnung zu verhindern). Oder, um die Genauigkeit des Resultats anzupassen (z.B. Division zweier Integer).

    Dravere schrieb:

    PS: SAGT MAL, WAS POSTET HIER SO SCHNELL??? Jedesmall wenn ich auf Vorschau geklickt habe, waren da 2-3 weiter Posts. Geht gefälligst arbeiten! 😃

    Habe ich mich auch gefragt. Meine Antworten sind immer auf etwa zwei Posts vorher bezogen...

    Tachyon schrieb:

    "Andere Parameter benötigen" und "einheitliche Schnittstelle" beisst sich ja irgendwie schon, oder? 😉

    Ja eben, deshalb ist auch die Schnittstelle unterschiedlich, wodurch ein dynamic_cast erforderlich ist. Ich weiss, ich habe nicht die besten Beispiele, aber so ein Fall könnte doch schon mal vorkommen...



  • Nexus schrieb:

    Ja eben, deshalb ist auch die Schnittstelle unterschiedlich, wodurch ein dynamic_cast erforderlich ist. Ich weiss, ich habe nicht die besten Beispiele, aber so ein Fall könnte doch schon mal vorkommen...

    Das heisst, Du willst an einer Stelle eine einheitliche Schnittstelle haben. Diese ist die Basisklasse. Dann fällt Dir aber auf, dass die Schnittstelle wohl doch nicht so einheitlich sein soll, und Du castest das, was über die einheitliche Schnittstelle reinkam wieder auf nicht einheitliche, abgeleitete Objekte zurück. Dann braucht man abere eben gerade auch keine einheitliche Schnittstelle.

    Ja, sowas kann vorkommen, aber nur wenn Du Dir vorher nicht ausreichend Gedanken dazu gemacht hast.
    Ich hab dynamic_cast<>, glaube ich, erst einmal gebraucht. Ich hatte mir nicht genug Gedanken über das Design gemacht, und einfach drauf losprogrammiert. Da war schon so viel Code zurechtgerickelt, dass ich fürs Neuschreiben einen auf den Deckel bekommen hätte.


  • Administrator

    Nexus schrieb:

    Ähm... Bitte keine Vorurteile. :p

    Ok, ehm ... können wir deine bisher geschriebenen Codestücke sehen? 😃

    Nexus schrieb:

    Grr, man findet immer etwas. 😉
    Naja, das Beispiel sollte das Prinzip erläutern, von daher läuft es nicht genau darauf hinaus. Von mir aus kann man 2.f durch eine float -Variable ersetzen.

    Dann kommt die Frage, wieso diese float -Variable, einem double zugewiesen werden muss und dann später wieder einem float ? Wieso nicht gleich float bleiben oder allenfalls alles double machen.

    Nexus schrieb:

    Teilweise ist man aber auch selber gezwungen, eine Konvertierung durchzuführen (sei es auch nur, um eine Warnung zu verhindern). Oder, um die Genauigkeit des Resultats anzupassen (z.B. Division zweier Integer).

    ** static_cast ist nicht dazu da Warnungen zu ignorieren!** Ich glaube das sollte man hier mal ganz wesentlich unterstreichen!

    Und was du mit der Genauigkeit meinst, ist mir nicht ganz klar.

    Nexus schrieb:

    Ich weiss, ich habe nicht die besten Beispiele, aber so ein Fall könnte doch schon mal vorkommen...

    Nein, in 99.9999999999% der Fälle, wird dynamic_cast verwendet um Designfehler zu umgehen.

    Grüssli



  • Dravere schrieb:

    Ok, ehm ... können wir deine bisher geschriebenen Codestücke sehen? 😃

    Muss ich mich denn die ganze Zeit rechtfertigen? :p
    Ich bin noch nicht sehr erfahren bei Designfragen und lerne ständig dazu, sonst hätte ich hier wohl keine Frage gestellt.

    Dravere schrieb:

    Dann kommt die Frage, wieso diese float -Variable, einem double zugewiesen werden muss und dann später wieder einem float ? Wieso nicht gleich float bleiben oder allenfalls alles double machen.

    Wie gesagt, man findet immer was. Leider wollte ich vorher kein Maximalbeispiel aufschreiben, damit auch alles klar gewesen wäre. Die Variablen sind von irgendwoher gegeben, durch Parameterübergaben oder so. Und ja, man könnte das schon immer weiter zurückverfolgen, und schlussendlich sagen, man hätte es gleich mit float machen können. Vielleicht waren aber bis zu einem Punkt immer double s erforderlich, und ab da eben nur noch float s. Irgendwo kommt der Punkt, wo man konvertieren muss, und da finde ich den expliziten Weg oft besser, weil man eben gerade deutlich macht, was getan wird.

    Dravere schrieb:

    ** static_cast ist nicht dazu da Warnungen zu ignorieren!** Ich glaube das sollte man hier mal ganz wesentlich unterstreichen!

    Ja, es war vielleicht ein bisschen unglücklich ausgedrückt. Aber man benutzt static_cast schon auch, um dem Compiler klar zu machen, dass man sich der Konvertierung bewusst ist. Insofern benutzt man es schon, um Warnungen zu unterdrücken (mit dem Nebeneffekt, dass man durch die explizite Konvertierung auch besser sieht, was gemacht wird). Auch wenn keine Warnung generiert würde, gibt es Fälle, wo ich lieber noch ein explizites static_cast hinschreibe. Also nicht nur, um Warnungen zu ignorieren.

    Dravere schrieb:

    Und was du mit der Genauigkeit meinst, ist mir nicht ganz klar.

    Folgende beiden Variablen i und j sind gegeben (beispielsweise als Schleifenvariablen):

    int i, j;
    float div = static_cast<float>(i)/static_cast<float>(j);
    

    Ich weiss, man könnte nur einen Cast benutzen, oder einfach eine 1.f * vorne dran setzen, aber ich schreib es lieber, um es eindeutig zu erkennen.

    Dravere schrieb:

    Nein, in 99.9999999999% der Fälle, wird dynamic_cast verwendet um Designfehler zu umgehen.

    So? Ich dachte, es wäre selber einer? :p
    Aber gut, wenn man damit Designfehler umgeht, spricht ja nichts dagegen... 😃


  • Mod

    Fabeltier schrieb:

    Sry, die '&' waren Schreibfehler (cpy/paste).

    template<class T>
    const typename Matrix_2D<T>::Proxy Matrix_2D<T>::operator[](int x) const
    {
        return Matrix_2D<T>::Proxy(const_cast< Matrix_2D<T>& >(*this), x);
    }
    
    template<class T>
    typename Matrix_2D<T>::Proxy Matrix_2D<T>::operator[](int x)
    {
        return typename Matrix_2D<T>::Proxy(*this, x);
    }
    

    const_cast
    Das ist ein Problem, das mir noch nicht 100% klar ist. Ich habe mich hier an Scott Meyers orientiert, dort werden in einem Beispiel beide Versionen der operator[]() wie oben einmal mit und einmal ohne const implementiert. Da die Funktion als "xxx() const" definiert ist, brauch ich hier doch den const_cast um das wieder zu lockern (oder nicht?). Wozu brauche ich eine Const und eine ohne-Const Version (such das gerade nochmal im Buch, ich glaube da stand was..) Afaik ist jegliches casten ja immer eher schlecht, da es das eigentliche Konzept aufbricht, oder?!

    private
    ja hab ich schliesslich auch gemacht.

    Danke fuer die Hinweise!

    Ich habe bereits etwas zu const-Rückgaben von Proxies gesagt, und ich habe nicht die Absicht, mich zu wiederholen.
    Es kann sinnvoll sein, dass eine nicht-const Memberfunktion einen const-Memberoverload aufruft, und das Ergebnis ggf. castet (auch das kann in bestimmten Fällen schiefgehen, das sind dann aber solche, in denen der wechselseitige Aufruf von vorneherein unzulässig ist); den umgekehrten Weg sollte man nie gehen, denn undefiniertes Verhalten ist dann vorprogrammiert, ergo

    template<class T>
    typename Matrix_2D<T>::Proxy Matrix_2D<T>::operator[](int x)
    {
        const Matrix_2D<T>& this_const = *this;
        return this_const[x];
    }
    
    template<class T>
    const typename Matrix_2D<T>::Proxy Matrix_2D<T>::operator[](int x) const
    {
        return typename Matrix_2D<T>::Proxy(*this, x);
    }
    

    Nanu. Wir müssen gar nicht casten? Komisch, dass ich bereits erwähnt habe, dass const-Rückgabe nicht den gewünschten Zweck erfüllen kann...

    Ein Proxie ist im Grunde so etwas wie eine Referenz in Form eines Klassenobjektes. Und so wie bei einer Referenz - die inhärent "konstant" ist - spielt es bei diesem Objekt keine Rolle ob es konstant ist oder nicht, um zu bestimmt, ob diese Konstanz auch auf das referenzierte Etwas zutrifft. Um das zu entscheiden benötigen wir verschiedene Refrenztypen oder eben verschiedene Proxietypen.



  • Nexus schrieb:

    Dravere schrieb:

    Und was du mit der Genauigkeit meinst, ist mir nicht ganz klar.

    Folgende beiden Variablen i und j sind gegeben (beispielsweise als Schleifenvariablen):

    int i, j;
    float div = static_cast<float>(i)/static_cast<float>(j);
    

    Ich weiss, man könnte nur einen Cast benutzen, oder einfach eine 1.f * vorne dran setzen, aber ich schreib es lieber, um es eindeutig zu erkennen.

    In solchen Fällen bin ich auch der Meinung, dass ein cast das einzig sinnvolle ist.
    Aber es gibt ja auch noch andere Fälle, wie z.B bei Farbwerten. Wenn man da halt einen schönen weichen Übergang haben will, kommt man nicht drum herum das mit float's zu lösen, da aber ein DWORD erwartet wird, muss man die Werte casten und in einen DWORD umformen. Ich persönlich übergäbe auch lieber 4 float Werte, anstattt einen DWORD, aber das ist nun halt mal gegeben.


  • Administrator

    Tut mir Leid für die späte Antwort, aber Bakterien scheinen keinen Respekt vor Wochenenden zu haben 🙂

    Nexus schrieb:

    Muss ich mich denn die ganze Zeit rechtfertigen? :p

    Du darfst uns auch einfach nur anbeten und immer recht geben, habe nix dagegen 😃

    Nexus schrieb:

    Die Variablen sind von irgendwoher gegeben, durch Parameterübergaben oder so.

    Nexus schrieb:

    Folgende beiden Variablen i und j sind gegeben (beispielsweise als Schleifenvariablen):

    Was heisst gegeben? Wie ich schon mal sagte, wenn man mit anderen Bibliotheken zusammenarbeitet, dann muss man durchaus mal den static_cast anwenden. Grundsätzlich sollte es aber in der eigenen Bibliothek oder Programm so sein, dass man nicht darauf angewiesen ist oder nur in äusserst seltenen und wenigen Fällen. Sonst ist die Bibliothek einfach nicht korrekt durchdacht. Zumindest ist das meine Meinung. Und ich möchte auch nicht sagen, dass meine Bibliotheken oder Programme immer zu 100% durchdacht sind 🙂

    Nexus schrieb:

    Und ja, man könnte das schon immer weiter zurückverfolgen, und schlussendlich sagen, man hätte es gleich mit float machen können. Vielleicht waren aber bis zu einem Punkt immer double s erforderlich, und ab da eben nur noch float s.

    Wieso man plötzlich von doubles auf floats wechseln muss? Könnte es mir noch höchstens andersrum vorstellen, aber man fragt sich halt schon, wieso man nicht von Anfang an eine allgemeine Grösse genommen hat. Vor allem halt im eigenen geschriebenen Code. Man sollte dort nämlich probieren einheitlich zu bleiben.

    Nexus schrieb:

    Irgendwo kommt der Punkt, wo man konvertieren muss, und da finde ich den expliziten Weg oft besser, weil man eben gerade deutlich macht, was getan wird.

    Nexus schrieb:

    int i, j;
    float div = static_cast<float>(i)/static_cast<float>(j);
    

    Ich weiss, man könnte nur einen Cast benutzen, oder einfach eine 1.f * vorne dran setzen, aber ich schreib es lieber, um es eindeutig zu erkennen.

    Nexus schrieb:

    Auch wenn keine Warnung generiert würde, gibt es Fälle, wo ich lieber noch ein explizites static_cast hinschreibe. Also nicht nur, um Warnungen zu ignorieren.

    Wenn man konvertieren muss, wo es keine implizite verlustfreie Konvertierung gibt und man sie zudem machen muss, dann nimmt man einen static_cast , definitiv. Aber wenn man es nicht muss, dann finde ich sollte man ein bisschen Vertrauen in die Sprache haben. Der Leser sollte schliesslich die Sprache verstehen und dann reicht ein static_cast . Sonst wird das viel zu überladen, erst recht, weil static_cast so ein langes Schlüsselwort ist.

    Nexus schrieb:

    Ja, es war vielleicht ein bisschen unglücklich ausgedrückt. Aber man benutzt static_cast schon auch, um dem Compiler klar zu machen, dass man sich der Konvertierung bewusst ist. Insofern benutzt man es schon, um Warnungen zu unterdrücken (mit dem Nebeneffekt, dass man durch die explizite Konvertierung auch besser sieht, was gemacht wird).

    Nein, man unterdrückt nicht und man sagt dem Compiler auch nicht, dass man sich der Konvertierung bewusst ist.
    Man behebt Warnungen! Und das heisst nicht einfach static_cast hinschreiben, das ist genau das, was mich an der Aussage so stört. Wenn man static_cast hinschreibt, dann sollte das eine wirkliche Lösung darstellen und am besten ist es, wenn man es hinschreibt, bevor der Compiler einem überhaupt eine Warnung an den Kopf geschleudert hat.
    Es kommt halt schnell der Gedanke auf, dass man mit static_cast Warnungen beheben kann, aber das ist ein Fehler, welcher man besser nicht machen sollte. Darunter leidet die Qualität des Codes.

    Nexus schrieb:

    Dravere schrieb:

    Nein, in 99.9999999999% der Fälle, wird dynamic_cast verwendet um Designfehler zu umgehen.

    So? Ich dachte, es wäre selber einer? :p
    Aber gut, wenn man damit Designfehler umgeht, spricht ja nichts dagegen... 😃

    dynamic_cast ist ein Schlüsselwort der Sprache, daher kann das Teil nur schwer ein Designfehler sein :p
    Es wird halt einfach zu oft falsch eingesetzt.

    Grüssli


Anmelden zum Antworten