Stack overflow: bei der Verwendung einer Funktion in der Klasse



  • Hallöchen, bin neu in der Thema, wie man eigene Klasse erstellt usw. und bin fast sicher, dass der Fehler auf der Oberfläche liegt, hab selbst im Internet nachgegugt und nix gefunden.. Wahrscheinlich verstehe ich was nicht ganz klar und stelle falsche Fragen zu Google.

    Hier geht es um ne Klasse, die eine Zahl modulo 13 speichert, dabei muss der Parameter, der übergeben wirt unsigned int sein. Dann überlade ich einige Operatoren und im Falle wenn eine Zahl der Klasse (minus/ mal) eine negative Zahl gerechnet wird kommt schliesslich ne negative Zahl raus und der Zahl muss wieder ensprechende Restklasse(mod 13) zugewiesen werden, deswegen habe ich ne Methode verwendet, die ihr übergebene Zahl in die Restklasse(13) verschiebt : (z.b aus -3 -> +10 macht).

    Soweit ich eine Methode (also void-Funktion)verwendet habe (Code unten) funktionirte alles, danach wollte ich meinen Code ein bisschen schöner gestalten, deswegen habe ich die als eine Funktion überschrieben: (und genau dann ist der Fehler aufgetreten! )

    Der Fehler: Ausnahmefehler bei 0x010B1879 in ZahlModulo13.neu.exe: 0xC00000FD: Stack overflow (Parameter: 0x00000001, 0x010D2F58),
    sowie ich das verstehe: Stack overflow passiert wenn Rekursion sehr oft auftritt oder wenn man auf Speicher zugreift, der gar nicht existiert, was mache ich da falsch?

    Ich wäre sehr dankbar wenn ihr mir helfen würden:

    void restklasse(int n&)
    {
            n=((n % 13)+ 13) % 13;
    }
    
    unsigned int restklasse(int n)
    {
    	return ((n % 13) + 13) % 13;
    }
    

    Der ganze Code:

    class.h :

    #pragma once
    #include<iostream>
    class ZahlModulo13
    {
    public:
    	ZahlModulo13(unsigned int n)
    	{
    		m_n = n % 13;
    	};
    
    	ZahlModulo13() : m_n(0) {};
    
    	friend unsigned int restklasse(int k);
    
    	friend ZahlModulo13 operator*(const ZahlModulo13& lhs, int rhs);
    	friend ZahlModulo13 operator*(const ZahlModulo13& lhs, const ZahlModulo13& rhs);
    	friend ZahlModulo13 operator*(int lhs, const ZahlModulo13& rhs);
    
    	friend ZahlModulo13 operator+(const ZahlModulo13& lhs, int rhs);
    	friend ZahlModulo13 operator+(const ZahlModulo13& lhs, const ZahlModulo13& rhs);
    	friend ZahlModulo13 operator+(int lhs, const ZahlModulo13& rhs);
    
    	friend ZahlModulo13 operator-(const ZahlModulo13& lhs, int rhs);
    	friend ZahlModulo13 operator-(const ZahlModulo13& lhs, const ZahlModulo13& rhs);
    	friend ZahlModulo13 operator-(int lhs, const ZahlModulo13& rhs);
    
    	friend std::ostream &operator<<(std::ostream &ostr, const ZahlModulo13 &a);
    	friend std::istream &operator >> (std::istream &istr, const ZahlModulo13 &a);
    
    private:
    	unsigned int m_n;
    
    };
    

    class.cpp :

    #include<iostream>
    #include<math.h>
    #include"class.h"
    
    unsigned int restklasse(int n)
    {
    	return ((n % 13) + 13) % 13;
    }
    
    ZahlModulo13 operator*(const ZahlModulo13& lhs, const ZahlModulo13& rhs)
    {
    	return lhs.m_n * rhs.m_n;
    }
    
    ZahlModulo13 operator*(const ZahlModulo13& lhs, int rhs)
    {
    	return ZahlModulo13(lhs.m_n* restklasse(rhs));
    }
    
    ZahlModulo13 operator *(int lhs, const ZahlModulo13& rhs)
    {
    	return ZahlModulo13(rhs.m_n* restklasse(lhs));
    }
    
    ZahlModulo13 operator+(const ZahlModulo13& lhs, const ZahlModulo13& rhs)
    {
    	return ZahlModulo13(lhs.m_n + rhs.m_n);
    }
    
    ZahlModulo13 operator +(const ZahlModulo13& lhs, int rhs)
    {
    	return ZahlModulo13(lhs.m_n + restklasse(rhs));
    }
    
    ZahlModulo13 operator +(int lhs, const ZahlModulo13& rhs)
    {
    	return ZahlModulo13(rhs.m_n + restklasse(lhs));
    }
    
    ZahlModulo13 operator - (const ZahlModulo13& lhs, const ZahlModulo13& rhs)
    {
    return ZahlModulo13( restklasse(lhs.m_n - rhs.m_n));
    }
    
    ZahlModulo13 operator - (const ZahlModulo13& lhs, int rhs)
    {
    return  ZahlModulo13( restklasse(lhs.m_n - rhs));
    }
    
    ZahlModulo13 operator -(int lhs, const ZahlModulo13& rhs)
    {
    return  ZahlModulo13( restklasse(lhs - rhs.m_n));
    }
    
    std::ostream &operator<<(std::ostream &ostr, const ZahlModulo13 &a)
    {
    	ostr << a.m_n;
    	return ostr;
    }
    
    std::istream &operator >> (std::istream &istr, const ZahlModulo13 &a)
    {
    	istr >> a.m_n;
    	return istr;
    }
    

    Main.cpp :

    #include<iostream>
    #include"class.h"
    
    int main()
    {
    	ZahlModulo13 a, b, erg;
    	char c;
    
    	std::cout << "Geben Sie Ihre erste Zahl ein: ";
    	std::cin >> a;
    
    	std::cout << "Geben Sie Ihre zweite Zahl ein: ";
    	std::cin >> b;
    
    	std::cout << "Geben Sie ein Operator ein (+,-,*): ";
    	std::cin >> c;
    
    	switch (c)
    	{
    	case '+':
    		erg = a + b;
    		break;
    	case '*':
    		erg = a * b;
    		break;
    	}
    
    	std::cout << "In der Restklasse 13: a " << c << " b = " << a << "(13) " << c << b << "(13) = " << erg << "(13) ";
    
    	std::cin.get();
    	return 0;
    }
    


  • Dann schaust du mal mit dem Debugger nach, in welcher Funktion der Stack überläuft.



  • Der operator>> ruft sich selbst auf.

    Du hast a als const& deklariert, also kann dieser Operator a (und damit auch a.m_n) nicht ändern. Er kann aber aus a.m_n ein temporäres ZahlModulo13 bauen und dessen operator>> (also sich selbst) aufrufen.



  • ...und um zu verhindern, dass ungewünscht der Konstruktor aufgerufen wird, solltest du im Normalfall alle Konstruktoren, die nur ein Argument haben, als explicit deklarieren.

    Also:

    explicit ZahlModulo13(unsigned int n) {
       ...
    }
    

    Dann fällt auch auf, dass dein operator* einfach nur eine Zahl zurückgibt. Auch hier musst du dann explizit "ZahlModulo13" schreiben, wie in den anderen Operatoren auch.

    Achtung bei modulo mit negativen Zahlen, wenn dein Code vor C++11 laufen soll - dann ist das Ergebnis nämlich nicht vom Standard festgelegt, sondern implementierungsabhängig. Ich bekomme bei Modulo mit Negativen Zahlen sowieso immer einen Knoten in den Kopf, also empfehle ich hier, unbedingt ein paar Tests zu schreiben!



  • MFK schrieb:

    Der operator>> ruft sich selbst auf.

    Du hast a als const& deklariert, also kann dieser Operator a (und damit auch a.m_n) nicht ändern. Er kann aber aus a.m_n ein temporäres ZahlModulo13 bauen und dessen operator>> (also sich selbst) aufrufen.

    Ah, stimmt! Danke für den Tipp 🙂



  • wob schrieb:

    ...und um zu verhindern, dass ungewünscht der Konstruktor aufgerufen wird, solltest du im Normalfall alle Konstruktoren, die nur ein Argument haben, als explicit deklarieren.

    Also:

    explicit ZahlModulo13(unsigned int n) {
       ...
    }
    

    Dann fällt auch auf, dass dein operator* einfach nur eine Zahl zurückgibt. Auch hier musst du dann explizit "ZahlModulo13" schreiben, wie in den anderen Operatoren auch.

    Achtung bei modulo mit negativen Zahlen, wenn dein Code vor C++11 laufen soll - dann ist das Ergebnis nämlich nicht vom Standard festgelegt, sondern implementierungsabhängig. Ich bekomme bei Modulo mit Negativen Zahlen sowieso immer einen Knoten in den Kopf, also empfehle ich hier, unbedingt ein paar Tests zu schreiben!

    Bei dem Operator* hab ich noch getestet und ist egal, ob ich das Ergebnis in ZahlModulo13 umwandle oder nicht: Funktion erwartet den entsprechenden Typ und macht's selbst. Oder ist es einfach 'schöner' zu lesen?

    Und ja, danke für den Tipp mit dem expliziten Konstrktor, das wusste ich nicht:)