herança e polimorfismo
………..ficha7, exercicio1 (a19)
#include <string> #include <iostream> #include <sstream> #include <vector> #include <regex> #include <initializer_list> #include <fstream> using namespace std; class Imovel { float preco; float area; string codigo; static int ordem; //para formar o codigo //para ser usado por classes derivadas protected: //nao deixamos o codigo exterior alterar, mas apenas as classes derivadas void setCodigo(const string& c); public: Imovel(float p, float a); virtual ~Imovel(); float getPreco() const; void setPreco(const float preco); float getArea() const; string getCodigo() const; static int getOrdem(); virtual string getAsString()const; }; ostream& operator << (ostream& saida, const Imovel& i); //operador do cout int Imovel::ordem = 0; void Imovel::setCodigo(const string& c) { codigo = c; } Imovel::Imovel(float p, float a):preco(p), area(a) { //ou //ostringstream oss; //oss << (++ordem); //codigo = oss.str(); //ou codigo = to_string(++ordem); } Imovel::~Imovel() { } float Imovel::getPreco() const { return preco; } void Imovel::setPreco(const float preco) { this->preco = preco; } float Imovel::getArea() const { return area; } string Imovel::getCodigo() const { return codigo; } int Imovel::getOrdem() { return ordem; } string Imovel::getAsString() const { ostringstream oss; oss << " codigo: " << codigo << "\n preco: " << preco << "\n area " << area << endl; return oss.str(); } ostream& operator<<(ostream& saida, const Imovel& i) { saida << i.getAsString(); return saida; } //apartamento deriva de imovel, : public .. e recebe por herança class Apartamento : public Imovel { int numeroAssoalhadas; int andar; public: Apartamento(float area0, int andar0, int numeroAssoalhadas0); //getAstring é por herança //precisa de ser redifinida com o override string getAsString()const override; }; //o construtor d euma classe derivada já manda executar o construtor da calsse base: Imovel Apartamento::Apartamento(float area0, int andar0, int numeroAssoalhadas0):Imovel(10* area0, area0), andar(andar0),numeroAssoalhadas(numeroAssoalhadas0) { setCodigo("apartamento-" + getAsString()); } string Apartamento::getAsString() const { ostringstream oss; //preco area -Imovel::getAsString() oss << "apartamento \n" << Imovel::getAsString() << " andar: " << andar << "\n n. assoalhadas: " << numeroAssoalhadas << endl; return oss.str(); } class LojaComercial : public Imovel { //nao tem membros privados public: LojaComercial(float area); string getAsString()const override; }; LojaComercial::LojaComercial(float area):Imovel(15*area, area) { setCodigo("lojaComercial-" + getAsString()); } string LojaComercial::getAsString() const { ostringstream oss; //preco area -Imovel::getAsString() oss << "lojaComercial \n" << Imovel::getAsString() << " andar: R/C" << endl; return oss.str(); } class Imobiliaria { //"não deve utilizar uma estrutura de dados para cada tipo diferente de bem imobiliário" //não usar multiplos vectores, um para cada tipo, mas um para todos //assim: vector<Imovel*> imoveis; //coleção de vários tipos de imoveis //um ponteiro de uma classe derivada pode apontar para a classe base, upcasting //relação entre imobiliaria e imoveis : agregação string nome; int pesquisa(string codigo)const; public: Imobiliaria(string nome); void acrescentaImovel(Imovel* imovel); //recebemos um imovel qualquer //ponteiro para a base bool setPreco(string codigo, float preco); float getPreco(string codigo)const; bool remover(string codigo); string getAsString()const; string getAsString(string codgio0)const; }; ostream& operator << (ostream& saida, const Imobiliaria& i); //operador do cout int Imobiliaria::pesquisa(string codigo) const { for(unsigned int i = 0; 0 < imoveis.size() ; i++) { if(codigo == imoveis[i]->getCodigo()) { return i; } } return -1; } Imobiliaria::Imobiliaria(string nome):nome(nome) { } void Imobiliaria::acrescentaImovel(Imovel* imovel) { if(imovel != nullptr) { //pode surigr uma loja ou apartamento imoveis.push_back(imovel); } } bool Imobiliaria::setPreco(string codigo, float preco) { if (preco < 0){ return false; } int qual = pesquisa(codigo); if (qual == -1) { return false; } imoveis[qual]->setPreco(preco); return true; } float Imobiliaria::getPreco(string codigo) const { int qual = pesquisa(codigo); if(qual == -1) { return 0; } return imoveis[qual]->getPreco(); } bool Imobiliaria::remover(string codigo) { int qual = pesquisa(codigo); if(qual == -1) { return false; } //relação de agregação faz-se apenas o erase imoveis.erase(imoveis.begin() + qual); return true; } string Imobiliaria::getAsString() const { ostringstream oss; oss << "Imobiliaria " << nome << endl; for(unsigned int i = 0; i < imoveis.size(); i++) { oss << imoveis[i]->getAsString() << endl; } return oss.str(); } string Imobiliaria::getAsString(string codgio0) const { int qual = pesquisa(codgio0); if(qual == -1) { return "codigo nao existe"; } return imoveis[qual]->getAsString(); } ostream& operator<<(ostream& saida, const Imobiliaria& i) { saida << i.getAsString(); return saida; } //extra Interaccao class Interaccao { Imobiliaria* imobiliaria; //classe que envolve toda a lógica public: Interaccao(Imobiliaria* imobiliaria0); int escolheOpcao(vector<string> opcoes); int lerInt(string msg); float lerFloat(string msg); void opcaoAcrescentarApartamento(); void opcaoAcrescentarLoja(); void opcaoPesquisarImovelPorCodigo(); void opcaoPesquisarPrecoDeImovelPorCodigo(); void opcaoActualizarPrecoDeImovelPorCodigo(); void opcaoRemoverImovelPorCodigo(); void corre(); }; Interaccao::Interaccao(Imobiliaria* imobiliaria0) { imobiliaria = imobiliaria0; } int Interaccao::escolheOpcao(vector<string> opcoes) { for (unsigned int i = 0; i < opcoes.size(); i++) cout << endl << i << " - " << opcoes[i]; int opcao = -1; do { opcao = lerInt("\n\nopcao > "); } while (opcao < 0 || opcao > opcoes.size()); return opcao; } int Interaccao::lerInt(string msg) { int valor; bool leu = false; do { cout << msg; string s; cin >> s; istringstream iss(s); if (iss >> valor) // se correu bem a leitura leu = true; } while (!leu); return valor; } float Interaccao::lerFloat(string msg) { float valor; bool leu = false; do { cout << msg; string s; cin >> s; istringstream iss(s); if (iss >> valor) // se correu bem a leitura leu = true; } while (!leu); return valor; } void Interaccao::opcaoAcrescentarApartamento() { float area; int andar; int nAss; cout << "\nAcrescentar apartamento"; area = lerFloat(" area: "); andar = lerInt(" andar: "); nAss = lerInt(" n. de assoalhadas: "); imobiliaria->acrescentaImovel(new Apartamento(area, andar, nAss)); } void Interaccao::opcaoAcrescentarLoja() { float area; cout << "\nAcrescentar loja: "; area = lerFloat(" area: "); imobiliaria->acrescentaImovel(new LojaComercial(area)); } void Interaccao::opcaoPesquisarImovelPorCodigo() { string codigo; cout << "\nPesquisar imovel por codigo\n codigo: "; cin >> codigo; cout << imobiliaria->getAsString(codigo) << endl; } void Interaccao::opcaoPesquisarPrecoDeImovelPorCodigo() { string codigo; cout << "\nPesquisar preco de imovel por codigo\n codigo: "; cin >> codigo; cout << imobiliaria->getPreco(codigo) << endl; } void Interaccao::opcaoActualizarPrecoDeImovelPorCodigo() { string codigo; float preco; cout << "\nActualizar preco de imovel por codigo\n codigo: "; cin >> codigo; cout << imobiliaria->getAsString(codigo) << endl; preco = lerFloat("\n preco: "); imobiliaria->setPreco(codigo, preco); } void Interaccao::opcaoRemoverImovelPorCodigo() { string codigo; cout << "\nRemover imovel por codigo\n codigo: "; cin >> codigo; cout << imobiliaria->getAsString(codigo) << endl; cout << "\n Remover "; if (imobiliaria->remover(codigo)) cout << " removeu "; else cout << " nao removeu "; } void Interaccao::corre() { vector<string> opcoes; opcoes.push_back("Sair"); opcoes.push_back("Listar"); opcoes.push_back("Acrescentar apartamento"); opcoes.push_back("Acrescentar loja"); opcoes.push_back("Pesquisar imovel por codigo"); opcoes.push_back("Pesquisar preco de imovel dado o codigo"); opcoes.push_back("Actualizar o preco de um imovel dado o codigo"); opcoes.push_back("Remover imovel dado o codigo"); int opcao = 0; do { opcao = escolheOpcao(opcoes); switch (opcao) { case 0: cout << "\nSair\n"; break; case 1: cout << *imobiliaria << endl; break; case 2: opcaoAcrescentarApartamento(); break; case 3: opcaoAcrescentarLoja(); break; case 4: opcaoPesquisarImovelPorCodigo(); break; case 5: opcaoPesquisarPrecoDeImovelPorCodigo(); break; case 6: opcaoActualizarPrecoDeImovelPorCodigo(); break; case 7: opcaoRemoverImovelPorCodigo(); break; } } while (opcao != 0); } int main() { Imobiliaria* imobiliaria = new Imobiliaria("Imobiliaria"); Interaccao interaccao(imobiliaria); interaccao.corre(); delete imobiliaria; cout << "\nfim do main.." << endl; return 1; }
………..ficha7, exercicio3 (a19,a20)
#include <string> #include <iostream> #include <sstream> #include <vector> #include <regex> #include <initializer_list> #include <fstream> using namespace std; #include <string> #include <iostream> #include <sstream> #include <vector> #include <regex> #include <initializer_list> #include <fstream> using namespace std; /* +---------------------------------------- + -------------------------- - + | operador | membro / não membro | +---------------------------------------- + -------------------------- - + | todos os operadores unários p.e: ++a, a++ | membro | | = () -> ->* | têm sempre que ser membro | | += -= /= *= &= |= %= >>= <<= | membro | | todos os restantes operadores binários, ==,<<... | globais | +--- */ //relação de agregaçao, memoria dinâmica class Livro { string titulo; string autor; long isbn; public: Livro(const string& titulo0, const string& autor0, const long isbn0); virtual ~Livro(); //classe de hierarquia, boa pratica string getTitulo() const; void setTitulo(const string& titulo); string getAutor() const; void setAutor(const string& autor); long getIsbn() const; void setIsbn(const long isbn); virtual string getAsString()const; //para adaptar aos objectos das classes derivadas virtual Livro* duplica() const; }; //comparação de dois livros bool operator==(const Livro& ob1, const Livro& ob2); // cout objecto-de-livro ostream& operator<<(ostream& saida, const Livro& lv); Livro::Livro(const string& titulo0, const string& autor0, const long isbn0):titulo(titulo0), autor(autor0), isbn(isbn0) { } Livro::~Livro() { } string Livro::getTitulo() const { return titulo; } void Livro::setTitulo(const string& titulo) { this->titulo = titulo; } string Livro::getAutor() const { return autor; } void Livro::setAutor(const string& autor) { this->autor = autor; } long Livro::getIsbn() const { return isbn; } void Livro::setIsbn(const long isbn) { this->isbn = isbn; } string Livro::getAsString() const { ostringstream oss; cout << "\ntitulo: " << titulo << " autor: " << autor << " isbn " << isbn << endl; return oss.str(); } //criar um clone Livro* Livro::duplica() const { //ou //return new Livro(*this); //ou Livro* lv = new Livro(*this); return lv; } bool operator==(const Livro& ob1, const Livro& ob2) { return ob1.getIsbn() == ob2.getIsbn(); } ostream& operator<<(ostream& saida, const Livro& lv) { saida << lv.getAsString(); return saida; } class LivroFiccao : public Livro { string nomePlaneta; int anoAccao; bool realidadeAccao; //0 realista, 1 fatansiosa public: LivroFiccao(const string& titulo0, const string& autor0, const long isbn0, const string& nome_planeta, const int ano_accao, const bool realidade_accao); string getNomePlaneta() const; int getAnoAccao() const; bool getRealidadeAccao() const; string getAsString() const override; Livro * duplica() const override; }; LivroFiccao::LivroFiccao(const string& titulo0, const string& autor0, const long isbn0, const string& nome_planeta, const int ano_accao, const bool realidade_accao) : Livro(titulo0, autor0, isbn0), nomePlaneta(nome_planeta), anoAccao(ano_accao),realidadeAccao(realidade_accao){ } string LivroFiccao::getNomePlaneta() const { return nomePlaneta; } int LivroFiccao::getAnoAccao() const { return anoAccao; } bool LivroFiccao::getRealidadeAccao() const { return realidadeAccao; } string LivroFiccao::getAsString() const { ostringstream oss; oss << endl << Livro::getAsString() << " planeta " << nomePlaneta << " ano " << anoAccao << endl; if(realidadeAccao) { oss << " realista \n"; }else { oss << " fantasiosa \n"; } return oss.str(); } Livro* LivroFiccao::duplica() const { return new LivroFiccao(*this); } class LivroPolicial: public Livro { string nomeDetective; int numeroTiros; public: LivroPolicial(const string& titulo0, const string& autor0, const long isbn0, const string& nomeDetective0, int numeroTiros = 0); string getNomeDetective() const; int getNumeroTiros() const; string getAsString()const override; Livro* duplica()const override; }; LivroPolicial::LivroPolicial(const string& titulo0, const string& autor0, const long isbn0, const string& nomeDetective0, int numeroTiros0):Livro(titulo0, autor0, isbn0), nomeDetective(nomeDetective0),numeroTiros(numeroTiros0) { } string LivroPolicial::getNomeDetective() const { return nomeDetective; } int LivroPolicial::getNumeroTiros() const { return numeroTiros; } string LivroPolicial::getAsString() const { ostringstream oss; oss << endl << Livro::getAsString() << " detective: " << nomeDetective << endl; if(numeroTiros > 10) { oss << " nao aconcelhado a criancas \n"; }else { oss << " n. de tiros " << numeroTiros << endl; } return oss.str(); } //nas classes concretas tem que haver um duplica Livro* LivroPolicial::duplica() const { //ou //return new LivroPolicial(*this); //ou LivroPolicial* lvp = new LivroPolicial(*this); return lvp; } //bibliteca tem relação de composição com o livro //posse exclusiva, implementar: destrutor, construtor por copia, operador atribuição class Biblioteca { string morada; //qualquer tipo de livros: ponteiros para a classe base, que depois tem acesso às derivadas vector<Livro *> livros; //vector polimorfico, <Livro *> int pesquisaLivro(long isbn0) const; //indice, int public: Biblioteca(const string& morada); bool acrescentarLivro(Livro * livro); bool removerLivro(long isbn0); //por haver relação de composição, os livros não sobrevivem à destruição da biblioteca //e destrutor virtual ~Biblioteca(); //e construtor por copia Biblioteca(const Biblioteca& ob); //e operador atribuição Biblioteca& operator=(const Biblioteca & ob); string getAsString()const; }; ostream& operator<<(ostream& saida, const Biblioteca& bibl); int Biblioteca::pesquisaLivro(long isbn0) const { for(unsigned int i=0; i<livros.size(); i++) { if(isbn0 == livros[i]->getIsbn()) { return i; } } return -1; } Biblioteca::Biblioteca(const string& morada) { } bool Biblioteca::acrescentarLivro(Livro* livro) { if(livro == nullptr || pesquisaLivro(livro->getIsbn())!=-1) { return false; } Livro* lv = livro->duplica(); //é duplicado com o livro->duplica();, não aceito o que me dão livros.push_back(lv); return true; } bool Biblioteca::removerLivro(long isbn0) { int qual = pesquisaLivro(isbn0); if(qual == -1) { return false; } //liberta o obejcto apontado por livro[i] delete livros[qual]; //só por ser relação de composição //retirar o vector o pionteito que aponta para memoria já libertada livros.erase(livros.begin() + qual); return true; } Biblioteca::~Biblioteca() { for(Livro * l: livros) { delete l; } } Biblioteca::Biblioteca(const Biblioteca& ob) { //nao ha ponteiros com valores lixo para limpar //funcionou o construtor por omissão do vector que criou //um vector vazio (sem ponteiros) //e do membro do tipo string //se houvesse ponteiros com valores lixo punha-se a nullptr //porque precisamos de preparar o objecto que esta aser criado //para invocar o operador de atribuição que limpa a memoria velha //do objecto que o invoca, o primeiro membro da atribuição *this = ob; //chama o operador atribuicao e copia os dados //de acordo com o que tem implementado: duplicando //a memoria dinmica que o destrutor liberta } Biblioteca& Biblioteca::operator=(const Biblioteca& ob) { //prevenção de auto atribuição if(this == & ob) { return *this; } //limpesa da memoria velha do primeiro membro de atribuicao for(Livro * lv: livros) { delete lv; } //esvaziar o vector que agora só aponta para memoria ja nao reservada livros.clear(); //duplicar os objectos dinamicos, copiar a informacao de ob for(Livro * lv: livros) { Livro* p = lv->duplica(); livros.push_back(lv); } //e nao esquecer os restantes membros morada = ob.morada; return *this; } string Biblioteca::getAsString() const { ostringstream oss; oss << "\nmorada: " << morada << endl; for(unsigned int i=0; i<livros.size(); i++) { oss << livros[i]->getAsString(); } return oss.str(); } // cout objecto-de-livro ostream& operator<<(ostream& saida, const Biblioteca & bibl) { saida << bibl.getAsString(); return saida; } int main() { Biblioteca* b = new Biblioteca("aldeia de coimbra"); Livro* p = new LivroPolicial("coimbra", "coimbra", 12345,"coimbra", 1); b->acrescentarLivro(p); cout << b->getAsString(); cout << "\nfim do main" << endl; return 1; }
………..ficha?, exercicio? (a21), aquario polimorfico
#include <string> #include <iostream> #include <sstream> #include <vector> #include <regex> #include <initializer_list> #include <fstream> using namespace std; class Pargo; class Pescada; class Aquario; class Peixe; //peixe é uma classe abstracta, não se podem criar objectos deste tipo class Peixe { string nomeEspecie; string cor; int peso; int numSerie; static int sequencia; //constantes iguais para todos: static const int INICIAL_PESO = 10; bool vivo = true; //importante, subs estadio protected: void aumentaPeso(int quant0); public: Peixe(string nomeEspecie0, string cor0 = "cinzento"); //nao existe aqui construtor default //assim a classe derivada precisa de um construtor que alimente a classe base Peixe(const Peixe& orig); //existe porque precisamos que os peixes tenham um num de seq diferente //tudo é copiado mas o num de série é diferente. ///se fosse o natrual copiaava tudo int getNumSerie() const; int getPeso() const; bool isVivo()const; virtual string getAsString()const; //funcao abstracta nao se podem criar objectos desta classe //pode haver "Peixe *" e "Peixe &" virtual void alimentar(int quant, Aquario* aquario) = 0; virtual Peixe* duplica()const = 0; //serve para criar diferentes tipos de peixes: pargo e pescada static Peixe* fabrica(string tipo0, string cor0="cinzento"); virtual ~Peixe(); bool setVivo(bool v); }; ostream& operator<<(ostream& saida, const Peixe& p); void Peixe::aumentaPeso(int quant0) { peso +=quant0; } Peixe::Peixe(string nomeEspecie0, string cor0) :nomeEspecie(nomeEspecie0), cor(cor0), peso(INICIAL_PESO), numSerie(sequencia++) { } Peixe::Peixe(const Peixe& orig):nomeEspecie(orig.nomeEspecie), cor(orig.cor), peso(orig.peso), numSerie(sequencia++) { //o peixe construido por copia tem outro numero de série } int Peixe::getPeso() const { return peso; } int Peixe::getNumSerie() const { return numSerie; } bool Peixe::isVivo() const { return vivo; } Peixe* Peixe::fabrica(string tipo0, string cor0) { if(tipo0 == "pargo") { return new Pargo(cor0); }else if(tipo0 == "pescada") { return new Pescada; } return nullptr; } bool Peixe::setVivo(bool v) { vivo = v; } ostream& operator<<(ostream& saida, const Peixe& p) { saida << p.getAsString(); return saida; } string Peixe::getAsString() const { ostringstream oss; oss << "\nPeixe: " << nomeEspecie << "\ncor: " << cor << "\npeso: " << peso << "\nnumSerie: " << numSerie << endl; return oss.str(); } int Peixe::sequencia = 499; //num. para cada peixe //NOVO: surgem duas espécies de peixes class Pargo: public Peixe { static const int LIMITE_PESO = 50; public: Pargo(string cor0 = "cinzento"); void alimentar(int quant0, Aquario* aquario) override; Peixe* duplica()const override; }; Pargo::Pargo(string cor0):Peixe("pargo",cor0) { //importante pargo precisa de passar o que o construtor da base precisa, o Peixe //porque a base não é default } void Pargo::alimentar(int quant0, Aquario* aquario) { if(quant0<=0 || aquario==nullptr) { return; } aumentaPeso(quant0); if(getPeso()>LIMITE_PESO) { //aquario->eliminaPeixe(getNumSerie()); //perigo setVivo(false); } } Peixe* Pargo::duplica() const { //duplicação polimórfica return new Pargo(*this); } class Pescada : public Peixe { static const int LIMITE_SOLIDAO = 1; static const int LIMITE_MULTIDAO = 10; public: Pescada(); void alimentar(int quant0, Aquario* aquario0) override; Peixe* duplica()const override; }; Pescada::Pescada():Peixe("pescada") { } void Pescada::alimentar(int quant0, Aquario* aquario0) { if(quant0<=0 || aquario0 == nullptr) { return; } int num = aquario0->getQuantosPeixes(); //uma estragégia para aceder ao aquario //ou colocar na classe peixe um ponteiro para aquario //assim as derivadas teriam sempre acesso if(num> LIMITE_SOLIDAO && num < LIMITE_MULTIDAO) { aumentaPeso(quant0); }else { aumentaPeso(quant0 / 2); } } Peixe* Pescada::duplica() const { return new Pescada(*this); } //aquario é uma classe abstracta class Aquario { vector<Peixe*> peixes; //vector de ponteiros int pesquisaPeixe(int numSerie0)const; void eliminarMortos(); public: Aquario() = default; //qd criado é um vector vazio //quando um peixe e posto no aquario, este assume a //sua posse e controlo total Aquario(const Aquario& orig); //construtor por cópia Aquario& operator=(const Aquario& orig); //operador atribuição virtual ~Aquario(); bool addPeixe(string tipo0, string cor0 = "cinzento"); const Peixe* getPeixe(int numSerie) const; void alimentar(int quantidade0); void removePeixe(int numSerie); bool eliminaPeixe(int numSerie0); string getAsString()const; unsigned int getQuantosPeixes()const; }; void Aquario::alimentar(int quantidade0) { //for (Peixe* p : peixes) //{ // p->alimentar(quantidade0, this); //mt cuidado com isto, usa o vector<Peixe*> novos; //} //v2 for(int i = 0; i < peixes.size(); i++) { peixes[i]->alimentar(quantidade0, this); //percorrer o vector } eliminarMortos(); //vou verificar o boolenao vivo dos peixes } string Aquario::getAsString() const { ostringstream oss; oss << "\nAquario; " << endl; //neste caso vai ser contatenada a informação //para o objecto que estiver a ser apontado //não interessa qual for (Peixe* p : peixes) { oss << p->getAsString(); } return oss.str(); } unsigned Aquario::getQuantosPeixes() const { return peixes.size(); } bool Aquario::addPeixe(string tipo0, string cor0) { Peixe* peixe = Peixe::fabrica(tipo0, cor0); //fabrica é static por isso :: if(peixe==nullptr) { return false; } peixes.push_back(peixe); return true; } const Peixe* Aquario::getPeixe(int numSerie) const { int qual = pesquisaPeixe(numSerie); if(qual == -1) { return nullptr; } return peixes[qual]; }; int Aquario::pesquisaPeixe(int numSerie0)const { for (int i = 0; i < peixes.size(); i++) { if (peixes[i]->getNumSerie() == numSerie0) { return i; } } return -1; } void Aquario::eliminarMortos() { //formula //ou //for(vector<Peixe*>::iterator it = peixes.begin() ; it != peixes.end(); ) //ou for (auto it = peixes.begin(); it != peixes.end();) { if (!(*it)->isVivo()) { delete (*it); it = peixes.erase(it); } else { ++it; } } } Aquario::~Aquario() { for (Peixe* p : peixes) { delete p; } cout << "\n~Aquario()" << endl; } Aquario::Aquario(const Aquario& orig) { //funcionou o constru por defeito do vector //o vector está vazio //não há ponteiros com lixo *this = orig; } Aquario& Aquario::operator=(const Aquario& orig) { //prevenção da auto atribuição if (this == &orig) { return *this; } //libtertar mem dina velha for (Peixe* p : peixes) { delete p; } //esvaziar o vector peixes.clear(); //copiar a informacao de orig, duplicando os objectos dinamicos for (Peixe * peixe : orig.peixes) { Peixe * p = peixe->duplica(); peixes.push_back(p); } return *this; } void Aquario::removePeixe(int numSerie) { int qual = pesquisaPeixe(numSerie); if (qual == -1) { return; } delete peixes[qual]; peixes.erase(peixes.begin() + qual); } bool Aquario::eliminaPeixe(int numSerie0) { int qual = pesquisaPeixe(numSerie0); if(qual == -1) { return false; } //remove o peixe do aquario, é destruido delete peixes[qual]; //depois de feito o dele (libertada a memoria) //precisamos de retirar do vector //o ponteio para memoria ja nao reservada peixes.erase(peixes.begin() + qual); return true; } int main() { cout << "\nfim do main" << endl; return 1; }
#include <string> #include <iostream> #include <sstream> #include <vector> using namespace std; class Caderno { private: //membros variáveis string marca; string cor; int numFolhas; string tamanho; public: Caderno(const string& marca, const string& cor, const int num_folhas, const string& tamanho) //const não consigo alterar o argumento que vem da main, assim fica mais eficiente/seguro, //e tambem assim posso fazer uso de uma const, usando por exemplo "marca" //o int pode ter const ou não e referencia, e porque é uma coisa pequena : marca(marca), cor(cor), numFolhas(num_folhas), tamanho(tamanho) { } //membros funções //funções get //os consts sigificam que não podem alterar nada, é uma função de consulta string getMarca() const { return marca; } string getCor() const { return cor; } int getNumfolhas() const { return numFolhas; } string getTamanho() const { return tamanho; } //funções set void setMarca(const string & marca) { this->marca = marca; } void setCor(const string & cor) { this->cor = cor; } void setNumfolhas(int num_folhas) { if(num_folhas>0){ numFolhas = num_folhas; }else { numFolhas = 0; } } void setTamanho(const string& tamanho) { this->tamanho = tamanho; } string getAsString()const; }; string Caderno::getAsString()const { ostringstream oss; oss << "\nmarca: " << marca << "\ncor: " << cor << "\nnum folhas: " << numFolhas << "n\ntamanho: " << tamanho; return oss.str(); } int main() { const Caderno Cad1("bic","branca",2,"a4"); //const não posso alterar cout << Cad1.getAsString(); cout << "\nfim do main" << endl; return 0; }
………..ficha?, exercicio? (a21, a22), aquario polimorfico v2
#include <string> #include <iostream> #include <sstream> #include <vector> #include <regex> #include <initializer_list> #include <fstream> using namespace std; class Aquario; class Pargo; class Pescada; //peixe é uma classe abstracta, não se podem criar objectos deste tipo class Peixe { string nomeEspecie; string cor; int peso; int numSerie; static int sequencia; //constantes iguais para todos: static const int INICIAL_PESO = 10; bool vivo = true; //importante, subs estadio //v2 Aquario* aquario = nullptr; protected: void aumentaPeso(int quant0); Aquario* getAquario(); //v2 public: Peixe(Aquario* aq0, string nomeEspecie0, string cor0 = "cinzento"); //v2 //nao existe aqui construtor default //assim a classe derivada precisa de um construtor que alimente a classe base Peixe(const Peixe& orig); //existe porque precisamos que os peixes tenham um num de seq diferente //tudo é copiado mas o num de série é diferente. ///se fosse o natrual copiaava tudo int getNumSerie() const; int getPeso() const; bool isVivo()const; virtual string getAsString()const; //funcao abstracta nao se podem criar objectos desta classe //pode haver "Peixe *" e "Peixe &" //virtual void alimentar(int quant, Aquario* aquario) = 0; virtual void alimentar(int quant) = 0; //v2 virtual Peixe* duplica()const = 0; //serve para criar diferentes tipos de peixes: pargo e pescada static Peixe* fabrica(string tipo0, Aquario * aq0, string cor0="cinzento"); virtual ~Peixe(); bool setVivo(bool v); //v3 void setAquario(Aquario* aqua0); }; ostream& operator<<(ostream& saida, const Peixe& p); void Peixe::aumentaPeso(int quant0) { peso +=quant0; } Aquario* Peixe::getAquario() { return aquario; } Peixe::Peixe(Aquario * aq0, string nomeEspecie0, string cor0) :aquario(aq0),nomeEspecie(nomeEspecie0), cor(cor0), peso(INICIAL_PESO), numSerie(sequencia++) { } Peixe::Peixe(const Peixe& orig):nomeEspecie(orig.nomeEspecie), cor(orig.cor), peso(orig.peso), numSerie(sequencia++) { //o peixe construido por copia tem outro numero de série } int Peixe::getPeso() const { return peso; } int Peixe::getNumSerie() const { return numSerie; } bool Peixe::isVivo() const { return vivo; } Peixe* Peixe::fabrica(string tipo0, Aquario * aqu0, string cor0) { if(tipo0 == "pargo") { return new Pargo(aqu0, cor0); }else if(tipo0 == "pescada") { return new Pescada(aqu0); } return nullptr; } bool Peixe::setVivo(bool v) { vivo = v; } void Peixe::setAquario(Aquario* aqua0) { this->aquario = aqua0; } ostream& operator<<(ostream& saida, const Peixe& p) { saida << p.getAsString(); return saida; } string Peixe::getAsString() const { ostringstream oss; oss << "\nPeixe: " << nomeEspecie << "\ncor: " << cor << "\npeso: " << peso << "\nnumSerie: " << numSerie << endl; return oss.str(); } int Peixe::sequencia = 499; //num. para cada peixe //NOVO: surgem duas espécies de peixes class Pargo: public Peixe { static const int LIMITE_PESO = 50; public: Pargo(Aquario * aqua0, string cor0 = "cinzento"); void alimentar(int quant0) override; Peixe* duplica()const override; }; Pargo::Pargo(Aquario* aqua0, string cor0):Peixe(aqua0, "pargo",cor0) { //importante pargo precisa de passar o que o construtor da base precisa, o Peixe //porque a base não é default } void Pargo::alimentar(int quant0) { if(quant0<=0 || getAquario()==nullptr) { return; } aumentaPeso(quant0); if(getPeso()>LIMITE_PESO) { //aquario->eliminaPeixe(getNumSerie()); //perigo setVivo(false); } } Peixe* Pargo::duplica() const { //duplicação polimórfica return new Pargo(*this); } class Pescada : public Peixe { static const int LIMITE_SOLIDAO = 1; static const int LIMITE_MULTIDAO = 10; public: Pescada(Aquario * aqu0); void alimentar(int quant0) override; Peixe* duplica()const override; }; Pescada::Pescada(Aquario* aqu0):Peixe(aqu0, "pescada") { } void Pescada::alimentar(int quant0) { if(quant0<=0 || getAquario() == nullptr) //v2 { return; } int num = getAquario()->getQuantosPeixes(); //uma estragégia para aceder ao aquario, v2 //ou colocar na classe peixe um ponteiro para aquario //assim as derivadas teriam sempre acesso if(num> LIMITE_SOLIDAO && num < LIMITE_MULTIDAO) { aumentaPeso(quant0); }else { aumentaPeso(quant0 / 2); } } Peixe* Pescada::duplica() const { return new Pescada(*this); } //aquario é uma classe abstracta class Aquario { vector<Peixe*> peixes; //vector de ponteiros int pesquisaPeixe(int numSerie0)const; void eliminarMortos(); public: Aquario() = default; //qd criado é um vector vazio //quando um peixe e posto no aquario, este assume a //sua posse e controlo total Aquario(const Aquario& orig); //construtor por cópia Aquario& operator=(const Aquario& orig); //operador atribuição virtual ~Aquario(); bool addPeixe(string tipo0, string cor0 = "cinzento"); const Peixe* getPeixe(int numSerie) const; void alimentar(int quantidade0); void removePeixe(int numSerie); bool eliminaPeixe(int numSerie0); string getAsString()const; unsigned int getQuantosPeixes()const; }; void Aquario::alimentar(int quantidade0) { //for (Peixe* p : peixes) //{ // p->alimentar(quantidade0, this); //mt cuidado com isto, usa o vector<Peixe*> novos; //} //v2 for(int i = 0; i < peixes.size(); i++) { peixes[i]->alimentar(quantidade0); //percorrer o vector, v2 } eliminarMortos(); //vou verificar o boolenao vivo dos peixes } string Aquario::getAsString() const { ostringstream oss; oss << "\nAquario; " << endl; //neste caso vai ser contatenada a informação //para o objecto que estiver a ser apontado //não interessa qual for (Peixe* p : peixes) { oss << p->getAsString(); } return oss.str(); } unsigned Aquario::getQuantosPeixes() const { return peixes.size(); } bool Aquario::addPeixe(string tipo0, string cor0) { Peixe* peixe = Peixe::fabrica(tipo0, this, cor0); //fabrica é static por isso ::, v2 if(peixe==nullptr) { return false; } peixes.push_back(peixe); return true; } const Peixe* Aquario::getPeixe(int numSerie) const { int qual = pesquisaPeixe(numSerie); if(qual == -1) { return nullptr; } return peixes[qual]; }; int Aquario::pesquisaPeixe(int numSerie0)const { for (int i = 0; i < peixes.size(); i++) { if (peixes[i]->getNumSerie() == numSerie0) { return i; } } return -1; } void Aquario::eliminarMortos() { //formula //ou //for(vector<Peixe*>::iterator it = peixes.begin() ; it != peixes.end(); ) //ou for (auto it = peixes.begin(); it != peixes.end();) { if (!(*it)->isVivo()) { delete (*it); it = peixes.erase(it); } else { ++it; } } } Aquario::~Aquario() { for (Peixe* p : peixes) { delete p; } cout << "\n~Aquario()" << endl; } Aquario::Aquario(const Aquario& orig) { //funcionou o constru por defeito do vector //o vector está vazio //não há ponteiros com lixo *this = orig; } Aquario& Aquario::operator=(const Aquario& orig) { //prevenção da auto atribuição if (this == &orig) { return *this; } //libtertar mem dina velha for (Peixe* p : peixes) { delete p; } //esvaziar o vector peixes.clear(); //copiar a informacao de orig, duplicando os objectos dinamicos for (Peixe * peixe : orig.peixes) { Peixe * p = peixe->duplica(); p->setAquario(this); //para aponter para o aquario novo, v3 peixes.push_back(p); } return *this; } void Aquario::removePeixe(int numSerie) { int qual = pesquisaPeixe(numSerie); if (qual == -1) { return; } delete peixes[qual]; peixes.erase(peixes.begin() + qual); } bool Aquario::eliminaPeixe(int numSerie0) { int qual = pesquisaPeixe(numSerie0); if(qual == -1) { return false; } //remove o peixe do aquario, é destruido delete peixes[qual]; //depois de feito o dele (libertada a memoria) //precisamos de retirar do vector //o ponteio para memoria ja nao reservada peixes.erase(peixes.begin() + qual); return true; } int main() { Aquario* aq1 = new Aquario; aq1->addPeixe("pescada"); aq1->addPeixe("pargo", "laranja"); cout << aq1->getAsString() << endl; Aquario* aq2 = new Aquario; aq2->addPeixe("pargo", "azul"); cout << aq2->getAsString() << endl; *aq2 = *aq1; cout << aq2->getAsString() << endl; aq2->alimentar(10); cout << aq2->getAsString() << endl; cout << "\nfim do main" << endl; return 1; }
………..ficha7, exercicio4 (a22, a23) exercicio global
#include <string> #include <iostream> #include <sstream> #include <vector> #include <regex> #include <initializer_list> #include <fstream> class Ginasio; using namespace std; class Tarifario { //sem usar contentores da STL //(vector, lista, maps.. ) //e implica: memoria dinamica, destrutor, operador atribuição, construtor por cópia //deve ser usado um array dinamico de inteiros unsigned int* treinos; //ponteiro para o array dinamico unsigned int quantos; //quantidade de elementos, pois não podemos usar o size(), serve para controlar qts //vai ser implementada pelas derivadas //esta função apenas se destina a calcular o pagamento //a função calculaPagamentoEApagaTreinos invoca esta e apaga os treinos virtual unsigned int calculaPagamento()const = 0; //abstracta public: void acrescentaTreino(unsigned int at); unsigned int calculaPagamentoEApagaTreinos(); //é preciso o construtor para inicializar o ponteiro e a variavel quantos Tarifario(); //este é um construtor por omissão //vai ser preciso ter o destrutor para devolver a memoria ocupada pela matriz dinamica virtual ~Tarifario(); //existem derivas esta é virtual //justificação de: //a matriz dinamica de inteiros(treinos) pertence exclusivamente a cada objeto //de tarifario mas nao e automaticamente copiada quando se copiam ou atribuem estes //objectos (apenas o ponteiro e copiado lvando a partilha de matriz entre objectos //e mais tarde a deletes repetidos da mesma matriz, entre outras incoerencias) // => é preciso fazer o operador de atribuição e o construtor por cópia Tarifario(const Tarifario& orig); Tarifario& operator=(const Tarifario& orig); unsigned int getNumTreinos()const; unsigned int getTreino(unsigned int i)const; virtual string getAsString() const; //tem que ser abstracta tb. nao se pode construir //um tarifario ainda porque é classe abstracta virtual Tarifario* duplica()const = 0; //duplicação polimorfica, por causa do operador atribuição do cliente }; void Tarifario::acrescentaTreino(unsigned at) { //ao inves do push back unsigned int* aux = new unsigned int[quantos + 1]; for(unsigned int i=0; i< quantos; i++) { aux[i] = treinos[i]; } aux[quantos] = at; quantos++; delete[] treinos; treinos = aux; } unsigned Tarifario::calculaPagamentoEApagaTreinos() { //vai chamar a função correspondente a classe do objeto que invoca unsigned int conta = calculaPagamento(); //definido nas classes concretas calculaPagamento(); delete[] treinos; treinos = nullptr; quantos = 0; return conta; } Tarifario::Tarifario() { treinos = nullptr; //inicialmente nao existem treinos quantos = 0; } Tarifario::~Tarifario() { delete[] treinos; //libertar a memoria dinamica } Tarifario::Tarifario(const Tarifario& orig) { //pre inicialização para que o operador de atribuição //consiga trabalhar bem ( precisa de ter o objecto num estado //coerente dai a inicialização previa //para acontecer o delete apenas a um valor de um ponteiro //nulo ou com um valor dado por new treinos = nullptr; //treinos é um vector ponteiro que nasce com lixo, por isso é impts isto! quantos = 0; //usar o operador de atribuição *this = orig; } Tarifario& Tarifario::operator=(const Tarifario& orig) //a= b { //testa auto-aribuição para evitar trabalho desnecssário e possivel incorencia //e libertação dos treinos da orgem da copia (que coincide com o destino) //na memoria diamica se nao o mesmo -> ja sao iguaos = concluido if(this == &orig) { return *this; } //devolve os recursos ocupados pelo objecto alvo da atribuição delete[] treinos; //treinos é um vector ponteiro que nasce com lixo treinos = nullptr; quantos = 0; //se o outro objecto tambem tem 0 treinos ja estamos iguais. concluido. if(orig.treinos == nullptr) { return * this; } //senão: //criar recursos iguais (copiar) aos do outro objecto //alocar matriz dnamica para tantos treinos como os do outro objecto //copiar dos dados: o conteudo da matriz e restantes membros treinos = new unsigned int[orig.quantos]; quantos = orig.quantos; for(unsigned int i = 0 ; i < quantos; i++) { treinos[i] = orig.treinos[i]; //copiar todos } return *this; } unsigned Tarifario::getNumTreinos() const { return quantos; } unsigned Tarifario::getTreino(unsigned i) const { if(i<= 0|| (i>=quantos)) { return 0; } return treinos[i]; } string Tarifario::getAsString() const { ostringstream oss; oss << " tarifario: " << endl; return oss.str(); } //relação com tarifario é de composição, sento Apressado uma sub-classe //apressado é uma classe derivada concreta e tem que existir: //tem que se concretirar tdoas as funções abstractas //tem que haver um construtor que alimenta a classe base, se tiver argumentos o construtor da base //mas neste caso é um construtor por omissão class Apressado :public Tarifario { unsigned int calculaPagamento() const override; //é abstracta na classe tarifario (virtual) public: Tarifario * duplica() const override; //é abstracta na classe tarifario (virtual) string getAsString() const override; }; unsigned Apressado::calculaPagamento() const { unsigned int custo = 0; unsigned int numTreinos = getNumTreinos(); for(unsigned int i = 0 ; i< numTreinos; i++) { unsigned int treino = getTreino(i); if(treino <=10) { custo += 10; }else if(treino > 10 && treino < 20) { custo += 15; }else { custo += 25; } } return custo; } Tarifario* Apressado::duplica() const { return new Apressado(*this); } string Apressado::getAsString() const { ostringstream oss; oss << " apressado " << endl; return oss.str(); } //cliente genérico, significa que é uma classe base de uma hierarquia class Cliente { string nome; unsigned int bi; //ou string Tarifario* tarifario; //aponta para um qualquer tipo de tarifario que exista int horarioInicio; //para impedir a copia e a atribuição de objectos //se for solicitado era: //Cliente(const Cliente& cli) = delete; //Cliente& operator=(const Cliente& cli) = delete; public: //nao podem existir clientes sem tarifario, é necessário o construtor Cliente(const string& nome, unsigned long bi, Tarifario* const tarifario); //destrutor para apagar tarifario virtual ~Cliente(); void iniciaTreino(int hora); void terminaTreino(int hora); unsigned int paga(); //pergunta exame //um método generico que não pode ser já implementado, é uma função abstracta, virtual e =0 //e vao ter codigo nas classes derivadas virtual void reageEntrada(Ginasio* g) = 0; virtual void reageSaida(Ginasio* g) = 0; void mudaTarifario(Tarifario* tarifario); unsigned int getBi()const; bool estarATreinar()const; //a c.5) Cliente(const Cliente& cli); Cliente& operator=(const Cliente& cli); virtual string getAsString()const; //tem que ser virtual pura (cliente é abstracta) virtual Cliente* duplica()const = 0; }; Cliente::Cliente(const string& nome, unsigned long bi, Tarifario* const tarifario) : nome(nome), bi(bi), tarifario(tarifario) { horarioInicio = -1; //nao esta a treinar quando é criado } Cliente::~Cliente() { delete tarifario; cout << "~Cliente" << endl; } void Cliente::iniciaTreino(int hora) { if(horarioInicio==-1) { horarioInicio = hora; } } void Cliente::terminaTreino(int hora) { if(horarioInicio != -1) { tarifario->acrescentaTreino(hora - horarioInicio); horarioInicio = -1; } } unsigned Cliente::paga() { //quem calcula é o tarifario, e o cliente tem return tarifario->calculaPagamentoEApagaTreinos(); } void Cliente::mudaTarifario(Tarifario* tarifario) { if(this->tarifario != nullptr) { //so muda se o novo tarifario existir mesmo //apaga tarifario anterior (deixa de servir) //(obs: os treinos do antigo tarifario ficaram //por pagar deixa-se pagar antes de mudar de tarifario delete this->tarifario; this->tarifario = tarifario; } } bool Cliente::estarATreinar() const { return horarioInicio != -1; } Cliente::Cliente(const Cliente& cli) { //efectua pre inicilização para compatibilizar com o operador //neste caso basta colocar o ponteiro tarifario num estacio inciial coerente tarifario = nullptr; //usa operador atribuicao *this = cli; } Cliente& Cliente::operator=(const Cliente& cli) { //testa a auto atribuição para evitar trabalho desnecessario //e libertacao do tarifario da origem da copia (que coincide com o destino) if(this == &cli) { return *this; } //liberta recursos atuais do objecto da atribuicao //neste caso so o objeto tarifario delete tarifario; //cria/copia recursos (iguais ao) do outro objeto //no caso do tarifario, pode ser de qualquer tipo //usar o new nao e viavel ( nao se sabe o tipo ) //o tarifario que se duplique //tem que ser pela via do "duplica" (implementar no tarifario e derivadas) nome = cli.nome; bi = cli.bi; horarioInicio = cli.horarioInicio; tarifario = cli.tarifario->duplica(); return *this; } string Cliente::getAsString() const { ostringstream oss; oss << nome << " - bi: " << bi; return oss.str(); } //classe concreta //e) class Sociavel: public Cliente { public: Sociavel(const string& nome, const unsigned long bi, Tarifario* const tarifario); void reageEntrada(Ginasio* g) override; void reageSaida(Ginasio* g) override; Cliente* duplica() const override; string getAsString() const override; }; Sociavel::Sociavel(const string& nome, const unsigned long bi, Tarifario* const tarifario) : Cliente(nome, bi, tarifario) { } void Sociavel::reageEntrada(Ginasio* g) { //nao faz nada } void Sociavel::reageSaida(Ginasio* g) { if(g->getNumClientesATreinar()==1) //se for só ele { g->saiClienteDoTreino(getBi()); } } Cliente* Sociavel::duplica() const { return new Sociavel(*this); } string Sociavel::getAsString() const { ostringstream oss; oss << "sociavel - " << Cliente::getAsString(); return oss.str(); } //os clientes pertencem ao ginasio //qd se destroi o ginasio o cliente tambem serão class Ginasio { //clientes de diversos tipos //vector de ponteiros para a classe base //* para validar o polimorfismo vector<Cliente*> clientes; unsigned int relogio; unsigned int pesquisaClienteDadoBi(unsigned int bi); public: void avancaRelogio(int tempo); bool acrescentaCliente(Cliente* c); unsigned int paga(unsigned int bi); void entraClienteNoTreino(unsigned int bi); void saiClienteDoTreino(unsigned int bi); void removeCliente(unsigned int bi); Ginasio(); ~Ginasio(); unsigned int getNumClientesATreinar()const; bool saiClienteDoTreino(int s); Ginasio& operator=(const Ginasio& orig); Ginasio(const Ginasio& orig); string getAsString() const; }; unsigned Ginasio::pesquisaClienteDadoBi(unsigned bi) { for(unsigned int i = 0; i<clientes.size(); i++) { if(bi == clientes[i]->getBi()) { return i; } } return -1; } void Ginasio::avancaRelogio(int tempo) { relogio += tempo; } bool Ginasio::acrescentaCliente(Cliente* c) { if(c == nullptr) { return false; } //se existem clientes com o mesmo bi if(pesquisaClienteDadoBi(c->getBi()) != -1) { return false; } clientes.push_back(c->duplica()); return true; } unsigned Ginasio::paga(unsigned bi) { //procura cliente. sera devolvida a posicao no vector unsigned int indice = pesquisaClienteDadoBi(bi); if(indice != -1) { //se encontrou.. return clientes[indice]->paga(); } return 0; } void Ginasio::entraClienteNoTreino(unsigned bi) { unsigned int indice = pesquisaClienteDadoBi(bi); if(indice == -1) { return; } //verificar se o cliente ainda não estava a treinar if(clientes[indice]->estarATreinar() == true) { return; } //avisa os outros clientes a treinar que entrou na sala for(unsigned int i=0; i< clientes.size(); i++) { if(clientes[i]->estarATreinar()){ clientes[i]->reageEntrada(this); } } //o cliente inicia o treino clientes[indice]->iniciaTreino(relogio); } void Ginasio::saiClienteDoTreino(unsigned bi) { unsigned int indice = pesquisaClienteDadoBi(bi); if(indice == -1) { return; } //cliente pode nao estar a treinar if(clientes[indice]->estarATreinar() == false) { return; } //primeiro tira da sala de treino e so depois avisa os que ficaram que saiu um clientes[indice]->terminaTreino(relogio); //avisa os outros clientes a treinar que saiu um da sala for(unsigned int i = 0; i< clientes.size(); i++) { if(clientes[i]->estarATreinar()) { clientes[i]->reageSaida(this); } } } void Ginasio::removeCliente(unsigned bi) { //procura o cliente na base de dados de clientes unsigned int indice = pesquisaClienteDadoBi(bi); if(indice == -1) { return; } //encontrou manda sair do treino saiClienteDoTreino(bi); //antes de ir embora pagar a conta clientes[indice]->paga(); //apaga, os clientes pertencem ao ginasio delete clientes[indice]; //retira do vector o ponteiro para memoria já libertada clientes.erase(clientes.begin() + indice); } Ginasio::Ginasio():relogio(0) { } Ginasio::~Ginasio() { //apaga as fichas for(unsigned int i = 0; i< clientes.size(); i++) { delete clientes[i]; //os clientes pertencem ao ginasio } } unsigned Ginasio::getNumClientesATreinar() const { unsigned int n = 0; for(unsigned int i = 0; i<clientes.size();i++) { if(clientes[i]->estarATreinar()) { n++; } } return n; } Ginasio& Ginasio::operator=(const Ginasio& orig) { //testar a auto atribuição se sao o mesmo objecto, "ja nao sao iguais" //nao se libertam recursos dos destino da atribuição porque coincide com a origem if(this == &orig) { return *this; } //apaga o conceudo ja existente no "alvo" da atribuicao (*this) for(unsigned int i = 0; i< clientes.size(); i++) { delete clientes[i]; //apaga mesmo os clientes (eram do ginasio) } //os clientes foram apagados, mas os ponteiros clientes.clear(); //ainda estão no vector, o qual deve ser esvaziado for(unsigned int i = 0; i<clientes.size(); i++) { //independentemente do tipo do cliente, duplica clientes.push_back(orig.clientes[i]->duplica()); } //copiar o valor do relgio relogio = orig.relogio; return *this; } Ginasio::Ginasio(const Ginasio& orig) { //nao é preciso pre inicialização explicita porque o vector e //inicializado automaticamente com o seu construtor por omissao //um avez que nao foi usado nenhum outro na lista de inicializaca deste construtor //e que o deixa vazio e pronto a usar. noutros casos poderia ser necessario algo aqui *this = orig; } string Ginasio::getAsString() const { ostringstream oss; oss << "\n ginasio" << "(tempo " << relogio << ")" << "clientes: " << endl; for(unsigned int i = 0 ; i < clientes.size(); i++) { oss << clientes[i]->getAsString() << endl; } oss << "\na treinar " << endl; for(unsigned int i = 0; i< clientes.size(); i++) { if(clientes[i]->estarATreinar()) { oss << clientes[i]->getAsString() << endl; } } return oss.str(); } int main() { cout << "\nfim do main" << endl; return 1; } }
………..ficha7, exercicio5 (a24)
#include <string> #include <iostream> #include <sstream> #include <vector> #include <regex> #include <initializer_list> #include <fstream> using namespace std; class Tagarela; class FalaPouco; //classe base, abstracta, relação de class Tarifario { //nao existem dados, quem tem é o Cartao //nao tem informação public: //só tem funções Tarifario() = default; virtual float calculaCustoChamada(int s) const = 0; //virtual e =0 virtual float fazCarregamento(float quantia) const = 0; virtual bool autorizaChamada(int saldo) const = 0; virtual string getNome()const = 0; virtual Tarifario* duplica() const = 0; //por causa do operador atribuição na classe rede static Tarifario* fabrica(string tipo); //fabrica de tarifarios, para os arrumar virtual string getAsString() const; }; Tarifario* Tarifario::fabrica(string tipo) { if(tipo=="Tagarela") { return new Tagarela; }else if(tipo == "FalaPouco") { return new FalaPouco; }else { return nullptr; } } string Tarifario::getAsString() const { ostringstream oss; oss << "tarifario: " << endl; return oss.str(); } //classe derivada class Tagarela : public Tarifario { //existem constantes desta classe static const float PRIMEIRO_MINUTO; static const float MINUTOS_SEGUINTES; static const float BONUS; static const float BASE; public: float calculaCustoChamada(int s) const override; float fazCarregamento(float quantia) const override; bool autorizaChamada(int saldo) const override; string getNome() const override; Tarifario* duplica() const override; string getAsString() const override; }; //concretizar as constantes const float Tagarela::PRIMEIRO_MINUTO = 0.02f; const float Tagarela::BONUS = 5.0f; const float Tagarela::BASE = 25.0f; const float Tagarela::MINUTOS_SEGUINTES = 0.02f; float Tagarela::calculaCustoChamada(int s) const { if(s<=0) //saldo { return 0; } float aux_custo = PRIMEIRO_MINUTO; if(s>60) { aux_custo += MINUTOS_SEGUINTES * (s - 60) / 60.0; } return aux_custo; } float Tagarela::fazCarregamento(float quantia) const { if(quantia<BASE) { return 0; }else if(quantia>=2*BASE) { quantia += BONUS; } return quantia; } bool Tagarela::autorizaChamada(int saldo) const { return saldo >= -PRIMEIRO_MINUTO; } string Tagarela::getNome() const { return "Tagarela"; } Tarifario* Tagarela::duplica() const { return new Tagarela(*this); } string Tagarela::getAsString() const { ostringstream oss; oss << "tagarela: " << endl; return oss.str(); } //classe derivada class FalaPouco : public Tarifario { static const float TODOS_MINUTOS; static const float CARREGAMENTOS; static const float BONUS_CARREGAMENTOS; public: float calculaCustoChamada(int s) const override; float fazCarregamento(float quantia) const override; bool autorizaChamada(int saldo) const override; string getNome() const override; Tarifario* duplica() const override; string getAsString() const override; }; //concretizar as constantes const float FalaPouco::TODOS_MINUTOS = 0.25f; const float FalaPouco::CARREGAMENTOS = 10.0f; const float FalaPouco::BONUS_CARREGAMENTOS = 0.2f; float FalaPouco::calculaCustoChamada(int s) const { if(s<0) { return 0; } return TODOS_MINUTOS * s / 60.0; } float FalaPouco::fazCarregamento(float quantia) const { if(quantia<CARREGAMENTOS) { return 0; } int n = rand() % 10; //de 0 a 9 if(n<2) //<2 é 20% { quantia *= 2; } return quantia; } bool FalaPouco::autorizaChamada(int saldo) const { //ou talvez meu if(saldo<=(TODOS_MINUTOS*10)) { return false; } return true; //ou //return saldo >= - TODOS_MINUTOS * 10; } string FalaPouco::getNome() const { return "FalaPouco"; } Tarifario* FalaPouco::duplica() const { return new FalaPouco(*this); } string FalaPouco::getAsString() const { ostringstream oss; oss << "falapouco" << endl; return oss.str(); } class Cartao { long numero; float saldo; Tarifario* tarifario; public: Cartao(const long numero, Tarifario* const tarifario); virtual ~Cartao(); long getNumero() const; float getSaldo() const; string getNomeTarifario() const; void setTarifario(Tarifario* const tarifario0); bool autorizaChamada()const; void registaChamada(int saldo); bool fazCarregamento(float quantia); string getAsString()const; }; bool operator==(const Cartao& orig1, const Cartao& orig2); //para dois tarifários iguais!! Cartao::Cartao(const long numero0, Tarifario* const tarifario0):numero(numero0), tarifario(tarifario0), saldo(0){} long Cartao::getNumero() const { return numero; } float Cartao::getSaldo() const { return saldo; } string Cartao::getNomeTarifario() const { return tarifario->getNome(); } void Cartao::setTarifario(Tarifario* const tarifario0) { this->tarifario = tarifario0; } bool Cartao::autorizaChamada() const { //função polimorfica, conforme o tarifario return tarifario->autorizaChamada(saldo); } void Cartao::registaChamada(int saldo0) { //função polimorfica, conforme o tarifario float aux_custo = tarifario->calculaCustoChamada(saldo0); saldo = -aux_custo; } bool Cartao::fazCarregamento(float quantia0) { //função polimorfica, conforme o tarifario float aux_carregamento = tarifario->fazCarregamento(quantia0); saldo += aux_carregamento; return aux_carregamento > 0; } string Cartao::getAsString() const { ostringstream oss; oss << "(numero " << numero << " saldo: " << saldo << " tarifario " << tarifario->getNome() << ")"; return oss.str(); } bool operator==(const Cartao& orig1, const Cartao& orig2) { return orig1.getNumero() == orig2.getNumero(); } class Rede { string nome; //tarifarios é uma classe abstracta //logo não pode haver objectos de uma classe abstracta //vector <Tarifario> tarifarios; //e queremos ponteiros para a classe base, e uma coleção polimorfica vector <Tarifario*> tarifarios; //cartoes não tem derivadas //e podia ser vector <Cartao> cartoes; vector <Cartao*> cartoes; Tarifario* procuraTarifario(const string& nome) const; public: Rede(const string& nome0); //rede composição: qd a rede deixar de existir os tarifários tb deixam Rede(const Rede& ob); Rede & operator=(const Rede& ob); //tem uma dificuldade ~Rede(); void setNome(const string& nome0); bool acrescentaTarifario(const string& nomeTarifario); bool acrescentaCartao(long num, const string& nomeTarifa); int procuraCartao(long i)const; bool removeCartao(long i); bool registaChamada(long numero, int duracao); bool fazCarregamento(long numero, float quantia); bool autorizaChamada(long n)const; string getAsString() const; }; ostream& operator<<(ostream& saida, const Rede& rede); Tarifario* Rede::procuraTarifario(const string& nome) const { for(Tarifario *t : tarifarios) { if(t->getNome() == nome) { return t; } } return nullptr; } Rede::Rede(const string& nome0):nome(nome0) { } Rede::Rede(const Rede& ob) { *this = ob; } Rede& Rede::operator=(const Rede& ob) //immportante, complicado { //prevenção da auto atribuicao if(this == &ob) { return *this; } //libertar mem. dinamica apontada pelo primeiro membro da atribuicao //e esvaziar os vectores for(Tarifario *t: tarifarios) { delete t; } tarifarios.clear(); for(Cartao *c: cartoes) { delete c; } cartoes.clear(); //copiar os dados do segundo membro da atribuição nome = ob.nome; for(Tarifario * t: ob.tarifarios) { tarifarios.push_back(t->duplica()); } //depois de todos os tarifários do primeiro membro da atribuição copiados for(Cartao *c: ob.cartoes) { Cartao* novo = new Cartao(*c); //cópia do cartao //que aponta para um tarifario do segundo membro da atribuicao string nomeTarifario = c->getNomeTarifario(); //identifica do seu tarifario //procura tarifario com nomeTarifario no vector do primeiro membro da atribuicao Tarifario* t = procuraTarifario(nomeTarifario); novo->setTarifario(t); cartoes.push_back(novo); } } Rede::~Rede() { //porque sao vectres de ponteiros para objectos dinamicos for(Tarifario *t: tarifarios) { delete t; } for(Cartao *c: cartoes) { delete c; } //e o que o destrutor libetra //o construtor por copia e o operador atribuicao tem que duplicar cout << "destr da rede " << nome << endl; } void Rede::setNome(const string& nome0) { this->nome = nome0; } bool Rede::acrescentaTarifario(const string& nomeTarifario) { Tarifario* tarifario0 = procuraTarifario(nomeTarifario); if(tarifario0 != nullptr) { return false; } Tarifario* novoTarifario = Tarifario::fabrica(nomeTarifario); if(novoTarifario == nullptr) { return false; } tarifarios.push_back(novoTarifario); return true; } bool Rede::acrescentaCartao(long num, const string& nomeTarifa) { if(procuraCartao(num) != -1) { return false; } Tarifario* tf = procuraTarifario(nomeTarifa); if(tf == nullptr) { return false; } cartoes.push_back(new Cartao(num, tf)); return true; } int Rede::procuraCartao(long i) const { for(unsigned int indice = 0; indice < cartoes.size(); indice++) { if(cartoes[indice]->getNumero() == i) { return indice; } } return -1; } bool Rede::removeCartao(long i) { int aux = procuraCartao(i); if(aux == -1) { return false; } //relação de composição delete cartoes[aux]; //libetra o objecto cartoes.erase(cartoes.begin() + aux);//tira o ponteiro do vector return true; } bool Rede::registaChamada(long numero, int duracao) { int aux = procuraCartao(numero); if(numero == -1) { return false; } cartoes[aux]->registaChamada(duracao); return true; } bool Rede::fazCarregamento(long numero, float quantia) { int aux = procuraCartao(numero); if(aux== -1) { return false; } return cartoes[aux]->fazCarregamento(quantia); } bool Rede::autorizaChamada(long n) const { int aux = procuraCartao(n); if(aux == -1) { return false; } return cartoes[aux]->autorizaChamada(); } string Rede::getAsString() const { ostringstream oss; oss << "\nRede: " << nome << endl << " tarifarios: "; for(Tarifario *t : tarifarios) { oss << t->getNome() << "\t"; } oss << "\nCartoes: " << endl; for(Cartao *c : cartoes) { oss << c->getAsString() << endl; } return oss.str(); } ostream& operator<<(ostream& saida, const Rede& rede) { saida << rede.getAsString(); return saida; } int main(){ Rede* rede = new Rede("meo"); rede->acrescentaTarifario("Tagarela"); rede->acrescentaTarifario("FalaPouco"); rede->acrescentaCartao(10, "Tagarela"); rede->acrescentaCartao(20, "FalaPouco"); cout << rede->getAsString(); rede->removeCartao(10); cout << rede->getAsString(); delete rede; cout << "\nfim do main" << endl; return 0; }
Tags : apontamentos, c++11, Learn C plus plus, poo_lab_pt6, poof
0 thoughts on “herança e polimorfismo”