View Full Version : [C++]: Dati char e string di una classe
Ciao a tutti ragazzi
vorrei un vostro aiuto per capire.
Quando ho una classe Notebook con dei membri char
vado a definire il costruttore in questo modo
class Notebook
{
private:
char*modello;
float peso;
float spessore;
float pollici;
public:
Notebook(char*, float, float, float);
virtual void StampaDati()const;
};
Quando vado a implementare il costruttore avrò
Notebook::Notebook(char* mod, float ps, float spes, float mon)
{
modello=new char[strlen(mod)+1];
strcpy(modello, mod);
peso=ps;
spessore=spes;
pollici=mon;
}
Se invece ho una classe con dati string
class Notebook
{
private:
string modello;
float peso;
float spessore;
float pollici;
public:
Notebook(string, float, float, float);
virtual void StampaDati()const;
};
vado ad implementare
Notebook::Notebook(string mod= " ", float ps, float spes, float mon)
{
Modello=mod;
peso=ps;
spessore=spes;
pollici=mon;
}
Se invece avessi una string allocata dinamicamente, come andrebbe implementato il costruttore?
[Kendall]
25-07-2012, 12:19
Se invece avessi una string allocata dinamicamente, come andrebbe implementato il costruttore?
class Notebook
{
private:
string* modello;
float peso;
float spessore;
float pollici;
public:
Notebook(char*, float, float, float);
virtual void StampaDati()const;
};
Notebook::Notebook(string &mod, float ps, float spes, float mon)
{
modello = new string(mod);
peso = ps;
spessore = spes;
pollici = mon;
}
oppure
Notebook::Notebook(string *mod, float ps, float spes, float mon)
{
modello = mod;
peso = ps;
spessore = spes;
pollici = mon;
}
Nel primo gli dai in pasto una stringa per valore e crei dinamicamente l'istanza di stringa dentro al costruttore.
Nel secondo caso l'istanza di stringa è stata già creata quindi tu gli passi solo il puntatore e lo copi ne relativo campo modello (questa seconda versione però te la sconsiglio perchè permette di modificare la stringa modello anche dall'esterno della classe).
Grazie mille Kendall del chiarimento
avrei dei dubbi:
nell'implementazione non ci vuole una cosa tipo strcpy(modello , char)
Notebook::Notebook(string &mod, float ps, float spes, float mon)
{
modello = new string(mod); //questa istruzione non crea solo spazio?
strcpy(modello , char)
peso = ps;
spessore = spes;
pollici = mon;
}
e se facessi un ibrido è scorretto?
mi spiego:
class Notebook
{
private:
string* modello;
float peso;
float spessore;
float pollici;
public:
Notebook(string*, float, float, float);
virtual void StampaDati()const;
};
facendo così è come se la stringa fosse statica?
Notebook::Notebook(string mod=" ", float ps, float spes, float mon)
{
modello = new string(mod);
peso = ps;
spessore = spes;
pollici = mon;
}
[Kendall]
25-07-2012, 13:28
Grazie mille Kendall del chiarimento
avrei dei dubbi:
nell'implementazione non ci vuole una cosa tipo strcpy(modello , char)
La funzione strcpy serve solo per la copia di stringhe in formato c.
Nel momento stesso in cui ti affidi alla classe string ti astrai da questo tipo di considerazioni (anche se internamente all'implementazione di string vengono utilizzate queste funzioni di basso livello).
Nel caso particolare al costruttore di string dai come argomento il valore di "mod"
che verrà utilizzato da string per assegnare al tuo campo "modello" una nuova istanza con il valore indicato da mod.
bender86
25-07-2012, 19:50
Non vedo distruttori... Se nel costruttore allochi qualcosa con new (o new[]) devi anche deallocarlo con delete (o delete[]) nel distruttore. Inoltre sarebbe meglio usare le liste di inizializzazione.
Notebook::Notebook(char* mod, float ps, float spes, float mon)
: modello(0),
peso(ps),
spessore(spes),
pollici(mon)
{
modello = new char[strlen(mod)+1];
strcpy(modello, mod);
}
Notebook::~Notebook()
{
delete [] modello;
}
e se facessi un ibrido è scorretto?
Non è che sia scorretto, ma quale sarebbe il vantaggio rispetto ad usare (std::)string? In linea di massima se puoi fare una cosa senza usare puntatori, new e delete quello è il modo migliore per farla.
nell'implementazione non ci vuole una cosa tipo strcpy(modello , char)
Codice:
modello = new string(mod); //questa istruzione non crea solo spazio?
strcpy(modello , char);
Stai chiamando il costruttore di copia di 'string'. Il costruttore di copia dovrebbe costruire una copia di un oggetto, quindi a 'modello' viene assegnata una copia di 'mod'.
Ho detto "dovrebbe" perché non è che sia obbligatorio, ma normalmente è così (per std::string è così di sicuro).
tomminno
25-07-2012, 23:00
Come la scriverei io:
class Notebook
{
private:
std::string modello;
float peso;
float spessore;
float pollici;
public:
Notebook(const std::string &, float, float, float);
virtual ~Notebook(); //Dato che hai definito un metodo virtuale... In ogni caso un distruttore virtuale male non fa :D
virtual void StampaDati()const;
};
Notebook::Notebook(const std::string & mod, float ps, float spes, float mon) : modello(mod), peso(ps), spessore(spes), pollici(mon)
{ }
Allocare dinamicamente std::string secondo me non ha molto senso, è solo un contenitore per qualcosa che è già allocato dinamicamente.
ciao ragazzi
grazie per avermi risposto
ovviamente per l'estensione dinamica ci vuole il ditruttore, ma non l'avevo messo poichè non era quello il punto
questo comando " std::string " non l'ho mai visto. che cosa fa di preciso?
questo è bello, ma se ho appunto un char *........
Notebook::Notebook(char* mod, float ps, float spes, float mon)
: modello(0),
peso(ps),
spessore(spes),
pollici(mon)
{
modello = new char[strlen(mod)+1];
strcpy(modello, mod);
}
Notebook::~Notebook()
{
delete [] modello;
}
lorenzo001
26-07-2012, 20:17
Non è un "comando"
std::string
è una classe della libreria standard, usata per istanziare oggetti stringa standard del C++
[Kendall]
26-07-2012, 21:27
Esattamente come dice Lorenzo.
Per dirla in maniera alternativa, l' "std" è il namespace standard che raccoglie tutte le classi standard (per l'appunto). Quindi come tu, in ogni qual caso crei un namespace utilizzi lo specificatore di namespace (il " :: " ) così fai con quello standard (non vi è alcuna differenza alcuna). L'alternativa più comune è quella di includere il namespace con la ben nota dicitura " #include namespace std"
Ma come ti è stato detto tutto ciò riguardo solo e semplicemente il sistema di namespace.
__ZERO_UNO__
26-07-2012, 23:33
;37863453'] L'alternativa più comune è quella di includere il namespace con la ben nota dicitura " #include namespace std"
La ben nota dicitura non è "using namespace std", o sbaglio?
[Kendall]
27-07-2012, 10:31
La ben nota dicitura non è "using namespace std", o sbaglio?
Uops, touchè... Ultimamente mi sto dedicando al C# dove si utilizza sempre l' "#include" (anche se in senso leggermente diverso dal concetto di namespace), da questo l'errore.
Hai ovviamente ragione tu ;)
__ZERO_UNO__
27-07-2012, 10:40
La qualità dei tuoi interventi sul forum mi ha fatto pensare che potessi essere io a sbagliarmi e che mi fossi rimbambito, quindi ho messo il punto di domanda.:D
[Kendall]
27-07-2012, 12:06
La qualità dei tuoi interventi sul forum mi ha fatto pensare che potessi essere io a sbagliarmi e che mi fossi rimbambito, quindi ho messo il punto di domanda.:D
Ti ringrazio :)
ok grazie ragazzi
rileggendo il codice di bender
Notebook::Notebook(char* mod, float ps, float spes, float mon)
: modello(0),
peso(ps),
spessore(spes),
pollici(mon)
{
modello = new char[strlen(mod)+1];
strcpy(modello, mod);
}
non è simile al mio modo ibrido?
mi spiego : con l' inizializzatore :modello(0)
nn è lo stesso di mettere
Notebook::Notebook(string mod= " ", float ps, float spes, float mon)
e poi un'altra particolarità
{
modello = new char[strlen(mod)+1];
strcpy(modello, mod);
}
oppure questa
{
modello = new char(mod);
strcpy(modello, mod);
}
non sono due cose diverse visto che in una si utilizza strlen per vedere la lunghezza di mod?
[Kendall]
27-07-2012, 14:01
non è simile al mio modo ibrido?
mi spiego : con l' inizializzatore :modello(0)
nn è lo stesso di mettere
Notebook::Notebook(string mod= " ", float ps, float spes, float mon)
No, son due cose decisamente diverse. Nel primo caso, cioè nell'inizializzazione "modello(0)" vai ad assegnare al puntatore char modello il valore di zero, ossia equivale ad un
modello = 0;
oppure
modello = NULL;
oppure (in c++11)
modello = nullptr;
e poi un'altra particolarità
{
modello = new char[strlen(mod)+1];
strcpy(modello, mod);
}
oppure questa
{
modello = new char(mod);
strcpy(modello, mod);
}
non sono due cose diverse visto che in una si utilizza strlen per vedere la lunghezza di mod?
Si sono due cose decisamente diverse perchè si riferiscono a due casi diversi. Nel primo stai assegnando ad un puntatore di char un array di char di lunghezza pari a mod (mod è una stringa stile c). Dopodichè tramite strcpy ne copi il contenuto.
Il secondo esempio invece è semplicemente errato, in quanto al puntatore a char modello vai ad assegnare un singolo char allocato dinamicamente (tra l'altro char(mod) è un costrutto non valido in quanto non puoi costruire un char da un char* (che sarebbe mod) ).
Dopodichè strcpy si troverebbe a copiare una stringa stile c di n caratteri in una puntatore che punta ad un solo carattere, e andresti pertanto in overflow.
tomminno
27-07-2012, 14:46
non è simile al mio modo ibrido?
mi spiego : con l' inizializzatore :modello(0)
nn è lo stesso di mettere
Notebook::Notebook(string mod= " ", float ps, float spes, float mon)
Il codice che hai scritto te è differente, il suo significato è: se non passi mod il suo valore è automaticamente assegnato a spazio. Ed è sbagliato perchè o lo sposti come ultimo parametro oppure assegni un valore di default anche agli altri.
Il codice che utilizza le liste di inizializzazione indica invece che alla variabile locale verrà assegnato il valore 0.
e poi un'altra particolarità
{
modello = new char[strlen(mod)+1];
strcpy(modello, mod);
}
oppure questa
{
modello = new char(mod);
strcpy(modello, mod);
}
non sono due cose diverse visto che in una si utilizza strlen per vedere la lunghezza di mod?
La seconda che hai scritto te è proprio sbagliata.
Ma dato che parliamo di C++ perchè insistere con gli array di char???
ragazzi è perchè non ho mai visto programmi che prevedono l'allocazione di stringhe dinamiche e quindi non so come fare quando si presenta un problema simile
[Kendall]
27-07-2012, 19:38
ragazzi è perchè non ho mai visto programmi che prevedono l'allocazione di stringhe dinamiche e quindi non so come fare quando si presenta un problema simile
Le tratti come tratteresti le istanze di una qualsiasi altra classe (visto che di per sè, string è proprio una classe come tutte le altre, solo fa parte della libreria standard)
bender86
28-07-2012, 11:04
Esattamente cosa intendo per "stringa dinamica"? In C le stringhe non esistono, quindi si deve ricorrere ad array di caratteri spesso allocati dinamicamente. In C++ invece c'è la classe 'std::string' che non ha quasi mai bisogno di essere allocata dinamicamente (la si dovrebbe usare esattamente come un int o un double).
Se stai seguendo un corso potrebbe essere una buona idea chiedere un chiarimento al professore.
Il namespace std contiene tutta la libreria standard del C++. I namespace permettono di dare lo stesso nome a variabili, funzioni, classi... diverse. Ad esempio nella libreria standard c'è la classe 'list' (std::list) che rappresenta una lista. Magari tu vuoi implementare una classe lista che funzioni in maniera diversa. Non puoi chiamarla 'list' dato che il nome è già usato, quindi devi trovare un altro nome; in C la soluzione tipica è quella di aggiungere prefissi: 'Bandit_List', che è terribile.
Usando i namespace invece classi in diversi namespace possono avere lo stesso nome: 'std::list', 'bandit::list'. Il vantaggio è che all'interno del namespace 'bandit' puoi usare semplicemente il nome 'list', il compilatore sa che ti stai riferendo alla classe nel namespace corrente. Inoltre se sei sicuro di non usare classi con lo stesso nome puoi importare i nomi di un namespace in quello corrente usando 'using namespace abc;'.
#include <list> // Definisce std::list.
namespace bandit {
class list...
void t()
{
std::list<int> a;
list<int> b; // Equivalente a bandit::list<int> b.
}
} // fine del namespace bandit
// Qui siamo nel namespace globale (cioè fuori da qualsiasi namespace).
int main()
{
std::list<int> a;
bandit::list<int> b;
using namespace std; // Importa i simboli del namespace 'std' in quello corrente.
list<int> c; // Equivalente a std::list<int> c.
} // Qua termina l'effetto di 'using namespace std;'.
int altro()
{
using namespace bandit; // Importa i simboli del namespace 'bandit' in quello corrente.
list<int> a; // Equivalente a bandit::list<int> a.
}
int ultimo()
{
using namespace std;
using namespace bandit;
list<int> a; // Errore, a quale ti riferisci?
std::list<int> b; // Ok
bandit::list<int> b; // Ok
}
vBulletin® v3.6.4, Copyright ©2000-2026, Jelsoft Enterprises Ltd.