[OO] Strings in C++

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
Antworten
Benutzeravatar
The Torso
Beiträge: 882
Registriert: 13.07.2003 12:46:40
Lizenz eigener Beiträge: MIT Lizenz

[OO] Strings in C++

Beitrag von The Torso » 26.05.2004 11:48:17

In Java sieht das so aus:

Code: Alles auswählen

    public String toString() {
	kuerzen();

	String st = "";
	int b = 0;

	if (zaehler > nenner)
	    {
		//System.out.println("\t\t\t" + zaehler  + "/" + nenner);
		int z = zaehler;
		while (z > nenner)
		    {
			z -= nenner;
			b++;
		    }
		if (nenner == zaehler)
		    st =  z + "/" + nenner + " = 1";
		else
		    st = b + " " + z + "/" + nenner;
	    }
	else if (zaehler == nenner)
	    st =  zaehler + "/" + nenner + " = 1";
	else if (zaehler != 0)
	    st = (zaehler + "/" + nenner);
	else
	    st = "0";

	return st;
    }
In C++ musste ich das aber so schreiben (nicht ganz der gleiche Code):

Code: Alles auswählen

char* Bruch::toString() 
{
  kuerzen();

  char *back;
  int b = 0;

  back = new char[50];
  char* number = new char[10];

  if (zaehler != 0)
    {

      if (zaehler > nenner)
	{
	  int z = zaehler;

	  while (z > nenner)
	    {
	      z -= nenner;
	      b++;
	    }

	  sprintf(number,"%d",b);
	  strcat(back,number);
	  strcat(back," ");
	  sprintf(number,"%d",z);
	  strcat(back,number);
	  strcat(back,"/");
	  sprintf(number,"%d",nenner);
	  strcat(back,number);
	}
      else
	{
	  sprintf(number,"%d",zaehler);
	  strcat(back,number);
	  strcat(back,"/");
	  sprintf(number,"%d",nenner);
	  strcat(back,number); 
	}
    }
  else
    { 
      strcat(back,"0");
    }

  return back;
}
Ich finde die Loesung in C++ etwas umstaendlich, kann man das nicht auch mit Strings machen? Ich hab schon in meinen buechern nachgeschaut, das Internet durchforstet, aber nichts gefunden.

Meine Fragen sind also:

1. Kann man da nicht einen String zurueckgeben?
2. wie wandle ich eine Zahl in ein String-element um und haenge es an den Rueckgabestring an?
Debian GNU/Linux 00101010

tylerD
Beiträge: 4068
Registriert: 10.07.2002 17:34:13
Wohnort: Halle/Saale
Kontaktdaten:

Beitrag von tylerD » 26.05.2004 13:07:57

Was du schreibst ist C und kein C++. Dafür gibts auch die Klasse std::string [1],[2].

Für das Umwandeln [3]

cu

[1] http://www.msoe.edu/eecs/ce/courseinfo/stl/string.htm
[2] http://www.cppreference.com/cppstring.html
[3] http://www.voyager.prima.de/cpp/str2num.html

Benutzeravatar
The Torso
Beiträge: 882
Registriert: 13.07.2003 12:46:40
Lizenz eigener Beiträge: MIT Lizenz

Beitrag von The Torso » 26.05.2004 15:25:15

Ok, das umwandeln funktioniert einwandfrei, aber ich schaff die Rueckgabe einfach nicht.

In der Headerdatei steht:

Code: Alles auswählen

 string toString(); oder
std::string toSort();
Im Programm dann

Code: Alles auswählen

string Bruch::toString() oder
std::string Bruch::toString()
Und der Kompiler sagt (hier nur fuer die erste Moeglichkeit, bei der zweiten wird das zu lang :roll: )

Code: Alles auswählen

In file included from bruch.cpp:1,
                 from main.cpp:1:
bruch.h:26: error: parse error before `)' token
In file included from main.cpp:1:
bruch.cpp:135: error: no `std::string Bruch::toString()' member function 
   declared in class `Bruch'


Testweise hab ich mal alles geloescht, jetzt schaut die Funktion so aus:

Code: Alles auswählen

//char* Bruch::toString()
string Bruch::toString()
{

  string ba = "";
  char *back = new char[1];
  int b = 0;

  std::ostringstream outStream;
  outStream << b;

  ba += outStream.str();
  ba += "/";
  std::cout << "\t\t\t" << ba << endl;

  //return back;
  return ba;
}
Kannst du mir vielleicht nicht doch noch einen Tipp geben, wie ich den String (ba) zurueckgeben kann. Achja, in der .cpp Datei sind

Code: Alles auswählen

#include "bruch.h"
#include <iostream>
#include <string>
#include <sstream> // Zum umwandeln von Zahlen in Strings
using namespace std;
eingebunden, aber trotzdem will er nicht, ich weis nicht mehr was ich probieren koennte!
Debian GNU/Linux 00101010

tylerD
Beiträge: 4068
Registriert: 10.07.2002 17:34:13
Wohnort: Halle/Saale
Kontaktdaten:

Beitrag von tylerD » 26.05.2004 15:42:40

Also erst einmal, wenn ich mich noch an meine C++-Zeiten richtig erinnern kann:

so wie du das machst geht das nicht. Da man in Java immer schön mit Referenzen (also Zeigern) arbeitet und in C++ nicht zwangsläufig wird das oben knallen. Du erzeugst eine lokale Variable ba, die nur in der Funktion gültig ist und gibst diese zurück. Ausserhalb der Funktion gibst die Instanz aber ned mehr. Der Java weg wäre, die Instanz mit new zu erzeugen und auf dem Zeiger (->) arbeiten und diesen zurückgeben (dann mußt du dich aber auch wieder drum kümmern, dass der belegte Speicher an geeigneter Stelle wieder freigegeben wird), oder eine Referenz auf einen String in diese Funktion reingeben und diesen dann bearbeiten.

Wenn ich die Compilerausgabe richtig interpretiere hast du irgend einen Syntaxerror in der bruch.h Datei, deswegen kennt er wohl auch die member Funktion nicht.

cu

Benutzeravatar
The Torso
Beiträge: 882
Registriert: 13.07.2003 12:46:40
Lizenz eigener Beiträge: MIT Lizenz

Beitrag von The Torso » 26.05.2004 15:57:16

tylerD hat geschrieben:so wie du das machst geht das nicht.
Was du nicht sagst :wink:

Ich glaube ich hab verstanden was du meinst. hab grad keine Zeit, werds aber dann probieren und Meldung erstatten falls es (nicht) funktioniert hat!
Debian GNU/Linux 00101010

tylerD
Beiträge: 4068
Registriert: 10.07.2002 17:34:13
Wohnort: Halle/Saale
Kontaktdaten:

Beitrag von tylerD » 26.05.2004 16:02:36

The Torso hat geschrieben: Was du nicht sagst :wink:
Ich meinte ja nicht das Compilerproblem, was ja glaub ich nur auf nen Syntaxfehler zurückzurühren ist. Die logik in deiner Funktion an sich ist meiner Meinung falsch. Das wäre das Problem, an das du geraden wärst, wenn du es geschafft hättest zu kompilieren 8)

cu

Benutzeravatar
Joghurt
Beiträge: 5244
Registriert: 30.01.2003 15:27:31
Wohnort: Hamburg
Kontaktdaten:

Beitrag von Joghurt » 26.05.2004 16:14:16

  1. Das mit dem string sollte gehen, es wird immer eine neue Instanz erzeugt
  2. Hast du auch in der

    Code: Alles auswählen

    class Bruch {...
    definition ein

    Code: Alles auswählen

    string toString();
    reingeschrieben? Und was soll das
    Im Programm dann

    Code: Alles auswählen

    string Bruch::toString()
    heißen?
Lad' die Programme doch irgendwo hoch, ich schau dann mal nach
Grüße,
Dennis

Benutzeravatar
bitbieger
Beiträge: 179
Registriert: 23.10.2003 08:26:00
Kontaktdaten:

Beitrag von bitbieger » 26.05.2004 16:34:42

tylerD hat geschrieben:...so wie du das machst geht das nicht....Du erzeugst eine lokale Variable ba, die nur in der Funktion gültig ist und gibst diese zurück....
Das ist falsch. Es wird eine Kopie der lokalen Variable zurückgegeben. Ist also kein Problem...

Mach's ungefähr so...

Code: Alles auswählen

class Bruch
{
    int zaehler;
    int nenner;

public:
    Bruch(int z, int n) : zaehler(z), nenner(n) 
    {}

    string toString()
    {
        ostringstream os;
        os << zaehler << "/" << nenner;
        return os.str();
    }
};

void main()
{
    Bruch b(1,2);
    cout << b.toString() << endl;
}
cu,
bitbieger

tylerD
Beiträge: 4068
Registriert: 10.07.2002 17:34:13
Wohnort: Halle/Saale
Kontaktdaten:

Beitrag von tylerD » 26.05.2004 16:48:49

bitbieger hat geschrieben:
Das ist falsch. Es wird eine Kopie der lokalen Variable zurückgegeben. Ist also kein Problem...
Ich sollte doch nicht soviel von Dingen reden, wovon ich keine Ahnung hab :lol:

Meine Frage nun: das funktioniert aber nur, wenn die Klasse ein Kopierkonstruktor (oder wie heißt das Ding?) hat, oder?
Und kann es sein dass einige Containerklassen (bin mir jetzt nicht sicher ob MFC oder STL) das nicht haben und ich deswegen auf den Trichter komme, dass obiges nicht geht?

So zurück zu Java, da geht das wenigstens, und ich weiß das es geht :-)

cu

Benutzeravatar
The Torso
Beiträge: 882
Registriert: 13.07.2003 12:46:40
Lizenz eigener Beiträge: MIT Lizenz

Beitrag von The Torso » 26.05.2004 23:40:24

So, ich danke euch allen fuer die Hilfe, ich habs jetzt geschaft.

burch.h

Code: Alles auswählen

#ifndef bruch_h
#define bruch_h bruch_h 

#include <string>

using std::string;

class Bruch 
{
 private:
  int zaehler;
  int nenner;
  void kuerzen();

 public:

  Bruch(int z, int n);
  ~Bruch();

  int getZ() const;
  int getN() const;
  void add(Bruch bz);
  void sub(Bruch bz);
  void mul(Bruch bz);
  void div(Bruch bz);
  Bruch copy();
  string toString();

};
#endif 
und die Funktion toString() von bruch.cpp:

Code: Alles auswählen

string Bruch::toString()
{
  int b = 0;
  std::stringstream outStream;

  if (zaehler > nenner && zaehler != 0) 
    {
      int z = zaehler;

      while (z > nenner)
	{
	  z -= nenner;
	  b++;
	}
      outStream << b << " " << z << "/"  << nenner;
    }
  else if (zaehler == 0)
    {
      outStream << zaehler;
    }
  else if (zaehler == nenner) 
    {
      outStream << 1;
    }
  else
    {
      outStream << zaehler << "/" << nenner;
      }

  return outStream.str();
}
So haut alles hin!

Mal abgesehen von dem, dass ich die Methode vollkommen umgeschrieben habe schaut das ganze doch fast aus wie Java-Code, oder? (Mal abgesehen vom outStream - gib's so was in Java?) :D
Debian GNU/Linux 00101010

Benutzeravatar
Joghurt
Beiträge: 5244
Registriert: 30.01.2003 15:27:31
Wohnort: Hamburg
Kontaktdaten:

Beitrag von Joghurt » 27.05.2004 01:57:27

Noch ein Tipp:
The Torso hat geschrieben:

Code: Alles auswählen

  void add(Bruch bz);
  void sub(Bruch bz);
  void mul(Bruch bz);
  void div(Bruch bz);
kannst du in

Code: Alles auswählen

Bruch& operator+=(Bruch& bz)
Bruch& operator-=(Bruch& bz)
etc.
umschreiben

Benutzeravatar
bitbieger
Beiträge: 179
Registriert: 23.10.2003 08:26:00
Kontaktdaten:

Beitrag von bitbieger » 27.05.2004 10:14:06

...und noch ein Tipp :)
Statt einer toString - Funktion kannst du auch den den << Operator überladen. Ich denke, das wäre die 'normale' Vorgehensweise in C++.

Code: Alles auswählen

ostream& ::operator<<(ostream& os, const Bruch& b)
{
     // Funktionalität aus toString() einbauen...
     os << b.getZ() << "/" << b.getN();
     return os;
}
Danach kannst du deine Brüche relativ simpel ausgeben:

Code: Alles auswählen

void main()
{
     Bruch b(1,2);
     cout << b << endl;
}
So bekommt der Bruch keine Aufgaben, die eigentlich nichts mit einem Bruch zu tun haben...

cu,
bitbieger

Benutzeravatar
The Torso
Beiträge: 882
Registriert: 13.07.2003 12:46:40
Lizenz eigener Beiträge: MIT Lizenz

Beitrag von The Torso » 27.05.2004 11:54:16

Ich werde euere Tipps beherzigen, allerdings muss ich bei der Funktion toString() einen String zurueckgeben, das liegt an der Aufgabenstellung!
Debian GNU/Linux 00101010

Antworten