2010-05-16 15 views
5

Ich versuche, meine eigene C++ - String-Klasse für Bildungs- und Bedarfszwecke zu schreiben.
Das erste ist, dass ich nicht viel über Operatoren weiß und deshalb will ich sie lernen. Ich habe angefangen, meine Klasse zu schreiben, aber wenn ich sie starte, blockiert sie das Programm, aber stürzt nicht ab.
Werfen Sie einen Blick auf die folgende Code bitte, bevor Sie weiterlesen:Benutzerdefinierte String-Klasse (C++)

class CString 
{ 
private: 
    char* cstr; 
public: 
    CString(); 
    CString(char* str); 
    CString(CString& str); 
    ~CString(); 

    operator char*(); 
    operator const char*(); 
    CString operator+(const CString& q)const; 
    CString operator=(const CString& q); 
}; 

Zunächst einmal bin ich nicht so sicher, erklärte ich alles richtig gemacht. Ich habe versucht, darüber zu googeln, aber alle Tutorials zum Überladen erklären die grundlegenden Ideen, die sehr einfach sind, aber nicht erklären, wie und wann jedes Ding aufgerufen wird. Zum Beispiel ruft das Programm in my = operator CString auf (CString & str); aber ich habe keine ideea warum.
Ich habe auch die CPP-Datei unten angehängt:

CString::CString() 
{ 
cstr=0; 
} 
CString::CString(char *str) 
{ 
cstr=new char[strlen(str)]; 
strcpy(cstr,str); 
} 
CString::CString(CString& q) 
{ 
if(this==&q) 
    return; 
cstr = new char[strlen(q.cstr)+1]; 
strcpy(cstr,q.cstr); 
} 
CString::~CString() 
{ 
if(cstr) 
    delete[] cstr; 
} 
CString::operator char*() 
{ 
return cstr; 
} 
CString::operator const char*() 
{ 
return cstr; 
} 
CString CString::operator +(const CString &q) const 
{ 
CString s; 
s.cstr = new char[strlen(cstr)+strlen(q.cstr)+1]; 
strcpy(s.cstr,cstr); 
strcat(s.cstr,q.cstr); 
return s; 
} 
CString CString::operator =(const CString &q) 
{ 
if(this!=&q) 
{ 
    if(cstr) 
    delete[] cstr; 
    cstr = new char[strlen(q.cstr)+1]; 
    strcpy(cstr,q.cstr); 
} 
return *this; 
} 

Zum Testen habe ich einen Code genauso einfach wie die
CString a = CString ("Hallo") + CString ("Welt");
Druck (a);
Ich habe versucht, es zu debuggen, aber an einem Punkt werde ich verloren. Zuerst ruft er den Konstruktor 2 mal für "Hallo" und für "Welt" auf. Dann kommt es in den Operator +, was in Ordnung ist. Dann ruft es den Konstruktor für die leere Zeichenfolge auf. Danach wird es in "CString (CString & str)" und jetzt bin ich verloren. Warum passiert dies? Danach bemerkte ich, dass meine Zeichenfolge, die "Hello World" enthält, im Destruktor ist (einige Male in Folge). Wieder bin ich sehr verwirrt. Nach der Konvertierung von char * nach Cstring und vor und zurück stoppt es. Es kommt nie in den Operator =, aber es geht auch nicht weiter. printf (a) wird nie erreicht.
Ich benutze Visual Studio 2010 für diese, aber es ist im Grunde nur Standard C++ Code und sollte daher glaube ich nicht, dass viel Unterschied

+0

ich die Bildungs ​​verstehen, aber was ist mit der „Notwendigkeit“ Zweck? Sie mögen nicht standard std :: string? – Nikko

+0

Ehrlich, nein. Ich träume von Code, der intelligent und einfach zu verwenden ist. Mit Blick auf CPlusplus.com Ich bemerkte, dass std :: string kann etwas tun wie folgt: string a = string ("Hallo") + string ("world") oder string a = String ("Hallo") + "Welt" weil es die + Überladung fehlt. Und mehr daran ist, dass ich in diesem Teil meines Projekts viel mit Strings arbeiten muss und somit einen habe, der alle Funktionen hat, die ich will und wie ich will. Ich hoffe, ich werde nicht dazu verleitet, dies zu sagen. – Sanctus2099

+0

Was Sie wirklich nicht tun können, ist: str3 = "qwe" + "rty"; Im Standard ist der Operator + eine globale Funktion für Strings. Für mich ist es ein Anfängerfehler, einen std :: string neu zu definieren, nur weil Sie es auf Ihre Weise wollen und nicht, dass es einen bestimmten Bedarf gibt. – Nikko

Antwort

4

Die Linie machen:

cstr=new char[strlen(str)]; 

sollte sein:

cstr=new char[strlen(str) + 1]; 

Auch der Test für die Selbstzuweisung ist im Kopierkonstruktor nicht sinnvoll - Sie erstellen ein neues Objekt - es kann möglicherweise nicht die gleiche Adresse wie jedes existierende Objekt haben. Und der Copy-Konstruktor sollte eine const-Referenz als Parameter annehmen,

Wenn Sie in Ihrem Code erwartet haben, dass der Zuweisungsoperator verwendet wird, würden Sie ein falsches Ergebnis erwarten. Dieser Code:

CString a = CString("Hello") + CString(" World"); 

ist im Wesentlichen die gleiche wie:

CString a(CString("Hello") + CString(" World")); 

die Kopie Konstruktion ist nicht Aufgabe. Der temporäre CString "Hallo Welt" wird zerstört (Aufruf des Destruktors), nachdem ein Konstrukt erstellt wurde.

Grundsätzlich klingt es so, als ob Ihr Code mehr oder weniger wie erwartet funktioniert.

+1

+1 Der Scheck für die Selbstaufgabe wurde in GotW # 11 http://www.gotw.ca/gotw/011 vorgestellt. htm Wenn ich mich richtig erinnere, zeigt die neueste Version des Buches, wie man den Test tatsächlich als wahr bewerten kann (ich erinnere mich nicht genau wie, aber ich vermute eine Art Platzierung neu) :) –

+0

Yeah - es war beabsichtigt zu behaupten, dass dies lächerlich sei. Es gibt keinen Grund, eine solche Überprüfung im Kopierkonstruktor durchzuführen, das ist unmöglich. – Puppy

+0

Ja, Sie haben Recht. Der Test für die Selbstzuweisung ist im Konstruktor nicht sinnvoll, da er vor der Erstellung nicht existieren kann. Und danke, dass du auf die Sache mit +1 hingewiesen hast. – Sanctus2099

1

Hier ist was los:

  1. Der Konstruktor in der Tat zweimal aufgerufen wird. Einmal für "Hallo" und einmal für "Welt". Die Reihenfolge ist nicht definiert.
  2. Der CString :: -Operator + wird am ersten CString ("Hallo") aufgerufen und übergibt den zweiten CString ("world") als Argument. Der Rückgabewert von CString :: operator + ist ein neuer CString
  3. Da Sie in Initialisierung zuweisen, d. H.: CString a = [CString result of operator +], wird C++ Sie nur als Kopierkonstruktor aufrufen. Daher der Aufruf an CString(CString&), den Sie im Debugger sehen.

Nun, das ist insgesamt 4 Objekte nur erstellt, eine für jede Stringliteral („Hallo“ und „Welt“), eine für die Verkettung von denen (das Ergebnis des CString::operator + Anrufs, und ein die halten .. Ergebnis (CString a = ...) Jede dieser temporären Objekte wird es destructor genannt haben

Was, warum Sie nicht die printf bekommen, habe ich keine Ahnung, dass ich Ihren Code nur in dieser Datei eingefügt Kopie.

#include <cstdio> 
#include <cstring> 

[your code] 

int main(int argc,char* argv[]) { 
    CString a = CString("hello") + CString(" world"); 
    printf(a); 
} 

Und als ich die resultierende ausführbare Datei lief, bekam ich hello world als Ausgabe. Dies ist auf Ubuntu mit g ++ 4.4. Nicht ganz sicher, warum unter dem VS-Debugger nichts gedruckt wird.

+0

Ich habe von der gleichen Sache, aber anscheinend musste ich Operator const char * eine const Überladung machen – Sanctus2099

3

Verwenden Sie nicht Strlen, speichern Sie Ihre eigene String-Länge. Die Zeichenfolge sollte nicht auf einen Null-Terminator angewiesen sein. Es ist in Ordnung, solche zu verwenden, wenn Sie in einem zufälligen const char * übergeben werden, aber für interne Operationen sollten Sie die Größe verwenden.

Außerdem haben Sie vergessen, Ihren Operator const char * eine konstante Überlast zu machen.

+0

Vielen Dank. Das letzte Stück, von dem du mir erzählt hast, hat es repariert. – Sanctus2099

0

Einige Fehler, die Sie gemacht:

1. Copykonstruktor Signatur falsch ist. Es muss sein:

CString(const CString& q) 

2. op = Unterschrift ist falsch. Es muss sein:

CString& operator=(const CString& q) 

Übrigens, das war auch der Grund, dass der Kopierkonstruktor aufgerufen wurde. Sie haben am Ende eine return *this gemacht, die das Objekt kopiert hat (mit Ihrer op = Signatur).

3. Sie erlauben CString-Instanzen mit cstr == NULL (Ihr Standardkonstruktor führt zu einer solchen Instanz). Obwohl Sie in fast allen Funktionen (Kopierkonstruktor, operator +, operator =) nicht gut umgehen können (q.cstr == NULL).

Vielleicht ist die einfachste und sicherste Weg wäre, nur diesen Fall nicht zu, und Ihr Standard-Konstruktor ändern:

CString::CString() 
{ 
    cstr = new char[1]; 
    cstr[0] = 0; 
} 
+0

Vielen Dank für Ihren Rat. Ich habe die Unterschriften geändert. Die Sache ist, dass ich an verschiedenen Orten verschiedene Signaturen sehe, weshalb ich mir nicht sicher bin, welcher der gute oder "normale" ist. Und ich sehe den Punkt darin, den Standardkonstruktor als null nur beendete Zeichenfolge zu machen. – Sanctus2099

Verwandte Themen