Operator [ ] rundet Wert



  • Hallo !

    Ich möchte im Rahmen einer Übung "[ ]" als Operator definieren.
    Es ist eine Klasse für einen Punkt im 3D Raum definiert.
    Die Punktkoordinaten sind double Werte.

    Beim Zugriff mittels Operator wird der Wert auf
    die erste Nachkommastelle gerundet, nur warum ist das so?

    • .hpp File:
    class Point3D
    {
    private:    double x, y, z;   unsigned short int precicion;
    		 std::string str;
    public:     
            //.... some Code 
    	double operator [] ( int index );    
            //.... some Code
    };
    
    • .cpp File:
    double Point3D::operator [] ( int index )
    {
    	switch (index) {
    		case 0: return x;
    		case 1: return y;
    		case 2: return z;
    		default: std::cerr << "Junge, gib 0 || 1 || 2 ein !" << std::endl;
    		exit(1);
    	}
    }
    
    • main:
    #include "19_6_class_Point_3D.hpp"
    int main(void)
    {
    	Point3D p1, p2;  
    	//Test Operator []
    	p1.Set_x(4); p1.Set_y(4.5687); p1.Set_z(5.67);
    	std::cout << "\n\nOperator '[]' Test: \n   p1( 4; 4,5687; 5,67 )"
    	<< " Jetzt Ausgabe des y-Elementes von p1:" << std::endl;
    	std::cout << "   p1[1] = " 
            << p1[1] << std::endl;   //Ausgegeben wird 4.6 !!! :-(
    
    	system("pause");
    }
    

    MfG, 0xFF



  • @0xFF am cout kann es nicht liegen?

    was gibt p1[1] * 10000 ?



  • @DirkB ..nein, das glaube ich nicht, weil wenn ich p1 so ausgeben lasse, dann wird p1 wie definiert ausgegeben,
    das habe ich schon getestet.



  • @0xFF Am einfachsten ist es für uns, wenn du den Code so zusammen schreibst, dass wir den raus kopieren und compilieren können um das Problem direkt nachzuvollziehen.



  • Ja Schlangenmensch, da hast Du vollkommen recht!

    Hier der Code:

    • Header:
    #pragma once
    #ifndef  _19_6_CLASS_POINT_3D_HPP_
    #define  _19_6_CLASS_POINT_3D_HPP_  // wie Ueb. 19.5 ergaenzt um Operator
                                        // fuer Multiplikation, Skalarprodukt usw.
    #include "general_definitions.h"
    #if RUN_Uebung_19_6 == 1
    
    #include<string>
    #include<iostream>
    #include<iomanip>
    #include<sstream>
    
    // Klasse die einen Punkt im 3 dimensionalen Raum beschreibt
    class Point3D
    {
    private:    double x, y, z;   unsigned short int precicion;
    			std::string str;
    public:      // Konstruktor -- Default
    	Point3D() : x(0.00), y(0.00), z(0.00) { Set_precision(4); }
    	         // Konstruktor -- Mit Parametern	      
    	Point3D(double x_, double y_, double z_);
    
    	Point3D operator - (Point3D *p3d_p); //Substraktion von 2 Punkten;  Ueb.: 19.6
    
    	Point3D operator - (Point3D& p3d) {
    		this->x -= p3d.x;
    		this->y -= p3d.y;
    		this->z -= p3d.z;  return p3d;
    	}
    	Point3D operator -= (Point3D& p3d) {
    		this->x -= p3d.x;
    		this->y -= p3d.y;
    		this->z -= p3d.z;  return p3d;
    	}
    	Point3D operator += (Point3D& p3d) {  
    		this->x += p3d.x;
    		this->y += p3d.y;
    		this->z += p3d.z;  return p3d;
    	}
    	Point3D operator * ( double d ) {      //Skalarprodukt
    		this->x *= d;                      // 1. Ueberladung des * - Operator
    		this->y *= d;                      //Test i.O. 2.2. 2020
    		this->z *= d;  return *this;
    	}
    	Point3D operator * ( Point3D &p3d ) {  //Produkt zweier Punkte
    		this->x *= p3d.x;                  // 2. Ueberladung des * - Operator
    		this->y *= p3d.y;                  //Test i.O. 2.2. 2020
    		this->z *= p3d.z;  return *this;
    	}
    #if  1
    	double operator [] ( int index );        //fuer nicht Konstante Objekte
    #endif
    #if  1
    	double operator [ ] ( int index ) const {  //fuer Konstante Objekte
    		switch (index) {
    		    case 0: return x;
    		    case 1: return y;
    			case 2: return z;
    			default: std::cerr << "Index must be 0, 1 or 2!" << std::endl;
    			exit(1);
    		}
    	}
    #endif
    	friend std::ostream& operator << (std::ostream& os, Point3D p3d);
    
    	// Getter
    	inline const double  Get_x(void) { return x; }
    	inline const double  Get_y(void) { return y; }
    	inline const double  Get_z(void) { return z; }
    	inline const double  Get_precision(void) { return precicion; }
    	inline std::string  Get_str(void);             //string
    
    	// Setter
    	inline void  Set_x(double x_) { this->x = (const double)x_; }
    	inline void  Set_y(double y_) { this->y = (const double)y_; }
    	inline void  Set_z(double z_) { this->z = (const double)z_; }
    	inline void  Set_precision(unsigned short int prec)
    	{ 
    		if (prec > 15) { prec = 15; }  this->precicion = prec;
    	}
    
    protected:   // ---
    
    };
    #endif  //if RUN_Uebung_19_6==1
    #endif  //_19_6_CLASS_POINT_3D_HPP_
    
    // EOF
    
    • cpp-File:
    
    #include "general_definitions.h"
    #if RUN_Uebung_19_6 == 1
    
    #include "19_6_class_Point_3D.hpp"
    
    Point3D::Point3D(double x_, double y_, double z_)  //Ueb. 19.5
    {
    	x = (double)x_; y = (double)y_; z = (double)z_;
    }
    #if  1
    double Point3D::operator [] ( int index )  //Ueb. 19.6
    {
    	switch (index) {
    		case 0: return x;
    		case 1: return y;
    		case 2: return z;
    		default: std::cerr << "Junge, gib 0 || 1 || 2 ein !" << std::endl;
    		exit(1);
    	}
    }
    #endif
    std::ostream& operator << (std::ostream& os, Point3D p3d) {  //friend of Point3D
    	#if  1                                                   //Ueb. 19.5
    		os << "(" + std::to_string(p3d.Get_x()) + ", "
    			      + std::to_string(p3d.Get_y()) + ", "
    			      + std::to_string(p3d.Get_z()) + ")";
    		return os;
    	#endif
    	#if  0
    		return os << p3d.Get_str();
    	#endif
    }
    
    Point3D Point3D::operator - (Point3D *p3d_p)  //2. Punkt als Pointer
    {                                             //Ueb. 19.6
    	x -= p3d_p->x;  y -= p3d_p->y;  z -= p3d_p->z; 
    	return *this;                             //OK getestet: 2.2.2020
    }
    
    inline std::string  Point3D::Get_str(void)    //Ueb. 19.5
    {
    	this->str = "(" + std::to_string(x) + ", " \
    	  + std::to_string(x) + ", " + std::to_string(x) + ")";
    	return str;
    }
    
    #endif //if RUN_Uebung_19_6==1
    // EOF
    
    • main:
    // A_19_6_MAIN.cpp: Definiert den Einstiegspunkt für die Konsolenanwendung.
    #include "general_definitions.h"
    
    #if RUN_Uebung_19_6 == 1
    
    #include <iostream>
    #include <fstream>
    #include "19_6_class_Point_3D.hpp"
    void Test_InneresProdukt_2er_Punkte( void );
    void Test_Produkt_doubleZahl_x_Punkt( void);
    void Test_Punkt_1_minus_Punkt_2(      void);
    int main( void )
    {
    	Point3D p1, p2;                      // Auruf Deufault Konstruktor
    	Point3D p3(20, 40, 60), p4(4, 6, 8); // Auruf Konstruktor mit Para.
    
    	std::cout << "\n=============== Uebung 19.6 Operatoren ==============" << std::endl
    		
    	//Test Operator []  ... neu hinzu bei 19.6
    	p1.Set_x(4); p1.Set_y(4.5687); p1.Set_z(5.67);
    	std::cout << "\n\nOperator '[]' Test: \n   p1( 4; 4,5687; 5,67 )"
    	<< " Jetzt Ausgabe des y-Elementes von p1:" << std::endl;
    	std::cout << "   p1[1] = " << p1[1] << std::endl;
    
    	system("pause");
    	return 0;
    }
    // EOF
    


  • #include "general_definitions.h"
    

    Der Inhalt dieser Datei fehlt. Unter Annahme, dass die Datei leer ist, ist das Problem nicht reproduzierbar.

    VS2019:

    =============== Uebung 19.6 Operatoren ==============
    
    
    Operator '[]' Test:
       p1( 4; 4,5687; 5,67 ) Jetzt Ausgabe des y-Elementes von p1:
       p1[1] = 4.5687
    Drücken Sie eine beliebige Taste . . .
    

    GCC 9.2.0 (libstdc++ und MinGW-w64):

    =============== Uebung 19.6 Operatoren ==============
    
    
    Operator '[]' Test:
       p1( 4; 4,5687; 5,67 ) Jetzt Ausgabe des y-Elementes von p1:
       p1[1] = 4.5687
    Dr▒cken Sie eine beliebige Taste . . .
    

    Das beschriebene Phänomen tritt bei mir mit beiden Compilern nur dann auf, wenn ich die precision für Floating-Point-Ausgabe verändere:

    std::cout.precision(2);
    ...
    std::cout << "   p1[1] = " << p1[1] << std::endl;
    

    gibt bei mir dann tatsächlich

       p1[1] = 4.6
    

    aus. Welchen Compiler verwendest du? Wird eventuell in general_definitions.h noch irgendwas komisches gemacht?

    Und Frage an andere: Wie weit ist eigentlich der initiale Zustand von cout vom Standard vorgegeben? Könnte es tatsächlich Compiler geben, bei denen cout standardkonform mit so einer precision initialisiert wird?



  • @Finnegan
    Hi, danke für Deine Mühe,
    Das File fehlt, da schalt ich nur die Files der
    betreffenden Übung zu oder ab.

    Ich muss heute Abend mal checken ob ich evtl.
    versehentlich cout.precision irgendwo vorher in meiner main
    gesetzt hatte,
    habe nicht das ganze main-File gepostet, weil ich da noch
    andere Funktionen getestet habe -- und war der (offentsichlich falschen)
    Ansicht dass der Code nicht relevant ist --- Asche auf mein Haupt 😕

    Ich werde die komplette main heute Abend posten.

    Als Compiler verwende ich den Standard C++ Compiler von Visual Studio Code 2019.

    Grüsse



  • @0xFF sagte

    Beim Zugriff mittels Operator wird der Wert auf
    die erste Nachkommastelle gerundet

    Nein, wird er nicht.

    @0xFF sagte

    wenn ich p1 so ausgeben lasse

    Tust du nicht. Du verwendest to_sting.

    x = (double)x_;

    Was soll der Cast? Ein double wird nicht doubliger.



  • Hallo Manni,

    Danke für Deinen Input,
    Da hast Du recht in allen Punkten.

    MfG, Dirk



  • Guten Abend,
    also hier ist die vollständige main:

    // A_19_6_MAIN.cpp: Definiert den Einstiegspunkt für die Konsolenanwendung.
    //
    //#include "stdafx.h"
    
    #include "general_definitions.h"
    
    #if RUN_Uebung_19_6 == 1
    
    #include <iostream>
    #include <fstream>
    #include "19_6_class_Point_3D.hpp"
    void Test_InneresProdukt_2er_Punkte( void );
    void Test_Produkt_doubleZahl_x_Punkt( void);
    void Test_Punkt_1_minus_Punkt_2(      void);
    int main( void )
    {
    	Point3D p1, p2;                      // Auruf Deufault Konstruktor
    	Point3D p3(20, 40, 60), p4(4, 6, 8); // Auruf Konstruktor mit Para.
    
    	std::cout << "\n=============== Uebung 19.6 Operatoren ==============" << std::endl
    		<< "Es wurden 4 Punkte angelegt, ihre Werte lauten:" << std::endl
    		<< "p1: " << std::setprecision(2) << p1 << std::endl
    		<< "p2: " << std::setprecision(2) << p2 << std::endl
    		<< "p3: " << std::setprecision(2) << p3 << std::endl
    		<< "p4: " << std::setprecision(2) << p4 << std::endl;
    
    	//Test Setter
    	std::cout << "\n\nManipulieren mit Setter, p1 auf 4.456, 5.34, 68" << std::endl;
    	p1.Set_x(4.456); p1.Set_y(5.34); p1.Set_z(68);
    	std::cout << "p1: " << p1 << std::endl;
    
    	//Test operator -
    	std::cout << "\n\nOperator '-=' Test: \n   p1( 4.456, 5.34, 68 )"
    		<< " -= p2( 1.00, 2.34, 8.00 ) ergibt:" << std::endl;
    	p2.Set_x(1.00); p2.Set_y(2.34); p2.Set_z(8.00);
    	p1 -= p2;  // '-=' Operator wirkt hier
    	std::cout << "   p1" << p1 << std::endl;  //Funktioniert.
    
    	//Test Operator []  ... neu hinzu bei 19.6
    	p1.Set_x(4); p1.Set_y(4.5687); p1.Set_z(5.67);
    	std::cout << "\n\nOperator '[]' Test: \n   p1( 4; 4,5687; 5,67 )"
    	<< " Jetzt Ausgabe des y-Elementes von p1:" << std::endl;
    	std::cout << "   p1[1] = " << p1[1] << std::endl;
    
    	Test_InneresProdukt_2er_Punkte();   //19.6
    
    	Test_Produkt_doubleZahl_x_Punkt();  //19.6
    
    	Test_Punkt_1_minus_Punkt_2();       //19.6
    
    	system("pause");
    	return 0;
    }
    
    void Test_InneresProdukt_2er_Punkte(void)  //Test i.O. 2.2. 2020
    {
    	//1. Überladung Operator *   ... neu hinzu bei 19.6
    	Point3D p1(2.2, 3.3, 4.4),  p2(1.1, 1.2, 2.0);
    	std::cout << "\n\nTest des inneren Produktes aus 2 Punkten im 3D-Raum"
    		<< "\n    p1( 2.2, 3.3, 4,4 ) und p2( 1.1, 1.2, 2.0 )"
    		<< "\n    Das Ergebnis muss 2.42, 3.96, 8.8 lauten:"
    	    << "\n    p1 * p2 = " << p1 * p2 << std::endl;
    }
    void Test_Produkt_doubleZahl_x_Punkt(void)  //Test i.O. 2.2. 2020
    {
    	//2. Überladung Operator *   ... neu hinzu bei 19.6
    	Point3D p1(2.2, 3.3, 4.4);
    	double z; z = 1.3;
    	std::cout << "\n\nTest Produkt double-Zahl mit Punkt im 3D-Raum"
    		<< "\n    p1( 2.2, 3.3, 4.4 ) und double-Zahle = 1.30"
    		<< "\n    Das Ergebnis muss 2.86, 4.29, 5.72 lauten:"
    		<< "\n    p1 * 1.3 = " << p1 * z << std::endl;
    }
    void Test_Punkt_1_minus_Punkt_2(void)  //Test i.O. 2.2 2020
    {
    	//2. Überladung Operator -   ... neu hinzu bei 19.6
    	Point3D p1(2.2, 3.3, 4.4), p2(1.1, 2.2, 1.39);
    	// p2 muss fuer diese Überladung als Zeiger übergeben werden
    	std::cout << "\n\nTest Subtraktion 2er Punkte im 3D-Raum"
    		<< "\n    p1( 2.2, 3.3, 4.4 ) und p2( 1.1 , 2.2 , 1.39 )"
    		<< "\n    Das Ergebnis p1 - p2 muss 1.1, 1.1, 3.01 lauten:"
    		<< "\n    p1 - p2 = " << p1 - &p2 << std::endl;
    }       //p1 wird dabei nicht verändert, wenn man das Ergebnis
            //speichern will muss man in neuen Punkt schreiben oder 
            //in p1 schreiben: p1 = p1 - p2; das geht.
    #endif //if RUN_Uebung_19_6 == 1
    // EOF
    

    ... Und hier noch der Vollständigkeit halber
    das File mit den Define-Schaltern:

    #pragma once
    #ifndef general_definitions_H_   
    #define general_definitions_H_   
    //       Fuer Uebung zu Operatoren              //
    // Uebungsbuch: "C++ Das Übungsbuch" 3. Auflage //
    // Autoren Peter Prinz, Ulla Kirch-Prinz        //
    
    #define  RUN_Uebung_19_5   0  //Thema: Point 3D
    #define  RUN_Uebung_19_6   0  //Thema: Point 3D
    #define  RUN_Uebung_19_7   1  //Thema: Student Scores
    #define  RUN_Uebung_19_8   0  
    #define  RUN_Uebung_19_9   0
    #define  RUN_Uebung_19_10  0
    
    #if RUN_Uebung_19_5 + RUN_Uebung_19_6 + RUN_Uebung_19_7 \
      + RUN_Uebung_19_8 + RUN_Uebung_19_9 + RUN_Uebung_19_10 != 1
    #  error " You Have to Choose 1 Option! "
    #endif
    
    #endif //general_definitions_H_
    // EOF
    

    Schönen Abend euch ..



  • @manni66 sagte in Operator [] rundet Wert:

    Ein double wird nicht doubliger.

    😁



  • .. Ja den fand ich auch zum schmunzeln, recht hat er !



  • @0xFF Nur ein ganz kleiner Tipp. Nimm für die Übungen in der Konsole statt system("pause") zB

    void ready()
    {
    	std::cerr << "\nready_\n";
    	std::cin.sync();
    	std::cin.get();
    }
    

    Nur um das rauszuhaben plus auf Tastendruck warten



  • Jo, Danke für den Tip!



  • @0xFF std::setprecision(2) da ist doch der Übeltäter



  • @0xFF sagte in Operator [] rundet Wert:

    exit(1);

    lass das!



  • @Swordfish sagte in

    :

    @0xFF sagte in Operator [] rundet Wert:

    exit(1);

    lass das!

    Wichtiger wäre, die Fehlerausgabe wegzulassen. Es ist nicht der Job von operator[], den Benutzer zu belehren. Die Funktion sollte eine Vorbedingung, 0 <= index && index < 3, haben, dokumentieren, und mit assert abprüfen. Das genügt. Es liegt dann in der Verantwortung des Aufrufers, einen gültigen Index zu übergeben.



  • @Bashar
    Jup, das stimmt, war eben in der Übung so gefordert, sollte aber
    bei einem Professionellen Programm anders abgefangen werden,
    Danke für den Hinweis.
    @Schlangenmensch
    Ja, ich war der Meinung std::setprecision wirkt nur bis zum nächsten
    Aufruf von cout ...


Anmelden zum Antworten