PDA

Visualizza la versione completa : [C++] Costruttori definiti fuori o dentro la classe


vicio_93
04-01-2015, 11:22
Salve Ragazzi, non capisco perchè ho sempre problemi quando definisco i costruttori fuori dal corpo classe:


//Persona.h
#ifndef PERSONA_H
#define PERSONA_H
#include "Data.h"
using namespace std;

class Persona{
public:
Persona();
Persona(string,string,Data);
virtual void print()=0;
protected:
string nome;
string cognome;
Data date;
};

class Studente : public Persona{
public:
Studente ();
Studente (string a, string b, Data c, string d);
virtual void print();
~Studente();
protected:
string CDL;
};

class Docente : public Persona{
public:
Docente ();
Docente (string a,string b,Data c,string d);
virtual void print();
~Docente();
private:
string Materia;
};

class StudenteSpecialista : public Studente{
public:
StudenteSpecialista ();
StudenteSpecialista (string,string,Data,string,string);
virtual void print();
~StudenteSpecialista();
private:
string LT;
};

#endif




//Persona.cpp
#include <iostream>
#include "Persona.h"
#include "Data.h"
using namespace std;


Persona::Persona(){
nome="-";
cognome="-";
}

Persona::Persona(string a, string b, Data c){
nome=a;
cognome=b;
date=c;
}



Studente::Studente(){
Persona();
CDL="-";
}

Studente::Studente(string a,string b,Data c,string d){
Persona(a,b,c);
CDL=d;
}

void Studente::print(){
cout<<nome<<endl<<cognome<<endl<<date<<endl<<CDL<<endl<<endl;
}

Docente::Docente(){
Persona();
Materia="-";
}

Docente::Docente(string a, string b, Data c, string d){
Persona (a,b,c);
Materia=d;
}

Studente::~Studente(){
cout<<"Distruttore"<<endl;
}

Docente::~Docente(){
cout<<"Distruttore"<<endl;
}



||=== Build: Debug in ese5 (compiler: GNU GCC Compiler) ===|
C:\Users\Vinc\Desktop\Bill\Bill_ese_9\ese5\Persona .cpp||In constructor 'Studente::Studente()':|
C:\Users\Vinc\Desktop\Bill\Bill_ese_9\ese5\Persona .cpp|21|error: cannot allocate an object of abstract type 'Persona'|
C:\Users\Vinc\Desktop\Bill\Bill_ese_9\ese5\Persona .h|6|note: because the following virtual functions are pure within 'Persona':|
C:\Users\Vinc\Desktop\Bill\Bill_ese_9\ese5\Persona .h|10|note: virtual void Persona::print()|
C:\Users\Vinc\Desktop\Bill\Bill_ese_9\ese5\Persona .cpp||In constructor 'Studente::Studente(std::string, std::string, Data, std::string)':|
C:\Users\Vinc\Desktop\Bill\Bill_ese_9\ese5\Persona .cpp|26|error: cannot allocate an object of abstract type 'Persona'|
C:\Users\Vinc\Desktop\Bill\Bill_ese_9\ese5\Persona .h|6|note: since type 'Persona' has pure virtual functions|
C:\Users\Vinc\Desktop\Bill\Bill_ese_9\ese5\Persona .cpp||In member function 'virtual void Studente::print()':|
C:\Users\Vinc\Desktop\Bill\Bill_ese_9\ese5\Persona .cpp|31|error: cannot bind 'std::basic_ostream<char>::__ostream_type {aka std::basic_ostream<char>}' lvalue to 'std::basic_ostream<char>&&'|
c:\program files\codeblocks\mingw\lib\gcc\mingw32\4.8.1\inclu de\c++\ostream|602|error: initializing argument 1 of 'std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char; _Traits = std::char_traits<char>; _Tp = Data]'|
C:\Users\Vinc\Desktop\Bill\Bill_ese_9\ese5\Persona .cpp||In constructor 'Docente::Docente()':|
C:\Users\Vinc\Desktop\Bill\Bill_ese_9\ese5\Persona .cpp|35|error: cannot allocate an object of abstract type 'Persona'|
C:\Users\Vinc\Desktop\Bill\Bill_ese_9\ese5\Persona .h|6|note: since type 'Persona' has pure virtual functions|
C:\Users\Vinc\Desktop\Bill\Bill_ese_9\ese5\Persona .cpp||In constructor 'Docente::Docente(std::string, std::string, Data, std::string)':|
C:\Users\Vinc\Desktop\Bill\Bill_ese_9\ese5\Persona .cpp|40|error: cannot allocate an object of abstract type 'Persona'|
C:\Users\Vinc\Desktop\Bill\Bill_ese_9\ese5\Persona .h|6|note: since type 'Persona' has pure virtual functions|
||=== Build finished: 6 error(s), 0 warning(s) (0 minute(s), 1 second(s)) ===|


il main è un semplice file di prova..


//main.cpp
#include <iostream>
#include "Persona.h"
#include "Data.h"
using namespace std;

int main(){
Studente l;
Docente d;
}

shodan
04-01-2015, 13:22
Perché stai sbagliando:


Studente::Studente(string a,string b,Data c,string d){
Persona(a,b,c); // non ha proprio senso.
CDL=d;
}

Nello specifico stai creando un oggetto Persona all'interno del costruttore di Studente. E persona è una classe virtuale pura.
Per passare i parametri da classe derivata a classe base dev'essere:


Studente::Studente(string a,string b,Data c,string d) : Persona(a,b,c) {
CDL=d;
}

E se non fornisci un'implementazione a Docente:: print() avrai un altro errore.

vicio_93
05-01-2015, 11:59
Grazie per la risposta.. E se ometto Il "Persona(a,b,c)" dopo i due punti è un errore? Non dovrebbe inizializzare a,b,c, di default?

shodan
05-01-2015, 13:05
Grazie per la risposta.. E se ometto Il "Persona(a,b,c)" dopo i due punti è un errore?
Se il costruttore della classe derivata è parametrico è obbligatorio passare i parametri al costruttore parametrico della classe base.

Se non usi il costruttore parametrico, la chiamata è implicita.


Non dovrebbe inizializzare a,b,c, di default?

E a cosa dovrebbe inizializzarli? Con quello che vuoi tu o con quello che vuole lui? Riflettici un po' su. :)

vicio_93
14-01-2015, 18:36
Grazie 1000 :)

vicio_93
14-01-2015, 18:40
A che ci sono chiedo subito un'altra cosa: perchè quando utilizzo un metodo set per settare un certo parametro devo passare per forza per valore:


void Persona::SetNome(string a){
nome=a;
}

Non si può passare per riferimento?


Poi string Persona::GetNome()const{
return nome;
}

non posso fare la stessa cosa, cioè quella di ritornare per riferimento? Grazie in anticipo :)

minomic
14-01-2015, 19:19
Non mi risulta che sia così. Infatti guarda questo piccolo esempio:



#include <iostream>

class Numero
{
public:
Numero() {};

void setNumero(int& num) {numero = num;}
const int& getNumero() {return numero;}

private:
int numero;
};


int main(int argc, char const *argv[])
{
Numero n;
int v = 1;

n.setNumero(v);

const int& a = n.getNumero();

std::cout << "Numero: " << a << std::endl;
return 0;
}




Poi, ci sono ovviamente dei problemi. Ad esempio, nell'esempio sopra non puoi fare



n.setNumero(2);



perché devi comunque passare un int&.

vicio_93
14-01-2015, 21:46
Va bene. Per ultimo quando per esempio invoco il costruttore di una classe base per una derivata se utilizzo gli stesso nomi posso avere un conflitto di nomi?

es.


Persona::Persona(string a, string b, string c){...}

Studente::Studente (string a, string b, string c, string d) : Persona (a,b,c){...}

vicio_93
14-01-2015, 22:08
Poi quando compilo mi da un errore nella get dicendo che devo ritornare un riferimento a costante no un riferimento semplice..
mi spiego..

quando scrivo


const string& Persona::getnome()const{
return nome;
}

il programma compila, mentre quando levo il const iniziale no. Perchè? string nome non è costante.
Possibile che quando metto il const iniziale significa che l'oggetto ritornato non è stato modificato e non come penso io che l'oggetto ritornato è costante?

Scusate troppe domande lo so ahahhah

MItaly
15-01-2015, 08:45
Va bene. Per ultimo quando per esempio invoco il costruttore di una classe base per una derivata se utilizzo gli stesso nomi posso avere un conflitto di nomi?

es.


Persona::Persona(string a, string b, string c){...}

Studente::Studente (string a, string b, string c, string d) : Persona (a,b,c){...}
Perché dovrebbe dare problemi? È concettualmente equivalente a chiamare una normale funzione, le espressioni che passi come argomenti non c'entrano nulla con il nome dei parametri usati dentro la funzione.


Poi quando compilo mi da un errore nella get dicendo che devo ritornare un riferimento a costante no un riferimento semplice..
mi spiego..

quando scrivo


const string& Persona::getnome()const{
return nome;
}

il programma compila, mentre quando levo il const iniziale no. Perchè? string nome non è costante.
Possibile che quando metto il const iniziale significa che l'oggetto ritornato non è stato modificato e non come penso io che l'oggetto ritornato è costante?

Scusate troppe domande lo so ahahhah
Se marchi un metodo come const, allora il this che ricevi è const, per cui tutti i membri "appaiono" come const. Per questo motivo non puoi restituire un riferimento non costante a nome, dato che this->nome in un metodo const è di tipo const std::string&.

Per inciso, quando posti codice racchiudilo tra tag
... , altrimenti perde l'indentazione e non si attiva l'evidenziazione della sintassi (ora ho corretto io).

Loading