2010-05-16 28 views
5

Sto provando a scrivere la mia classe di stringhe C++ per scopi didattici e di necessità.
La prima cosa è che non ne so molto degli operatori ed è per questo che voglio impararli. Ho iniziato a scrivere il mio corso, ma quando lo eseguo blocca il programma ma non fa alcun crash.
Date un'occhiata al seguente codice di favore, prima di leggere oltre:Classe stringa personalizzata (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); 
}; 

Prima di tutto io non sono così sicuro dichiarai tutto per bene. Ho provato googleing a riguardo ma tutti i tutorial sull'overloading spiegano l'ideea di base che è molto semplice ma non spiega come e quando ogni cosa viene chiamata. Ad esempio nel mio operatore = il programma chiama CString (CString & str); ma non ho ideea perché.
Ho anche allegato il file cpp di seguito:

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; 
} 

Per la prova ho usato un codice altrettanto semplice come questo
CString a = CString ("Ciao") + CString ("World");
printf (a);
Ho provato a debuggarlo ma a un certo punto mi sono perso. Prima chiama il costruttore 2 volte per "ciao" e per "mondo". Quindi entra nell'operatore + che sta bene. Quindi chiama il costruttore per la stringa vuota. Dopodiché entra in "CString (CString & str)" e ora sono perso. Perché sta succedendo? Dopo ciò ho notato che la mia stringa contenente "Hello World" si trova nel distruttore (alcune volte di seguito). Di nuovo sono molto confuso. Dopo la conversione di nuovo da char * a Cstring e avanti e indietro si ferma. Non entra mai nell'operatore =, ma non va oltre. printf (a) non viene mai raggiunto.
Io uso VisualStudio 2010 per questo, ma è fondamentalmente codice appena standard di C++ e quindi non credo che si dovrebbe fare che molta differenza

+0

Capisco la didattica, ma per quanto riguarda lo scopo "bisogno"? Non ti piace standard std :: string? – Nikko

+0

Francamente, no. Sogno un codice che sia intelligente e facile da usare. Guardando CPlusplus.com ho notato che std :: string non può fare qualcosa del genere: string a = string ("Hello") + string ("world") o string a = String ("Hello") + "World" perché manca il sovraccarico +. E in più su questo devo lavorare molto con le stringhe in questa parte del mio progetto e quindi preferisco avere una che abbia tutte le funzioni che voglio e come voglio. Spero di non sentirmi indolenzito per aver detto questo. – Sanctus2099

+0

Ciò che in realtà non si può fare è: str3 = "qwe" + "rty"; Nello standard l'operatore + è una funzione globale per le stringhe. Per me, è un errore da principiante ridefinire una std :: string solo perché la vuoi a modo tuo e non che ci sia un bisogno specifico. – Nikko

risposta

4

La linea: dovrebbe essere

cstr=new char[strlen(str)]; 

:

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

Inoltre, il test per l'autoassegnazione non ha senso nel costruttore di copie - si sta creando un nuovo oggetto - non può possibilmente avere lo stesso indirizzo di qualsiasi oggetto esistente. E il costruttore di copie dovrebbe prendere un riferimento const come parametro,

Se nel codice si aspettava che l'operatore di assegnazione fosse usato, ci si aspetterebbe che fosse sbagliato. Questo codice:

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

è essenzialmente lo stesso come:

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

che è copia costruzione, non assegnazione. Il CString temporaneo "Hello world" sarà distrutto (invocando il distruttore) dopo che è stato costruito.

Fondamentalmente, sembra che il codice funzioni più o meno come previsto.

+1

+1 Il controllo per l'autoassegnazione è stato pubblicato su GotW # 11 http://www.gotw.ca/gotw/011. htm Se ricordo bene, l'ultima versione del libro mostra come si possa effettivamente fare il test per valutare il vero però (non ricordo esattamente come ma indovino una sorta di posizionamento nuovo) :) –

+0

Sì - era inteso suggerire che fare questo fosse ridicolo. Non c'è motivo di eseguire tale controllo nel costruttore di copie, è impossibile. – Puppy

+0

Sì, hai ragione. Il test per l'autoassegnazione non ha senso nel costruttore poiché non può esistere prima di crearlo. E grazie per aver segnalato la cosa +1. – Sanctus2099

1

Ecco quello che sta succedendo:

  1. Il costruttore è infatti chiamato due volte. Una volta per "ciao" e una volta per "mondo". L'ordine non è definito.
  2. CString :: operator + viene chiamato al primo CString ("ciao"), passando il secondo CString ("mondo") come argomento. Il valore di ritorno di CString :: operator + è un nuovo CString
  3. Poiché si sta assegnando in fase di inizializzazione, ovvero: CString a = [CString result of operator +], C++ chiamerà semplicemente il costruttore di copie. Da qui la chiamata a CString(CString&) che stai vedendo nel debugger.

Ora, che è 4 oggetti totale appena creati, uno per ogni stringa letterale ("ciao", e "mondo"), uno per la concatenazione di coloro (il risultato della chiamata CString::operator +, e uno per tenere il .. risultato (CString a = ...) Ognuno di questi oggetti temporanei avrà è distruttore chiama

per quanto riguarda il motivo per cui non stai ricevendo il printf, non ho idea di che basta copiare e incollato il codice in questo file:.

#include <cstdio> 
#include <cstring> 

[your code] 

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

E quando ho eseguito l'eseguibile risultante, ho ottenuto hello world come output. Questo è su Ubuntu con g ++ 4.4. Non è esattamente sicuro perché sotto il debugger VS non sta stampando nulla.

+0

Ho pensato alla stessa cosa ma a quanto pare ho dovuto rendere l'operatore const char * a const sovraccarico – Sanctus2099

3

Non utilizzare strlen, memorizzare la lunghezza della propria stringa. La stringa non dovrebbe essere dipesa per avere un terminatore nullo. Va bene usarlo se passi in un const char casuale *, ma per le operazioni interne, devi usare la dimensione.

Inoltre, hai dimenticato di rendere il tuo operatore const char * un sovraccarico const.

+0

Grazie mille. L'ultimo pezzo che mi hai detto di averlo risolto. – Sanctus2099

0

Alcuni errori commessi:

1. La firma del costruttore della copia è errata. Deve essere:

CString(const CString& q) 

2. op = firma è errata. Deve essere:

CString& operator=(const CString& q) 

Btw., Questo era anche il motivo per cui è stato chiamato il costruttore di copie. Hai fatto un return *this alla fine che ha copiato l'oggetto (con la tua op = firma).

3. Consenti alle istanze CString con cstr == NULL (il costruttore predefinito genererà tale istanza). Sebbene, in quasi tutte le funzioni (copy constructor, operator +, operator =) non si gestisca bene il caso (q.cstr == NULL).

Forse il modo più semplice e più sicuro sarebbe quello di non consentire solo quel caso e cambiare il costruttore di default a:

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

Grazie per il vostro consiglio. Ho cambiato le firme. Il fatto è che in posti diversi vedo diverse sigle, ecco perché non sono sicuro quale sia quella buona o "standard". E vedo il punto nel rendere il costruttore predefinito come una stringa terminata solo null. – Sanctus2099

Problemi correlati