Day: September 6, 2021
excepções e vários
………..varios, exercicios excepções (a25)
#include <string> #include <iostream> #include <sstream> #include <vector> #include <regex> #include <initializer_list> #include <fstream> using namespace std; void funcao() { double dX = -23.99; cout << "se funcao : antes excepcao " << endl; //se não houver excepções corre tudo bem //throw - 1; //sai aqui em estado de erro, lançada a execpção que não é tratata //ou //throw "um texto que e erro..";//sai aqui em estado de erro, lançada a execpção que não é tratata //ou //throw dX; //sai aqui em estado de erro, lançada a execpção que não é tratata cout << "se funcao : depois excepcao " << endl; } int main() { cout << "\n inicio do main" << endl; funcao(); cout << "\n fim do main" << endl; return 0; }
………..varios, exercicios excepções (a25)
#include <string> #include <iostream> #include <sstream> #include <vector> #include <regex> #include <initializer_list> #include <fstream> using namespace std; class minhaExcepcao { const char* const descricao; public: minhaExcepcao(const char * const msg =0):descricao(msg){} }; void funcao2() { double dX = -23.99; cout << "se funcao : antes excepcao " << endl; //esta versão também não adianta.. throw minhaExcepcao("algo aconteceu"); cout << "se funcao : depois excepcao " << endl; } int main() { cout << "\n inicio do main" << endl; funcao2(); cout << "\n fim do main" << endl; return 0; }
………..varios, exercicios excepções (a25)
#include <string> #include <iostream> #include <sstream> #include <vector> #include <regex> #include <initializer_list> #include <fstream> using namespace std; class Erro { }; void funcao3() { cout << "se funcao : antes excepcao " << endl; try { //criação artifical de um erro de uma excepção com o uso do throw //ou //sendo executado o primeiro thorw e interrompe este try throw -1; //ou throw "primeira linha de comentario"; //ou throw Erro(); //esta excepção não é tratada num catch, logo termina em erro, mesmo com a class estabelecida //ou //se nao for lançada nenhuma excepção então tbm não vai ser executado nenhum catch, e é porque está tudo bem } catch (int x) { //e é sempre executado no máximo um catch cerr << "apanho o valor int da excepcao: " << x << endl; }catch(const char * s) { cerr << "apanho o valor char da excepcao: " << s << endl; } cout << "se funcao : depois excepcao " << endl; } int main() { cout << "\n inicio do main" << endl; funcao3(); cout << "\n fim do main" << endl; return 0; }
………..varios, exercicios excepções (a25)
#include <string> #include <iostream> #include <sstream> #include <vector> #include <regex> #include <initializer_list> #include <fstream> using namespace std; int main() { cout << "\n inicio do main" << endl; try { throw - 1; } catch (int x) { //e é sempre executado no máximo um catch cerr << "apanho o valor int da excepcao: " << x << endl; } catch (double) { cerr << "apanho o valor double da excepcao: "<< endl; } catch (const string & str) { cerr << "apanho o valor string da excepcao: " << str << endl; } cout << "\n fim do main" << endl; return 0; }
………..varios, exercicios excepções (a25)
#include <string> #include <iostream> #include <sstream> #include <vector> #include <regex> #include <initializer_list> #include <fstream> using namespace std; class denominadorNull { public: string sobre() { return string("denominador nulo\n"); } }; class foraDosLimites { public: string sobre() { return string("fora dos limites\n"); } }; double divisao(int numerador, int denominador) { if(!denominador) { throw denominadorNull(); } return static_cast<double>(numerador) / denominador; } int main() { cout << "\n inicio do main" << endl; int a[4] = { 10,11,12,13 }; int index = 1, d; while(index >=0) { cout << "qual o index: "; cin >> index; cout << "qual o denominador: "; cin >> d; try { //ou //throw "aaa"; //ou if (index < 0 || index >= 4) throw foraDosLimites(); //e interrompe, não foi resolvido nao existe um catch //se correr bem continuo cout << "resultado: " << divisao(a[index], d) << endl; } catch (denominadorNull & dn) { cerr << dn.sobre(); //depois disto considera-se resolvido } catch(foraDosLimites & fl) { cerr << fl.sobre(); //depois disto considera-se resolvido } catch (...) //apanha todos os outros erros { cerr << "qualquer outro erro\n"; //depois disto considera-se resolvido } } return 0; }
………..varios, exercicios excepções (a25)
#include <string> #include <iostream> #include <sstream> #include <vector> #include <regex> #include <initializer_list> #include <fstream> using namespace std; class baseErro { public: virtual void oque() { cout << "baseErro" << endl; } }; class derivadaErro : public baseErro { public: virtual void oque() { cout << "derivadaErro" << endl; } }; void funcao6() { throw derivadaErro(); } int main() { try { funcao6(); } catch (baseErro b) //não é usada a derivada mas sim a base, //não existe neste caso o polimorfismo { b.oque(); } try { funcao6(); } catch (baseErro & b) //convem passar por referencia para existir o polimorfismo //porque é passado por referencia, surgre assim o erro da derivada //e para que não se faça mais uma copia da excepção que foi lançada { b.oque(); } return 0; }
………..varios, exame1920_epocanormal (a25)
#include <string> #include <iostream> #include <sstream> #include <vector> #include <regex> #include <initializer_list> #include <fstream> using namespace std; class Bilhete { string passageiro; int passaporte; string & companhia; //obrigatoria ser na lista de inicialização, se for & e const vector<int> id_malas; //Acrescentar bagagens ao bilhete (representadas pelos seus ID e sem repetir): int pesquisa(int id)const; public: //ou 1 //Bilhete(string passageiro0, int passaporte0, string & companhia0, vector<int> id_malas0); //ou 2 Bilhete(string passageiro0, int passaporte0, string& companhia0, initializer_list<int> id_malas0); //lidar com a atribuir objectos b1=b2 Bilhete& operator=(const Bilhete& ob); //Acrescentar bagagens ao bilhete (representadas pelos seus ID e sem repetir): //operador que pode ser membro Bilhete& operator <<(int id); //por estar em cadeia //ou //void operator <<(int id); //se não estivesse em cadeia //Remover todas as bagagens com id superior a um indicado): Bilhete& operator -=(int id); //por estar em cadeia //extra string getAsAstring()const; }; //Mostrar o conteúdo no ecrã da forma (bilhete1 e bilhete2 são objetos da classe Bilhete): ostream& operator<<(ostream& saida, const Bilhete & ob); //Acrescentar bagagens ao bilhete (representadas pelos seus ID e sem repetir): int Bilhete::pesquisa(int id) const { for(unsigned int i = 0; i< id_malas.size(); i++) { if(id == id_malas[i]) { return i; } } return -1; } //Acrescentar bagagens ao bilhete (representadas pelos seus ID e sem repetir): Bilhete& Bilhete::operator<<(int id) { int pos = pesquisa(id); if(pos == -1) { //não está lá o id id_malas.push_back(id); } //senão não faço nada return *this; // pedido em cadeia, o retorno é *this } //Remover todas as bagagens com id superior a um indicado): Bilhete& Bilhete::operator-=(int id) { for(auto it= id_malas.begin(); it != id_malas.end(); ) { if(*it >id) { it = id_malas.erase(it); }else { ++it; } } return *this; } //ou //void Bilhete::operator<<(int id) //se não estivesse em cadeia //ou 1 //Bilhete::Bilhete(string passageiro0, int passaporte0, string& companhia0, vector<int> id_malas0) : passageiro(passageiro), //passaporte(passaporte), //companhia(companhia), //id_malas(id_malas) //{ //} //ou 2, versão "mais complicada" Bilhete::Bilhete(string passageiro0, int passaporte0, string& companhia0, initializer_list<int> id_malas0) : passageiro(passageiro0), passaporte(passaporte0), companhia(companhia0) { //para lidar com o initializer_list for(auto & m : id_malas0) { id_malas.push_back(m); } } //lidar com a atribuir objectos Bilhete& Bilhete::operator=(const Bilhete& ob) { //evitar autoatribuição if(this == &ob) { return *this; } //pode-se atribuir tudo menos a companhia, i.e. referencias e const passageiro = ob.passageiro; passaporte = ob.passaporte; id_malas = ob.id_malas; return *this; } //extra string Bilhete::getAsAstring() const { ostringstream oss; oss << "Passageiro: " << passageiro << " Passaporte: " << passaporte << " Companinha: " << companhia << "mala:" << endl; for (int i : id_malas) { oss << " " << i; } oss << endl; return oss.str(); } //Mostrar o conteúdo no ecrã da forma (bilhete1 e bilhete2 são objetos da classe Bilhete): ostream& operator<<(ostream& saida, const Bilhete& ob) { saida << ob.getAsAstring(); return saida; } int main() { //alinea 6. //string & companhia; exige uma variavel string aux_nome("tap"); //ou 1 ou 2 Bilhete b1("nome Passageiro", 123, aux_nome, {1,2,3,4}); //{1,2,3,4} com initializer_list cout <<b1.getAsAstring(); //para atribuir objectos string aux_nome2("fly"); Bilhete b2("outro Passageiro",456, aux_nome2, {5,6,7,8}); cout << b2.getAsAstring(); //atribuir objectos b1 = b2 //não é possivel por existe objectos com membros objectos com referencia (&) ou const //assim b1=b2 dá erro, é a atribuição default //solução: operador atribuição e operator b1 = b2; cout << b1.getAsAstring(); //Mostrar o conteúdo no ecrã da forma (bilhete1 e bilhete2 são objetos da classe Bilhete): cout << "\nPassageiro 1 : " << b1 << "\nPassageiro 2" << b2; //Acrescentar bagagens ao bilhete (representadas pelos seus ID e sem repetir): b1 << 123 << 789 << 123; cout << "\nPassageiro 1 acrescentou: " << b1; //Remover todas as bagagens com id superior a um indicado): (b1 -= 40) -= 35; cout << "\nPassageiro 1 removeu: " << b1; cout << "\nfim do main" << endl; return 0; }
………..varios, exame1920_epocanormal (a25)
#include <string> #include <iostream> #include <sstream> #include <vector> #include <regex> #include <initializer_list> #include <fstream> using namespace std; //antes /* class Doutor { string nome; public: Doutor(const string& n) :nome(n) {} string getNome()const { return nome; } }; class Engenheiro { string nome; public: Engenheiro(const string& n) :nome(n) {} string getNome()const { return nome; } }; class Empresa { vector<Doutor> doutores; vector<Engenheiro> engenheiros; public: Empresa() { doutores.push_back(Doutor("D1")); doutores.push_back(Doutor("D2")); engenheiros.push_back(Engenheiro("E1")); engenheiros.push_back(Engenheiro("E2")); } void cumprimentar() { for (auto& d : doutores) { cout << "Bom dia Doutor " << d.getNome() << endl; } for (auto& e : engenheiros) { cout << "Bom dia Engenheiro " << e.getNome() << endl; } } void removeDoutor(string nome) { // remove o doutor com esse nome do seu vector } void removeEngenheiro(string nome) { // remove o engenheiro com esse nome do seu vector } }; */ //depois corrigido //class abstracta class Funcionario { string nome; public: Funcionario(string nome0) :nome(nome0){} virtual void cumprimentar() const = 0; string getNome()const { return nome; } //para funionar o destutor, construtor por copia e operador atribuição virtual Funcionario* duplica()const = 0; }; class Doutor: public Funcionario { public: Doutor(const string& nome0) : Funcionario(nome0) { } void cumprimentar() const override { cout << "Bom dia Doutor " << getNome() << endl; } Funcionario* duplica() const override { return new Doutor(*this); } }; class Engenheiro : public Funcionario { public: Engenheiro(const string& nome0) : Funcionario(nome0) { } void cumprimentar() const override { cout << "Bom dia Engenheiro " << getNome() << endl; } Funcionario* duplica() const override { return new Engenheiro(*this); } }; class Empresa { vector<Funcionario*> funcionarios; int pesquisa(string nome) const { for (unsigned int i = 0; i < funcionarios.size(); i++) { if (nome == funcionarios[i]->getNome()) { return i; } } return -1; } public: Empresa() { funcionarios.push_back(new Doutor("D1")); funcionarios.push_back(new Doutor("D2")); funcionarios.push_back(new Engenheiro("E1")); funcionarios.push_back(new Engenheiro("E2")); } void cumprimentar() { for (auto& d : funcionarios) { d->cumprimentar(); } } void removerNome(string nome0) { int pos = pesquisa(nome0); if(pos == -1) { return; } //existe posso exclucivsa, eliminar o objecto de mem dinamica delete funcionarios[pos]; //remover o ponteiro funcionarios.erase(funcionarios.begin() + pos); } //e existe propriedade exclusiva da empresa //fazer destrutor, construtor por copia e operador atribuição e duplica (esta em funcionarions) ~Empresa() { for(auto f: funcionarios) { delete f; } } //construtor por copia Empresa(const Empresa& ob) { *this = ob; //apenas, porque não existem ponteiros primitivos } //operador atribuição Empresa &operator=(const Empresa &ob) { if(this ==&ob) { return *this; } for(auto f: funcionarios) { delete f; } funcionarios.clear(); for(auto f: ob.funcionarios) { //depois de feitos os duplicas funcionarios.push_back(f->duplica()); } return *this; } }; int main() { Empresa empresa; empresa.cumprimentar(); Empresa empresa2 = empresa; empresa2.removerNome("E1"); empresa2.removerNome("D2"); empresa2.cumprimentar(); cout << "\nfim do main" << endl; return 1; }
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; }
classes cujos objectos interagem de forma bidirecional
………..ficha6, exercicio1 (a18)
#include <string> #include <iostream> #include <sstream> #include <vector> #include <regex> #include <initializer_list> #include <fstream> using namespace std; class Aquario; class Peixe { string nomeEspecie; string cor; int peso; int numSerie; int estadio; //0, normal, 1, emagrece, 2,3,4,5 nao come, 6 morre static int sequencia; //constantes iguais para todos: static const int LIMITE_PESO = 50; static const int INICIAL_PESO = 10; public: Peixe(string nomeEspecie0, string cor0="cinzento"); //posso e controlo total: //composição: destrutor a lierbtar os peixes, construtor pro copia e operador atribuição a duplicar aquilo que o destrutor destroi string getNomeEspecie() const; void setNomeEspecie(const string& nome_especie); string getCor() const; void setCor(const string& cor); int getPeso() const; void setPeso(const int peso); int getNumSerie() const; void setNumSerie(const int num_serie); int getEstadio() const; void setEstadio(const int estadio); bool isVivo()const; void alimentar(int quant, Aquario* aquario); string getAsString()const; }; Peixe::Peixe(string nomeEspecie0, string cor0):nomeEspecie(nomeEspecie0), cor(cor0), peso(INICIAL_PESO), numSerie(++sequencia), estadio(0) { } string Peixe::getNomeEspecie() const { return nomeEspecie; } void Peixe::setNomeEspecie(const string& nome_especie) { nomeEspecie = nome_especie; } string Peixe::getCor() const { return cor; } void Peixe::setCor(const string& cor) { this->cor = cor; } int Peixe::getPeso() const { return peso; } void Peixe::setPeso(const int peso) { this->peso = peso; } int Peixe::getNumSerie() const { return numSerie; } void Peixe::setNumSerie(const int num_serie) { numSerie = num_serie; } int Peixe::getEstadio() const { return estadio; } void Peixe::setEstadio(const int estadio) { this->estadio = estadio; } bool Peixe::isVivo() const { return getEstadio() <= 5; } void Peixe::alimentar(int quant, Aquario* aquario) { if(quant <= 0|| aquario == nullptr) { return; } if(estadio >0 && estadio<=5) { ++estadio; return; } if(estadio>5) { return; } peso += quant; if(peso> LIMITE_PESO) { int probabilidade = rand() % 100; if(probabilidade < 50) { peso = LIMITE_PESO - INICIAL_PESO; aquario->nasceNovoPeixe(nomeEspecie, cor); }else { peso /= 2; //reduzido a metade estadio = 1; } } } string Peixe::getAsString() const { ostringstream oss; oss << "\nPeixe: " << nomeEspecie << "\ncor: " << cor << "\npeso: " << peso << "\nnumSerie: " << numSerie << (estadio <= 5 ? " vivo" : " morto") << " estadio " << estadio << endl; return oss.str(); } int Peixe::sequencia = 499; //num. para cada peixe //relação bidirecional entre o Peixe e o Aquario //include no CPP e declaração da classe no h class Aquario { //tem uma colecção de peixes vector<Peixe*> peixes; vector<Peixe*> novos; //o peixe usa para colocar os novos void eliminarMortos(); void deslocaNovoParaAquario(); int pesquisaPeixe(int numSerie0)const; public: Aquario() = default; //os dois vectores são construidos por omissão, isto é ficam vazios na construção //e porque não existe nenhum ponteirp primitivo na classe //e no construtor por copia fica mais simples virtual ~Aquario(); //quando um peixei e colocado no aquario, este assume //a sua posse e controlo total: Aquario(const Aquario& orig); //construtor por copia Aquario& operator=(const Aquario & orig); //operador atribuição void removePeixe(int numSerie); void alimentar(int quantidade0); void nasceNovoPeixe(string especie0, string cor0); bool acrescentaPeixeDoExterior(Peixe* peixe); string getAsString()const; }; void Aquario::alimentar(int quantidade0) { for(Peixe * p : peixes) { p->alimentar(quantidade0, this); //mt cuidado com isto, usa o vector<Peixe*> novos; } eliminarMortos(); deslocaNovoParaAquario(); //sair do novo para o aquario normal } void Aquario::nasceNovoPeixe(string especie0, string cor0) { novos.push_back(new Peixe(especie0, cor0)); } bool Aquario::acrescentaPeixeDoExterior(Peixe* peixe) { if (peixe == nullptr){ return false; } //se o peixe estiver no aquario if(pesquisaPeixe(peixe->getNumSerie())!= -1) { return false; } //se ainda nao esta no aquario //criar um novo em mem dinamica, com new Peixe* p = new Peixe(*peixe); //faço copia local peixes.push_back(p); return true; } string Aquario::getAsString() const { ostringstream oss; oss << "\nAquario; " << endl; for(Peixe * p: peixes) { oss << p->getAsString(); } return oss.str(); } 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; } } } void Aquario::deslocaNovoParaAquario() { for(Peixe * p: peixes) { peixes.push_back(p); } novos.clear(); } Aquario::~Aquario() { for(Peixe * p: peixes) { delete p; } for(Peixe * p: novos) { delete p; } cout << "\n~Aquario()" << endl; } Aquario::Aquario(const Aquario& orig) { *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; } peixes.clear(); //copiar a infor de orig, duplicando os objectos dinamicos Peixe for(Peixe * p: orig.peixes){ peixes.push_back(new Peixe(*p)); } for(Peixe * p: orig.peixes) { novos.push_back(new Peixe(*p)); } return *this; } void Aquario::removePeixe(int numSerie) { int qual = pesquisaPeixe(numSerie); if(qual == -1) { return; } delete peixes[qual]; peixes.erase(peixes.begin() + qual); } int main() { Peixe a("Robalo", "branco"); Peixe b("Pescada"); Peixe c("Salmao"); Aquario* aq1 = new Aquario; aq1->acrescentaPeixeDoExterior(&a); aq1->acrescentaPeixeDoExterior(&b); aq1->acrescentaPeixeDoExterior(&c); cout << aq1->getAsString() << endl; // peso 10 aq1->alimentar(20); cout << aq1->getAsString() << endl; // peso 30 aq1->alimentar(30); cout << aq1->getAsString() << endl; // peso 60 e consequencias for (int i = 0; i < 6; ++i) { aq1->alimentar(1); cout << aq1->getAsString() << endl; } aq1->removePeixe(500); aq1->removePeixe(500); cout << aq1->getAsString() << endl; /// testa mem din Aquario* aq2 = new Aquario; aq2->acrescentaPeixeDoExterior(&a); aq2->acrescentaPeixeDoExterior(&a); aq2->acrescentaPeixeDoExterior(&a); cout << aq2->getAsString() << endl; *aq2 = *aq1; delete aq1; cout << " aq1:\n"; cout << " aq2:\n"; cout << aq2->getAsString() << endl; Aquario* aq3 = new Aquario(*aq2); delete aq2; cout << aq3->getAsString() << endl; delete aq3; cout << "\nfim do main" << endl; return 1; }
objetos dinâmicos, matrizes dinâmicas, classes com construtores por cópia, operador de atribuição e destrutor
………..ficha5, exercicio1 (a15)
#include <string> #include <iostream> #include <sstream> #include <vector> #include <regex> #include <initializer_list> #include <fstream> using namespace std; class MSG { string mensagem; public: // MSG(const string & s); MSG(const string& s="por omissao"); //d) ~MSG(); }; MSG::MSG(const string& s):mensagem(s) { cout << "ola " << mensagem << "\n"; } MSG::~MSG() { cout << "adeus " << mensagem << endl; } MSG * func(string s) { MSG* p = new MSG(s); cout << "\n func: criado um objecto " << s << endl; return p; //retornamos uma copia, que é o valor do endereço } int main() { //a) //MSG * a = new MSG("AAAA"); //MSG * b = new MSG("BBBB"); ////para destruir o new só aplicando o delete //cout << "\ndestruir.."; //delete a; //destroi apenas o objecto dinamico, não o ponteiro //cout << "\ndestruir.."; //delete b; // ////um objecto que nao é dinamico //MSG c("CCCC"); //a = new MSG("outro"); //o ponteiro a continua disponivel! //delete a; //c usar a func(a,b) //MSG* a = func("AAAA"); //MSG* b = func("BBBB"); //delete a; //delete b; //d) MSG* v = new MSG[3]; // com este construtor MSG(const string & s); nao funciona //só funciona com construtor por omissão MSG* v0 = new MSG[2]{ {"primeiro"}, {"segundo"} }; //e) delete [] v; delete [] v0; //não se pode libertar espaço do MSG* v = new MSG[3]; //quando se liberta é todos de uma vez cout << "\nfim do main" << endl; return 0; }
………..ficha5, exercicio2 (a15, a16)
#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 | +--- */ class ABC { char* p; public: ABC(const char* s); ~ABC(); //c const char* getConteudo() const; //c) construtor por copia ABC(const ABC& ob); //c) operador atribuição ABC& operator=(const ABC & ob); }; ABC::ABC(const char* s) { p = new char[strlen(s) + 1]; //construtor cria, composição strcpy(p, s); cout << "\nconstruindo .." << p << endl; } ABC::~ABC() { cout << "\ndestruindo .." << p << endl; delete[] p; } const char* ABC::getConteudo() const { return p; } //ABC::ABC(const ABC& ob) //c) versão um //{ // p = nullptr; // //ver se estamos a copiar uma string vazia // if(ob.p == nullptr || strlen(ob.p)==0) // { // return; // } // //alocar espaco para copiar a string da origem da copia // p = new char[strlen(ob.p) + 1]; // //copiar para o proprio espaco // strcpy(p,ob.p); // // cout << "\nconstrutor por copia: " << p << endl; //} ABC& ABC::operator=(const ABC& ob) //c) { //operador atribuição tem: //prevenção da auto atribuição if (this == &ob) { return *this; } //libertacao de memoria apontada pelo prim membro de atribuição delete[]p; //ponteiro que tem lixo //limpar objecto p = nullptr; //se estamos a copiar uma string vazia if(ob.p == nullptr || strlen(ob.p)==0) { return *this; } //alocar espaco para copiar a string do segundo membro p = new char[strlen(ob.p) + 1]; //copiar a string do seg membro para um espaco proprio strcpy(this->p, ob.p); cout << "\nOperador atribuicao "; return *this; } //c) alternativa versao dois //construtor por copia à custa do operador atribuição ABC::ABC(const ABC& ob) { p = nullptr; *this = ob; //ao fazer esta atribuição chama.se o operator= cout << "\n CCop " << (p != nullptr ? p : nullptr) << " - " << ob.p << endl; } //b void gastaMemoria() { ABC temp("\nTexto temporario que ocupa espaco"); } //c) void func(ABC a) { //o a é passado por valor //o a é criado pro copia de y, com o construtor por cópia //o construtor automatico, faz copia de membro a membro } void func() { ABC a("aaa"); ABC b("bbb"); a = b; } int main() { //b //for(unsigned int i = 0; i<10 ; i++) //{ // gastaMemoria(); //} //c //a classe não tem construtor por cópia //a classe não tem operador de atribuição //apos o construtor por copia ABC y("ola y"); cout << "conteudo do y: " << y.getConteudo() << endl; func(y); cout << "conteudo do y: " << y.getConteudo() << endl; //apos o operador de atribuição e a versao dois func(); cout << "\nfim do main" << endl; }
………..ficha5, exercicio5 (a16)
#include <string> #include <iostream> #include <sstream> #include <vector> #include <regex> #include <initializer_list> #include <fstream> using namespace std; //versão matriz dinamica class Pessoa { string nome; long bi; long nif; void setBi(long b); public: Pessoa() = delete; Pessoa(const string& s, long b, long n); string getNome()const; void setNome(const string& n); long getBi()const; long getNif()const; void setNif(long t); string getAsString()const; }; Pessoa::Pessoa(const string& s, long b, long n) : nome(s), bi(b), nif(n) { } string Pessoa::getNome()const { return nome; } void Pessoa::setNome(const string& n) { nome = n; } long Pessoa::getBi()const { return bi; } void Pessoa::setBi(long b) { bi = b; } long Pessoa::getNif()const { return nif; } void Pessoa::setNif(long t) { nif = t; } string Pessoa::getAsString()const { ostringstream oss; oss << "\nNome: " << nome << "\nBi: " << bi << "\nNif: " << nif << endl; return oss.str(); } class Clube { Pessoa** socios; //vector <Pessoa *> socios; int tam; public: Clube(int t); ~Clube(); void setMembroDoclube(Pessoa* p, int pos); //construtor por copia Clube(const Clube& ob); //operador atribuição Clube & operator=(const Clube & ob); string getAsString() const; }; Clube::Clube(int t) { tam = t > 0 ? t : 0; if(tam == 0) { socios = nullptr; return; } socios = new Pessoa * [tam]; //tam, é um array tam, de tam Pessoa *. if (socios == nullptr) { tam = 0; return; } for (unsigned int i = 0; i < tam; i++) socios[i] = nullptr; //tudo igual a nulltpr } Clube::~Clube() { delete[]socios; //liberta o array dinamico dos ponteiros //nao existe o ciclo for para deletar as pessoas //ninguem toca nas pessoas } //v1 //void Clube::setMembroDoclube(Pessoa* p, int pos) //{ // socios[pos] = p; //socios 0 = endereço de p //} //v2 void Clube::setMembroDoclube(Pessoa* p, int pos) { if(pos >= 0 && pos < tam && socios[pos] == nullptr) { socios[pos] = p; } } Clube::Clube(const Clube& ob) { //limpar os ponteiros aos quais o operador atribuicao vai fazer delete socios = nullptr; tam = 0; //aplicar o operador atribuição *this = ob; } Clube & Clube::operator=(const Clube& ob) { //prevenção da auto atribuição if(this == &ob) { return *this; } //limpar memoria velha delete[] socios; //a seguir é necessário o nullptr socios = nullptr; tam = 0; //se a origem da copia for um clube sem socios if(ob.socios == nullptr || ob.tam ==0 ) { return * this; } //se a origem da copia for um clube com socios socios = new Pessoa * [ob.tam]; //copiar o tam tam = ob.tam; //copiar os ponteiros for(unsigned int i = 0; i < tam; i++) { //nao se duplicam os cosios porque a relacao entre clube e socios e de agregacao //o destrutor tambem nao os destroi socios[i] = ob.socios[i]; } return *this; } string Clube::getAsString() const { ostringstream oss; oss << "\nTam: " << tam << endl; for (unsigned int i = 0; i < tam; i++) { if (socios[i] != nullptr) { oss << socios[i]->getAsString() << endl; } } return oss.str(); } int main() { //agregacao entre o clube e as pessoas //relação entre o clube e o array de ponteiros é de composição Pessoa a("aaa",1,111), b("bbb", 2, 222); Clube* clube1 = new Clube(50); clube1->setMembroDoclube(&a, 0); clube1->setMembroDoclube(&b, 1); cout << "Clube1: " << clube1->getAsString(); Pessoa c("ccc", 3, 333), d("ddd", 4, 444); Clube* clube2 = new Clube(10); clube2->setMembroDoclube(&a, 0); clube2->setMembroDoclube(&b, 1); clube2->setMembroDoclube(&c, 2); clube2->setMembroDoclube(&d, 3); cout << "Clube2: " << clube2->getAsString(); *clube1 = *clube2; //atribuir os apontados delete clube2; cout << "Clube2 depois: " << clube1->getAsString(); //copia do apontado Clube clube3(*clube1); cout << "Clube3 depois: " << clube3.getAsString(); cout << "\nfim do main" << endl; }
………..ficha5, exercicio5 (a16,)
#include <string> #include <iostream> #include <sstream> #include <vector> #include <regex> #include <initializer_list> #include <fstream> using namespace std; //versão vector class Pessoa { string nome; long bi; long nif; void setBi(long b); public: Pessoa() = delete; Pessoa(const string& s, long b, long n); string getNome()const; void setNome(const string& n); long getBi()const; long getNif()const; void setNif(long t); string getAsString()const; }; Pessoa::Pessoa(const string& s, long b, long n) : nome(s), bi(b), nif(n) { } string Pessoa::getNome()const { return nome; } void Pessoa::setNome(const string& n) { nome = n; } long Pessoa::getBi()const { return bi; } void Pessoa::setBi(long b) { bi = b; } long Pessoa::getNif()const { return nif; } void Pessoa::setNif(long t) { nif = t; } string Pessoa::getAsString()const { ostringstream oss; oss << "\nNome: " << nome << "\nBi: " << bi << "\nNif: " << nif << endl; return oss.str(); } class Clube { //Pessoa** socios; vector <Pessoa *> socios; int tam; public: Clube(int t); //~Clube(); void setMembroDoclube(Pessoa* p, int pos); //construtor por copia //Clube(const Clube& ob); //operador atribuição //Clube& operator=(const Clube& ob); //Nesta versao não é preciso construtor por copia, atribuição e destrutor //Por nesta classe so usarmos ponteiros, e não ciramos nenhuma memoria dinamica, logo não existe necessidade de cópiar nada string getAsString() const; }; //Clube::Clube(int t) //{ // tam = t > 0 ? t : 0; // if (tam == 0) // { // socios = nullptr; // return; // } // socios = new Pessoa * [tam]; //tam, é um array tam, de tam Pessoa *. // if (socios == nullptr) { // tam = 0; // return; // } // for (unsigned int i = 0; i < tam; i++) // socios[i] = nullptr; //tudo igual a nulltpr //} Clube::Clube(int t) { for (unsigned int i = 0; i < t; i++) { socios.push_back(NULL); } } //v1 //Clube::~Clube() //{ // delete[]socios; //liberta o array dinamico dos ponteiros // //nao existe o ciclo for para deletar as pessoas // //ninguem toca nas pessoas //} //v1 //void Clube::setMembroDoclube(Pessoa* p, int pos) //{ // socios[pos] = p; //socios 0 = endereço de p //} //v2 //void Clube::setMembroDoclube(Pessoa* p, int pos) //{ // if (pos >= 0 && pos < tam && socios[pos] == nullptr) // { // socios[pos] = p; // } //} //v3 vestores void Clube::setMembroDoclube(Pessoa* p, int pos) { if (pos >= 0 && pos < socios.size() && socios[pos] == NULL) { socios[pos] = p; // Notar que o obj. Pessoa e visto pelo Clube } } //Clube::Clube(const Clube& ob) //{ // //limpar os ponteiros aos quais o operador atribuicao vai fazer delete // socios = nullptr; // tam = 0; // //aplicar o operador atribuição // *this = ob; //} // //Clube& Clube::operator=(const Clube& ob) //{ // //prevenção da auto atribuição // if (this == &ob) // { // return *this; // } // //limpar memoria velha // delete[] socios; //a seguir é necessário o nullptr // socios = nullptr; // tam = 0; // // //se a origem da copia for um clube sem socios // if (ob.socios == nullptr || ob.tam == 0) // { // return *this; // } // //se a origem da copia for um clube com socios // socios = new Pessoa * [ob.tam]; // //copiar o tam // tam = ob.tam; // //copiar os ponteiros // for (unsigned int i = 0; i < tam; i++) // { // //nao se duplicam os cosios porque a relacao entre clube e socios e de agregacao // //o destrutor tambem nao os destroi // socios[i] = ob.socios[i]; // } // return *this; //} //v1 //string Clube::getAsString() const //{ // ostringstream oss; // oss << "\nTam: " << tam << endl; // for (unsigned int i = 0; i < tam; i++) { // if (socios[i] != nullptr) { // oss << socios[i]->getAsString() << endl; // } // } // // return oss.str(); //} //v2 vectores string Clube::getAsString()const { ostringstream oss; oss << "\nTam: " << socios.size() << endl; for (unsigned int i = 0; i < socios.size(); i++) { if (socios[i] != nullptr) { oss << socios[i]->getAsString() << endl; // tem de uusar -> } } return oss.str(); } int main() { //agregacao entre o clube e as pessoas //relação entre o clube e o array de ponteiros é de composição Pessoa a("aaa", 1, 111), b("bbb", 2, 222); Clube* clube1 = new Clube(50); clube1->setMembroDoclube(&a, 0); clube1->setMembroDoclube(&b, 1); cout << "Clube1: " << clube1->getAsString(); Pessoa c("ccc", 3, 333), d("ddd", 4, 444); Clube* clube2 = new Clube(10); clube2->setMembroDoclube(&a, 0); clube2->setMembroDoclube(&b, 1); clube2->setMembroDoclube(&c, 2); clube2->setMembroDoclube(&d, 3); cout << "Clube2: " << clube2->getAsString(); *clube1 = *clube2; //atribuir os apontados delete clube2; cout << "Clube2 depois: " << clube1->getAsString(); //copia do apontado Clube clube3(*clube1); cout << "Clube3 depois: " << clube3.getAsString(); cout << "\nfim do main" << endl; }
………..ficha5, exercicio7 (a17)
#include <string> #include <iostream> #include <sstream> #include <vector> #include <regex> #include <initializer_list> #include <fstream> using namespace std; //relação da agenda com contacto é de composição //qd a agenda for destruida os contactos tb são //contactos: objecto em memória dinamica //usar vectores, sem necessidade de indicar quantidades //matriz dinamics de ponteiros class Contacto { string nome; unsigned int tel; public: Contacto() = delete; Contacto(const string& s, unsigned int t); string getNome()const; void setNome(const string& n); unsigned int getTel()const; void setTel(unsigned int t); string getAsString()const; }; Contacto::Contacto(const string& s, unsigned t):nome(s), tel(t) { } string Contacto::getNome() const { return nome; } void Contacto::setNome(const string& n) { this->nome = n; } unsigned Contacto::getTel() const { return tel; } void Contacto::setTel(unsigned t) { this->tel = t; } string Contacto::getAsString() const { ostringstream oss; oss << "Contacto " << " Nome: " << nome << "\tTel: " << tel; return oss.str(); } class Agenda { string nome; vector<Contacto*> contactos; //vector de ponteiros //o objecto composto vai destruir a string e o vector de ponteiros //mas não os apontados, tem que haver um destrutor que faça a libertação dos apontados //pois não existe mais nada no programa que conheça os apontados (ver destrutor da Agenda) int pesquisa(const string& s)const; public: Agenda(const string& nome0); Agenda(const Agenda& ob); //construtor por copia Agenda& operator=(const Agenda& ob); //operador = ~Agenda(); string getNome()const; void setNome(const string& nome0); bool acrescentaContacto(const string& n, unsigned int i); bool removeContacto(const string& n); string getAsString()const; const Contacto * getContacto(const string& s); bool gravaContactosEmFicheiroDeTexto(); bool lerContactosDeFicheiroDeTexto(); }; int Agenda::pesquisa(const string& s) const { for(unsigned int i = 0 ; i < contactos.size(); i++) { if(contactos[i]->getNome() == s) { return i; } } return -1; } Agenda::Agenda(const string& nome0):nome(nome0) { } Agenda::Agenda(const Agenda& ob) { //existem dois membros da classe: nome e vector *this = ob; cout << "\n CCop " << ob.getAsString() << endl; } Agenda& Agenda::operator=(const Agenda& ob) //a.operator(b), a apontado por this ou *this, //b é recebido pela ref. ob { //testar a auto atribuição if(this == &ob) { return *this; } //destruir os objectos apontados pelo primeiro membro de atribuição for(Contacto * c: contactos) { delete c; } //esvaziar o vector contactos contactos.clear(); //copiar o segundo membro da atribuição for(Contacto * c : ob.contactos) { Contacto* dupplicado = new Contacto(*c); contactos.push_back(dupplicado); } return *this; } Agenda::~Agenda() { //obrigatório por ser relação de composição //e existe uma estrutura de vectores de ponteiros for(Contacto * c: contactos) { delete c; } } string Agenda::getNome() const { return nome; } void Agenda::setNome(const string& nome0) { this->nome = nome0; } bool Agenda::acrescentaContacto(const string& n, unsigned int t) { int qual = pesquisa(n); if(qual != -1) { return false; } contactos.push_back(new Contacto(n, t)); return true; } bool Agenda::removeContacto(const string& n) { int qual = pesquisa(n); if(qual == -1) { return false; } delete contactos[qual]; //nunca sera erase, e primeiro faz-se sempre o erase e depois o delete //relação da classe é de composição: 1º deçete, 2º depois erase. //se a relação for de agregação é só o erase //sendo composição: //o delete: liberta a memoria dinamica apontada //o erase: tira a posição do vector, tira o ponteiro, erase será do vector //se fizer o delete e nao fizer o erase, o ponteiro fica apontar para lixo, e o destrutor vai fazer duplo delete, erro de execução //erase e depois o delete: erase da pos zero, e depois o delete de contactos zero.. não faz sentido contactos.erase(contactos.begin() + qual); return true; } string Agenda::getAsString() const { ostringstream oss; oss << nome << endl; for(Contacto * p: contactos) { oss << endl << p->getAsString(); } return oss.str(); } const Contacto* Agenda::getContacto(const string& s) { int qual = pesquisa(s); if(qual == -1) { return nullptr; }else { return contactos[qual]; } } bool Agenda::gravaContactosEmFicheiroDeTexto() { ofstream dados("dados.txt"); if (!dados.is_open()) { return false; } for (unsigned int i = 0; i < contactos.size(); i++) { dados << contactos[i]->getTel() << " " << contactos[i]->getNome() << endl; } dados.close(); if (dados) { return true; } else return false; } bool Agenda::lerContactosDeFicheiroDeTexto() { ifstream dados("dados.txt"); string nome; unsigned int tel; string s; if (!dados.is_open()) { return false; } // ler dados de todas as pessoas // uma por linha while (!dados.eof()) { // ler string com os dados da pessoa getline(dados, s); istringstream iss(s); // ler dados da pessoa iss >> tel >> std::ws; getline(iss, nome); // se correu bem a leitura ... if (iss) { acrescentaContacto(nome, tel); } } dados.close(); return true; } int main() { Agenda* a1 = new Agenda("a minha agenda 2021"); a1->acrescentaContacto("pedro", 1234); a1->acrescentaContacto("maria", 5678); cout << "\nAgenda: " << a1->getAsString() << endl; a1->gravaContactosEmFicheiroDeTexto(); Agenda* a2 = new Agenda("a minha agenda 2022"); a2->lerContactosDeFicheiroDeTexto(); cout << "\nAgenda: " << a2->getAsString() << endl; Agenda* a3 = new Agenda("a minha agenda especial"); *a3 = *a2; delete a2; a3->removeContacto("maria"); cout << "\nAgenda: " << a3->getAsString() << endl; cout << "\nsair do main" << endl; return 1; }
operadores
………..ficha4, exercicio1 (a13, a14)
#include <string> #include <iostream> #include <sstream> #include <vector> #include <regex> #include <initializer_list> #include <fstream> using namespace std; //os operadores //uso de operados de atribuiçao em situações de composição envolvendo memória dinâmica //aumentar a clareza do código por exemplo a.multiplica(b) po a * b //operadores podem ser globais ou membros //p.e.: globaL operator++(a,b) //p.e.: membro a.operator++(b) /* +---------------------------------------- + -------------------------- - + | 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 | +---------------------------------------- + -------------------------- - + */ //o retorno de um operador pode ser um valor ou uma cópia de algo //se o objectivo é usar o resultado de um operador, então este deve ser uma referência para algo, não constante e que pode ser modificado class Fraccao { int numerador; int denominador; public: //explicit //se usado trancamos o construtor, fazendo com que tenhamos que usar implicitamente Fracca(a) , na main //explicit, indicar ao construtor que só trabalhar quando o mandarmos trabalhar Fraccao(); Fraccao(int num); Fraccao(int num, int denom); int getNumerador() const; void setNumerador(const int numerador); int getDenominador() const; void setDenominador(const int denominador); string getAsString() const; //b v3 Fraccao operator*(const Fraccao& f); //operador * membro //j) Fraccao & operator*=(const Fraccao& f); //operador *= membro, não pode ser void //m) membro, operador unário Fraccao & operator++(); //++a Fraccao operator++(int n); //a++, int n, serve para poderem funcionar as duas, mesmo que nao faça nada //n) passamos uma fraccao mas a f recebe apenas um inteiro //operador de conversao operator int()const { return denominador/numerador; }; }; Fraccao::Fraccao() { numerador = 0; denominador = 1; } Fraccao::Fraccao(int num) :numerador(num) { denominador = 1; } Fraccao::Fraccao(int num, int denom):numerador(num) { setDenominador(denom); } int Fraccao::getNumerador() const { return numerador; } void Fraccao::setNumerador(const int numerador) { this->numerador = numerador; } int Fraccao::getDenominador() const { return denominador; } void Fraccao::setDenominador(const int denominador) { if(denominador >0) { this->denominador = denominador; }else if(denominador ==0) { this->denominador = 1; }else { this->numerador = -this->numerador; this->denominador = -denominador; } } string Fraccao::getAsString() const { ostringstream oss; oss << " ( " << numerador << " / " << denominador << " ) " << endl; return oss.str(); } //b, v3 Fraccao Fraccao::operator*(const Fraccao& f) { cout << "operator*(const Fraccao& f)\n"; Fraccao prod(getNumerador() * f.getNumerador(), getDenominador() * f.getDenominador()); return prod; } Fraccao & Fraccao::operator*=(const Fraccao & f) { cout << "operator*=(const Fraccao & f)\n"; numerador *= f.getNumerador(); denominador *= f.getDenominador(); return *this; } Fraccao& Fraccao::operator++() { numerador += denominador; //a fracao aumenta uma unidade return *this; //retorna objecto depois de incremento } Fraccao Fraccao::operator++(int n) { Fraccao aux = *this; //grava para esta varavel auxiliar o objecto antes de incrementar numerador += denominador; //a fracção aumenta uma unidade return aux; //não pode ser por referencia, retorna-se a variavel local } //b, v1 Fraccao produto(const Fraccao& x, const Fraccao& y) //função global { Fraccao prod(x.getNumerador() * y.getNumerador(), x.getDenominador() * y.getDenominador()); return prod; } //b, v2 Fraccao operator*(const Fraccao& x, const Fraccao& y) //função global { cout << "operator*(const Fraccao& x, const Fraccao& y)\n"; Fraccao prod(x.getNumerador() * y.getNumerador(), x.getDenominador() * y.getDenominador()); return prod; } //g ostream & operator<<(ostream & saida, const Fraccao & ob) { saida << ob.getAsString(); return saida; } //extra istream& operator>>(istream& entrada, Fraccao& ob) { int num, denom; entrada >> num, denom; if(entrada) { ob.setNumerador(num); ob.setDenominador(num); } return entrada; } //n) void func(int n) { cout << n; // aparece 2 } //o) (a==b) bool operator==(const Fraccao& op1, const Fraccao& op2); bool operator==(const Fraccao& op1, const Fraccao& op2) { return (op1.getNumerador() * op2.getDenominador() == op1.getDenominador() * op2.getNumerador()); } int main() { //a) /*Fraccao a(1, 2); Fraccao b(3); const Fraccao c(3, 4); cout << a.getAsString(); cout << b.getAsString(); cout << c.getAsString();*/ //b) multiplicação de duas fraccoes //v1 //Fraccao a(1, 2); //Fraccao b(3); //const Fraccao c(3, 4); //Fraccao a1; //a1 = produto(b,c); //cout << a1.getAsString(); //v2 //a = b * c; // a = operator(b,c); global //cout << a.getAsString(); //v3 (estando as duas opções disponiveis, global ou membro, recai sobre o membro) //a = b * c;// a = b.operator*(c); membro //cout << a.getAsString(); //c) //Fraccao a(1, 2); //Fraccao b(3); //const Fraccao c(3, 4); //a = a * b * c; //composição das funções, (a*b)*c //operator*(operator*(a,b),c) //cout << a.getAsString(); //d e e) //Fraccao a(1, 2); //Fraccao b(3); //a = b * 4; //b.operator*(4) //cout << a.getAsString(); //d e e) v2 construtor explicit //a = b * Fraccao(4); //só assim funcionaria //d e e) v3 //Fraccao a(1, 2); //Fraccao b(3); //a = 4 * b; //funciona apenas o global, se for membro só se usado o explicit, Fraccao(4) * b; //cout << a.getAsString(); //g) v1 //Fraccao a(1, 2); //cout << a; //<<, operador binário, tem que ser operador global //cout está a invocar a nossa operação, cout é da classes ostream, não é da nossa classe, logo << tem que ser global //g e h) v2 //Fraccao a(1, 2); //Fraccao b(3); //const Fraccao c(3, 4); //cout << a << b << c; //por ser global e ostream ao inves de void funciona em cadeia //i) ao inves de copia usar o valor, ostream & operator<<(ostream saida, const Fraccao & ob) //não dá...dá erro //extra //Fraccao a(1, 2); //Fraccao b(3); //cin >> a; //cout << a.getAsString(); //j) a *= b //Fraccao a(1, 2); //Fraccao b(2,3); ////a *= b; ////operador global: operator*=(a,b) ////operador membro: a.operator*=(b) //recomendada ////*= te como retorno //cout << "antes->" << " a: " << a << " b: " << b << endl; //a *= b; //cout << "depois->" << " a: " << a << " b: " << b << endl; //Fraccao a2(1, 2); //Fraccao b2(2, 3); //Fraccao c2(3, 4); //cout << "antes->" << " a2: " << a2 << " b2: " << b2 << " c2: " << c2 << endl; //a2 *= b2 *= c2; //cout << "depois->" << " a2: " << a2 << " b2: " << b2 << " c2: " << c2 << endl; //Fraccao a3(1, 2); //Fraccao b3(2, 3); //Fraccao c3(3, 4); //cout << "antes->" << " a3: " << a3 << " b3: " << b3 << " c3: " << c3 << endl; //(a3 *= b3) *= c3; //cout << "depois->" << " a3: " << a3 << " b3: " << b3 << " c3: " << c3 << endl; //l) retornar referencia ou valor //Fraccao a(1, 2), b(2, 3), c(3, 4); //cout << "antes->" << " a: " << a << " b: " << b << " c: " << c << endl; //(a *= b) *= c; //cout << "depois->" << " a: " << a << " b: " << b << " c: " << c << endl; //// é suposto aparecer 6/24 //cout << a; //cout << "expressao ((a *= b) *= c)" << ((a *= b) *= c) << endl; //retornar por referência Fraccao & Fraccao::operator*=(const Fraccao & f) //retornar por valor (é uma copia) Fraccao Fraccao::operator*=(const Fraccao & f) //m) posfixado, a++ e prefixado ++a //++a, global, operator++(a) //++a, membro, a.operator++() //não recebe nenhum argumento //prefixado //int n = 2; //cout << "++n= " << ((++n)) << endl; //3, e é possivel fazer uma atribuição (++n)=55, vem ++n=55 //cout << " n= " << n << endl; //3 ////posfixado //int n2 = 2; //cout << "n2++= " << ((n2++)) << endl; //2 //cout << " n2= " << n2 << endl; //3 //Fraccao a(1, 2), b(2, 3), c(3, 4); //(++a) = c; //cout << ++a; //a.operator++() //sem argumento //cout << a; //Fraccao a2(1, 2), b2(2, 3), c2(3, 4); //cout << a2++; //a.operator++(0) //0 é um argumento //cout << a2; //n) //const Fraccao f(7,3); //func(f); // é passado automaticamente o valor 7/3 // // arredondado para baixo //o) if(a==b) //tem que existir o operador== que retorne um bool, e é global Fraccao a(1, 2), b(1, 2); if(a== b) { cout << "oi"; }else { cout << "noi"; } cout << "\nfim do main" << endl; return 0; }
………..ficha4, exercicio3 (a14)
#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 | +--- */ class Automovel { const string matricula; //const para proibir atribuições string marca; string modelo; int ano; static int nAutomoveisCriados; //tem que ser inicializada fora da classe public: Automovel(const Automovel& ob); Automovel(string matricula, string marca, string modelo, int ano); ~Automovel(); string getMatricula()const; string getMarca()const; string getModelo()const; int getAno()const; static int getNAutomoveisCriados(); void setMarca(string marca); void setModelo(string modelo); void setAno(int ano); string getAsString()const; Automovel& operator=(const Automovel& ob); //retorna uma referencia para o primeiro membro da atribuição }; int Automovel::nAutomoveisCriados = 0; ostream& operator<<(ostream& saida, const Automovel& ob); Automovel::Automovel(const Automovel& ob):matricula(ob.matricula), marca(ob.marca), modelo(ob.modelo), ano(ob.ano) { cout << "\nConstrutor por copia"; ++nAutomoveisCriados; //tambem por copia, os construidos por cópia tb devem ser contados! } Automovel::Automovel(string matricula1, string marca1, string modelo1, int ano1): matricula(matricula1), marca(marca1), modelo(modelo1), ano(ano1) { cout << "\nConstrutor com parametros"; ++nAutomoveisCriados; } Automovel::~Automovel() { cout << "\nDestruindo " << getAsString(); } string Automovel::getMatricula()const { return matricula; } string Automovel::getMarca()const { return marca; } string Automovel::getModelo()const { return modelo; } int Automovel::getAno()const { return ano; } int Automovel::getNAutomoveisCriados() { return nAutomoveisCriados; } void Automovel::setMarca(string marca1) { marca = marca1; } void Automovel::setModelo(string modelo1) { modelo = modelo1; } void Automovel::setAno(int ano1) { ano = ano1; } string Automovel::getAsString()const { ostringstream oss; oss << "\nAutomovel: " << matricula << " " << marca << " " << modelo << " " << ano; return oss.str(); } Automovel& Automovel::operator=(const Automovel& ob) { // if (this == &ob) { return *this; } cout << "\nOperador atribuicao "; //a matricula nao se altera no objecto destino da atribuição this->marca = ob.marca; this->ano = ob.ano; this->modelo = ob.modelo; return *this; } ostream& operator<<(ostream& saida, const Automovel& ob) { saida << ob.getAsString() << endl; return saida; } void f(Automovel x) { cout << x << endl; } int main() { Automovel a1("11-11-AA", "OPEL", "OMEGA", 2010); Automovel a2("22-22-BB", "FIAT", "PUNTO", 2011); Automovel a3 = a1; //a3 copia de a1, construtor por copia a1 = a2; //operador atribuição, mas havendo membros constantes, tem que se fazer o operador operator= //a1.operator=(a2) f(a1); return 1; }
composição, agregação, vectores, ficheiros
………..ficha3, exercicio1 (a8)
#include <string> #include <iostream> #include <sstream> #include <vector> #include <regex> #include <initializer_list> using namespace std; //"nao deve ser possivel construir objectos desta classe sem a indicacação.." não pode haver construtor por omissão //"sem desrespeitar o encapsulamento.." gets e sets //"as funções que permitem obter os dados devem poder ser chamadas sobre bjectos constantes" devem conter o const class Ponto { private: //encapsulamento int x; int y; public: //Ponto(int x0, int y0); //necessário introduzir coordenadas ~Ponto(); Ponto(int x0 = 0, int y0 = 0); //construtor por omissão, e) //extra /*Ponto() { x = rand() % 100; y = rand() % 100; cout << "\nponto " << getAsString(); }*/ int getX() const { return x; } void setX(const int x) { this->x = x; } int getY() const { return y; } void setY(const int y) { this->y = y; } double calculaDistancia(const Ponto & outro)const; string getAsString()const; }; Ponto::Ponto(int x0, int y0) { x = x0; y = y0; cout << "\nPonto(in x0, int y0) " << getAsString(); } Ponto::~Ponto() { cout << "\n~Ponto() " << getAsString(); } double Ponto::calculaDistancia(const Ponto& outro) const { //pitágoras, calculo da distância double dist = (x - outro.x) * (x - outro.x) + (y - outro.y) * (y - outro.y); return sqrt(dist); } string Ponto::getAsString() const { ostringstream oss; oss << " ( " << x << " , " << y << " ) " << endl; return oss.str(); } int main() { Ponto a(1,1); Ponto b(2,2); cout << a.getAsString(); //as funções mmebros recebem um ponbteiro para o objectos que as invocou, daí tem acesso a e b cout << a.calculaDistancia(b); //c) const Ponto c(5, 6); //agora só posso chamar funcções que sejam const cout << c.getAsString(); cout << "c.getY(); " << c.getY(); //d) Ponto tab_d[] = {Ponto(1,3), Ponto(2,4), Ponto(5,7)}; //e) Ponto(int x0 = 0, int y0 = 0); //construtor por omissão, e) Ponto tab_e[3]; cout << "\nfim do main" << endl; return 0; }
………..ficha3, exercicio3 (a8, a9)
#include <string> #include <iostream> #include <sstream> #include <vector> #include <regex> #include <initializer_list> using namespace std; //composição de objectos class Ponto { int x; int y; public: //Ponto(); //construtor por omissao //Ponto(int x0, int y0); Ponto(int x0=0, int y0=0); //construtor por omissão Ponto(const Ponto& z); ~Ponto(); int getX() const { return x; } void setX(const int x) { this->x = x; } int getY() const { return y; } void setY(const int y) { this->y = y; } string getAsString() const; }; Ponto::Ponto(int x0, int y0) { x = x0; y = y0; cout << "\nponto(int x0, int y0) " << getAsString(); } Ponto::Ponto(const Ponto& z) { x = rand() % 100; y = rand() % 100; cout << "\nponto(const Ponto& z) " << getAsString(); } Ponto::~Ponto() { cout << "~Ponto()"; } string Ponto::getAsString() const { ostringstream oss; oss << " ponto x" << x << " y " << y << endl; return oss.str(); } class Rectangulo //objecto composto { Ponto canto; int largura; int altura; public: Rectangulo(int x, int y, int largura0, int altura0); Rectangulo(const Ponto& p0, int largura0, int altura0); ~Rectangulo(); Ponto getCanto() const { return canto; } int getX()const { return canto.getX(); } int getY()const { return canto.getY(); } int getLargura() const { return largura; } int getAltura() const { return altura; } bool setLargura(int larg0); bool setAltura(int alt0); void setCanto(const Ponto& c); string getAsString() const; int calculaArea()const; }; Rectangulo::Rectangulo(int x, int y, int largura0, int altura0):canto(x,y) //canto(x,y) membro objecto { if(!setLargura(largura0)) { largura = 1; } if (!setAltura(altura0)) { altura = 1; } cout << "\nrectangulo int x, int y.." << getAsString(); } Rectangulo::Rectangulo(const Ponto& p0, int largura0, int altura0):canto(p0) { cout << "\nrectangulo const Ponto& p0.." << getAsString(); } Rectangulo::~Rectangulo() { cout << "~Rectangulo()" << getAsString(); } bool Rectangulo::setLargura(int larg0) { if(larg0<0) { return false; } largura = larg0; return true; } bool Rectangulo::setAltura(int alt0) { if(alt0<0) { return false; } altura = alt0; return true; } void Rectangulo::setCanto(const Ponto& c) { canto = c; } string Rectangulo::getAsString() const { ostringstream oss; oss << " rectangulo " << canto.getAsString() << " larg: " << largura << " alt: " << altura << endl; return oss.str(); } int Rectangulo::calculaArea() const { return largura * altura; } int main() { //a) relação de composição //b) //Rectangulo a(1, 2, 4, 2); //cout << "\na:" << a.getAsString() << endl; //Rectangulo b(1, 2, 44, 22); //cout << "\nb:" << a.getAsString() << endl; //os cantos são iguais, mas estão localizados em sitios diferentes de memória.. //cada rectangulo tem a posso exclusiva do seu canto. mas são diferentes const Rectangulo c(1, 2, 4, 2); c.getLargura(); cout << "\nfim do main" << endl; return 0; }
………..ficha3, exercicio4 (a9, a10)
#include <string> #include <iostream> #include <sstream> #include <vector> #include <regex> #include <initializer_list> using namespace std; class Ponto { int x; int y; public: //Ponto(); //construtor por omissao //Ponto(int x0, int y0); Ponto(int x0 = 0, int y0 = 0); //construtor por omissão Ponto(const Ponto& z); ~Ponto(); int getX() const { return x; } void setX(const int x) { this->x = x; } int getY() const { return y; } void setY(const int y) { this->y = y; } string getAsString() const; //calcular a distancia entre dois pontos double calculaDistancia(const Ponto& outro)const; bool isIgual(const Ponto& outro)const; }; Ponto::Ponto(int x0, int y0) { x = x0; y = y0; //cout << "\nponto(int x0, int y0) " << getAsString(); } Ponto::Ponto(const Ponto& z) { x = rand() % 100; y = rand() % 100; //cout << "\nponto(const Ponto& z) " << getAsString(); } Ponto::~Ponto() { cout << "~Ponto()"; } string Ponto::getAsString() const { ostringstream oss; oss << " ponto x " << x << " y " << y << endl; return oss.str(); } double Ponto::calculaDistancia(const Ponto& outro) const { //pitágoras, calculo da distância double dist = (x - outro.x) * (x - outro.x) + (y - outro.y) * (y - outro.y); return sqrt(dist); } bool Ponto::isIgual(const Ponto& outro) const { return x == outro.x && y == outro.y; } class Rectangulo //objecto composto { Ponto canto; int largura; int altura; public: Rectangulo(int x, int y, int largura0, int altura0); //Rectangulo(const Ponto& p0, int largura0, int altura0); //Rectangulo(const Rectangulo& r); //construtor por cópia ~Rectangulo(); Ponto getCanto() const { return canto; } int getX()const { return canto.getX(); } int getY()const { return canto.getY(); } int getLargura() const { return largura; } int getAltura() const { return altura; } bool setLargura(int larg0); bool setAltura(int alt0); void setCanto(const Ponto& c); string getAsString() const; int calculaArea()const; }; Rectangulo::Rectangulo(int x, int y, int largura0, int altura0) :canto(x, y) //canto(x,y) membro objecto { if (!setLargura(largura0)) { largura = 1; } if (!setAltura(altura0)) { altura = 1; } //cout << "\nrectangulo int x, int y.." << getAsString(); } //Rectangulo::Rectangulo(const Rectangulo& r) //{ // *this = r; // cout << "\nRectangulo(const Rectangulo& r) " << getAsString() << endl; //} //Rectangulo::Rectangulo(const Ponto& p0, int largura0, int altura0) :canto(p0) //{ // cout << "\nrectangulo const Ponto& p0.." << getAsString(); //} Rectangulo::~Rectangulo() { cout << "~Rectangulo()" << getAsString(); } bool Rectangulo::setLargura(int larg0) { if (larg0 < 0) { return false; } largura = larg0; return true; } bool Rectangulo::setAltura(int alt0) { if (alt0 < 0) { return false; } altura = alt0; return true; } void Rectangulo::setCanto(const Ponto& c) { canto = c; } string Rectangulo::getAsString() const { ostringstream oss; oss << " rectangulo " << canto.getAsString() << " larg: " << largura << " alt: " << altura << endl; return oss.str(); } int Rectangulo::calculaArea() const { return largura * altura; } class Desenho { string nome; vector<Rectangulo> rectangulos; //coleccão de rectangulos //ao ser destruido o vector são destruidos os seus elementos, //são destruidos os rectangulos //existe assim uma relação de composição //relação de posse exclusiva public: Desenho(string nome0); ~Desenho(); void acrescentar(int x, int y, int alt, int larg); //um rectangulo int calculaAreda()const; vector<Rectangulo> pesquisarRectMesmoCanto(const Ponto& p)const; //const, função de consulta, e retorna o conjunto dos rect que satifazem a condição int somaDasAreas()const; int calculaArea()const; string getAsString() const; bool eliminarUm(unsigned int qual); int eliminarRectAreaSup(int areaLimite); }; Desenho::Desenho(string nome0)//:nome(nome0) { //ou nome = nome0; //ou //se nada for indicado, ele vem construido na mesma sendo usada o construtor por omissão } Desenho::~Desenho() { cout << "\n~Desenho" << getAsString(); } void Desenho::acrescentar(int x, int y, int larg , int alt) { Rectangulo rect(x, y, larg, alt); rectangulos.push_back(rect); //é feito uma cópia do rect para o vector, pelo construtor por cópia //ou //rectangulos.push_back(Rectangulo(x, y, larg, alt)); } int Desenho::calculaAreda() const { return 1; } vector<Rectangulo> Desenho::pesquisarRectMesmoCanto(const Ponto& p) const { vector<Rectangulo> v; for(const auto & rect : rectangulos) { //ou if(rect.getCanto().isIgual(p)) { v.push_back(rect); } //ou, mas falha o encapsulamento //pois é a classe do ponto que sabe se dois pontos são iguais //pois quem deve ter a funcionalidade é a classe que tem a informação correspondente //assim não deve ser a classe desenho a faze-lo //if(rect.getCanto().getX() == p.getX() && rect.getCanto().getY() == p.getY()) //{ // v.push_back(rect); //} } return v; } int Desenho::somaDasAreas() const { int soma = 0; //ou for(vector<Rectangulo>::const_iterator it = rectangulos.begin(); it != rectangulos.end(); ++it) { soma += it->calculaArea(); } //ou for(auto it = rectangulos.begin(); it != rectangulos.end(); ++it) { soma += it->calculaArea(); } //ou for(unsigned int i= 0; i< rectangulos.size(); i++) { soma += rectangulos[i].calculaArea(); } //ou for(const auto & elem:rectangulos) { soma += elem.calculaArea(); } return soma; } int Desenho::calculaArea() const { int area = 0; return area; } string Desenho::getAsString() const { ostringstream oss; oss << " nome " << nome << " tem " << rectangulos.size() << " rectangulos \n "; //ou for(unsigned int i = 0; i< rectangulos.size(); i++){ oss << rectangulos[i].getAsString() << endl; } //ou //for( auto & rect : rectangulos) //{ // oss << rect.getAsString() << endl;; //} //ou iteradores //for(vector<Rectangulo>::const_iterator it =rectangulos.begin(); it != rectangulos.end(); ++it) //{ // oss << it->getAsString() << endl; //} return oss.str(); } bool Desenho::eliminarUm(unsigned qual) //qual: indice { { if (qual < 0 || qual >= rectangulos.size()) { return false; } rectangulos.erase(rectangulos.begin() + qual); //o vector auto-reorganiza-se //é um iterator: rectangulos.begin() + qual return true; } } int Desenho::eliminarRectAreaSup(int areaLimite) { //serve para coleções //https://www.cplusplus.com/reference/vector/vector/erase/ int nEliminar = 0; for(vector<Rectangulo>::iterator it = rectangulos.begin(); it != rectangulos.end();) { if(it->calculaArea() > areaLimite) { it = rectangulos.erase(it); ++nEliminar; }else { ++it; } } return nEliminar; //não era necessaria esta informação } int main() { Desenho a1("janela"); cout << "\na1"; a1.acrescentar(1, 2, 3, 4); a1.acrescentar(5, 6, 7, 8); a1.getAsString(); cout << "\nfim do main.." << endl; return 0; }
………..ficha3, exercicio7 (a11, a12)
#include <string> #include <iostream> #include <sstream> #include <vector> #include <regex> #include <initializer_list> #include <fstream> using namespace std; //relação entre banco, conta, pessoa e arquivo de identificacao: //relação entre banco e conta: composição (banco cria a conta) //quando o banco for destruído as contas tambem o são //relação entre conta e pessoa: agregação //relação entre arquivo de identificacao e pessoa: composição (arquivo cria a pessoa) class Pessoa { //objecto dinamico, que não muda. string nome; long bi; long nif; void setBi(long bi); //alteração é privado public: Pessoa(const string& s, long b, long n); Pessoa() = delete; //não disponbilizamos construtor por omissão, fica proibido ~Pessoa(); string getNome() const; void setNome(const string& nome); long getBi() const; long getNif() const; void setNif(const long nif); string getAsString()const; string getDados()const; }; Pessoa::~Pessoa() { cout << "~Pessoa()" << endl; } string Pessoa::getNome() const { return nome; } void Pessoa::setNome(const string& nome) { this->nome = nome; } long Pessoa::getBi() const { return bi; } void Pessoa::setBi(const long bi) { this->bi = bi; } Pessoa::Pessoa(const string& s, long b, long n):nome(s), bi(b),nif(n) { } long Pessoa::getNif() const { return nif; } void Pessoa::setNif(const long nif) { this->nif = nif; } string Pessoa::getAsString() const { ostringstream oss; oss << "nome: " << nome << " bi: " << bi << " nif: " << nif << endl; return oss.str(); } string Pessoa::getDados() const { //ficheiro de dados, linha ostringstream oss; oss << bi << " " << nif << nome << endl; return oss.str(); } class ArquivoDeIdentificacao { //vector de ponteiros para pessoas //ou vector de pessoas/objectos (não ia funcionar bem, porque na conta existe um ponteiro para pessoa, e se for eliminado no arquivo o ponteiro fica como?) //o destrutor tem que destruir primeiro as pessoas, libertar a memória com delete string nome; vector<Pessoa* > pessoas; int pesquisa(long bi)const; public: ArquivoDeIdentificacao(string nome0); ArquivoDeIdentificacao(const ArquivoDeIdentificacao& ob) = delete; //proibir a construção por cópia ArquivoDeIdentificacao& operator=(const ArquivoDeIdentificacao& ob) = delete; //proibir o operador atribuição, proibir a atribuição //esta dupla proibição tem a ver com evitar erros de execuação ~ArquivoDeIdentificacao(); string getNome() const; void setNome(const string& nome); bool acrescentaPessoa(string n, long b, long nif); //relação de posse o arquivo. string getDados()const; //para lidar com ficheiros const Pessoa * getPessoa(long bi); string getAstring()const; bool gravarPessoasEmFicheiroDeTexto(const ArquivoDeIdentificacao &arquivo); bool lerPessoasDeFicheiroDeTexto(ArquivoDeIdentificacao &arquivo); }; int ArquivoDeIdentificacao::pesquisa(long bi) const { //porque existe uma coleção for(unsigned int i = 0; i< pessoas.size(); i++) { if(pessoas[i]->getBi()==bi) { return i; } } return -1; } ArquivoDeIdentificacao::ArquivoDeIdentificacao(string nome0):nome(nome0) { } ArquivoDeIdentificacao::~ArquivoDeIdentificacao() { //o arquivo tem uma relação de composição: cria e destoi a pessoa for(Pessoa * p: pessoas) { cout << p->getAsString(); delete p; } //ou //for (int i = 0; i < pessoas.size(); i++) // delete pessoas[i]; } string ArquivoDeIdentificacao::getNome() const { return nome; } void ArquivoDeIdentificacao::setNome(const string& nome) { this->nome = nome; } bool ArquivoDeIdentificacao::acrescentaPessoa(string n, long b, long nif) { int qual = pesquisa(b); if(qual != -1) { return false; //já existe uma pessoa com este bi } pessoas.push_back(new Pessoa(n, b, nif)); //o arquivo tem uma relação de composição: cria e destoi a pessoa //new Pessoa(n, b, nif) //criar a pessoa em memória dinamica, e retorna o endereço //pessoas.push_back //acrescenta mais um elemento com o endereço da nova pessoa return true; } string ArquivoDeIdentificacao::getDados() const { //para lidar com ficheiros ostringstream oss; for(Pessoa * p: pessoas) { oss << p->getDados() << endl; } return oss.str(); } const Pessoa* ArquivoDeIdentificacao::getPessoa(long bi) //primeiro const: para nao alterar o ponteiro, damos acesso apenas aos dados para onde aponta (read only) { int qual = pesquisa(bi); if(qual == -1) { return nullptr; }else { return pessoas[qual]; } } string ArquivoDeIdentificacao::getAstring() const { ostringstream oss; for(Pessoa * p : pessoas) { oss << p->getAsString(); } return oss.str(); } bool ArquivoDeIdentificacao::gravarPessoasEmFicheiroDeTexto(const ArquivoDeIdentificacao & arquivo) { ofstream dados("dados.txt"); if (!dados.is_open()) { return false; } dados << arquivo.getDados(); dados.close(); if (dados) { return true; } else return false; } bool ArquivoDeIdentificacao::lerPessoasDeFicheiroDeTexto(ArquivoDeIdentificacao& arquivo) { ifstream dados("dados.txt"); string nome; long bi; long nif; string s; if (!dados.is_open()) { return false; } // ler dados de todas as pessoas // uma por linha while (!dados.eof()) { // ler strig com os dados da pessoa getline(dados, s); istringstream iss(s); // ler dados da pessoa iss >> bi >> nif; getline(iss, nome); // se correu bem a leitura ... if (iss) { acrescentaPessoa(nome, bi, nif); } } dados.close(); return true; } class Conta { //ponteiro para pessoa const Pessoa* titular; //const, para não alterar int saldo; public: Conta(const Pessoa* const titular); //posso usar um ponteiro para const ou sem const //ou //Conta(Pessoa* const titular); //pode alterar o apontado desta forma ~Conta(); const Pessoa* getTitular()const; //não altera, damos o conhecimento int getSaldo()const; bool depositar(int quantia); bool levantar(int quantida); long getBi()const; string getAsString()const; }; Conta::Conta(const Pessoa* const titular):titular(titular), saldo(0) { } Conta::~Conta() { cout << "~Conta()" << endl; } const Pessoa* Conta::getTitular() const { return titular; } int Conta::getSaldo() const { return saldo; } bool Conta::depositar(int quantia) { if (quantia <= 0) return false; saldo += quantia; return true; } bool Conta::levantar(int quantia) { if (quantia <= 0 || quantia > saldo) return false; saldo -= quantia; return true; } long Conta::getBi() const { return titular->getBi(); } string Conta::getAsString() const { ostringstream oss; oss << "\ntitular " << titular->getAsString() << "\nsaldo " << saldo << endl; return oss.str(); } class Banco { string nome; //vector de objectos contas vector <Conta> contas; //a destruição deste obejcto vai destruir os membros de outras classes: vector e nome int pesquisar(long bi)const; public: Banco(string n); //~Banco(); //não é preciso, porque as contas não sobrevivem ao fim do banco string getNome() const; void setNome(const string& nome); bool acrescentar(const Pessoa* const pessoa); bool eliminar(long bi); int somaDosSaldos()const; bool depositar(long bi, int quantia); bool levantar(long bi, int quantia); void eliminarTodasAsContas(long bi); string getAsString()const; }; int Banco::pesquisar(long bi) const { for(unsigned int i=0; i< contas.size(); i++) { if(bi == contas[i].getBi()) { return i; } } return -1; } Banco::Banco(string n):nome(n) //vai funcionar o construtor por omissão, e fica vazio, sem lixo/elementos { } //Banco::~Banco() //{ // cout << "\n~Banco" << endl; //} string Banco::getNome() const { return nome; } void Banco::setNome(const string& nome) { this->nome = nome; } bool Banco::acrescentar(const Pessoa* const pessoa) { if (pessoa == nullptr){ return false; } contas.push_back(Conta(pessoa)); //criar contas, é o banco que o faz return true; } bool Banco::eliminar(long bi) { int qual = pesquisar(bi); if(qual == -1) { return false; } contas.erase(contas.begin() + qual); return true; } int Banco::somaDosSaldos() const { int soma = 0; for(const Conta &c : contas) { soma += c.getSaldo(); } return soma; } bool Banco::depositar(long bi, int quantia) { int qual = pesquisar(bi); if(qual == -1) { return false; } return contas[qual].depositar(quantia); } bool Banco::levantar(long bi, int quantia) { int qual = pesquisar(bi); if(qual == -1) { return false; } return contas[qual].levantar(quantia); } void Banco::eliminarTodasAsContas(long bi) //vector { { for (auto it = contas.begin(); it != contas.end();) { if (it->getBi() == bi) { it = contas.erase(it); } else { ++it; } } } } string Banco::getAsString() const { ostringstream oss; oss << "\n== Banco : " << nome << "\t n.contas " << contas.size() << endl; for (unsigned int i = 0; i < contas.size(); i++) { oss << contas[i].getAsString(); } return oss.str(); } int main() { //Pessoa p("coimbra", 123, 321); //cout << p.getAsString(); //Pessoa* ap=nullptr; //ou //Pessoa* const ap = nullptr; //preciso que Conta(const Pessoa* const titular); //ou //const Pessoa* const ap=nullptr; //preciso que Conta(const Pessoa* const titular); //Conta c1(ap); /*Pessoa p1("AAA", 123, 321); Pessoa p2("BBB", 928, 890); Banco b("o banco b"); b.acrescentar(&p1); b.acrescentar(&p2); cout << "Banco \n" << b.getAsString() << endl; b.depositar(123, 40); b.depositar(928, 240); cout << "Bancos depositos\n" << b.getAsString() << endl;*/ //ArquivoDeIdentificacao arquivo("coimbra"); //ArquivoDeIdentificacao arquivo2("porto"); //ArquivoDeIdentificacao arquivo3(arquivo2); //dá erro, proibida a cópia de arquivo2, construção por cópia //arquivo1 = arquivo2; //dá erro, poribida a atribuição , atribuição //arquivo.acrescentaPessoa("pedro", 123, 456); //arquivo.acrescentaPessoa("ines", 888, 999); // //cout << "arquivo de identificacao\n" << arquivo.getAstring(); //ArquivoDeIdentificacao arquivo("coimbra final"); //arquivo.acrescentaPessoa("pedro", 123, 456); //arquivo.acrescentaPessoa("ines", 888, 999); //cout << "arquivo de identificacao\n" << arquivo.getAstring(); // //Banco banco("filial coimbra"); //banco.acrescentar(arquivo.getPessoa(123)); //banco.acrescentar(arquivo.getPessoa(888)); //banco.acrescentar(arquivo.getPessoa(88)); //banco.acrescentar(arquivo.getPessoa(123)); //cout << "banco" << banco.getAsString() << endl; //operação grava ficheiro //ArquivoDeIdentificacao arquivo("coimbra"); //arquivo.acrescentaPessoa("pedro", 123, 456); //arquivo.acrescentaPessoa("ines", 888, 999); //cout << "arquivo de identificacao\n" << arquivo.getAstring(); //Banco banco("filial coimbra"); //banco.acrescentar(arquivo.getPessoa(123)); //banco.acrescentar(arquivo.getPessoa(888)); //banco.acrescentar(arquivo.getPessoa(88)); //banco.acrescentar(arquivo.getPessoa(123)); //cout << "banco" << banco.getAsString() << endl; //arquivo.gravarPessoasEmFicheiroDeTexto(arquivo); //operação ler ficheiro //ArquivoDeIdentificacao arquivo2("porto final"); //arquivo2.lerPessoasDeFicheiroDeTexto(arquivo2); // //cout << "arquivo de identificacao\n" << arquivo2.getAstring(); //Banco banco("filial coimbra"); //banco.acrescentar(arquivo2.getPessoa(123)); //banco.acrescentar(arquivo2.getPessoa(888)); //banco.acrescentar(arquivo2.getPessoa(88)); //banco.acrescentar(arquivo2.getPessoa(123)); //cout << "banco" << banco.getAsString() << endl; cout << "\nfim do main" << endl; return 0; }
Encapsulamento, classes, construtores, destrutores
………..ficha2, exercicio3e4 (a4,a5)
#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; }
………..ficha2, exercicio5 (a5)
#include <string> #include <iostream> #include <sstream> #include <vector> #include <regex> using namespace std; class Automovel { private: string matricula; string combustivel; string marca; string modelo; int ano; static int conta; //não surge nos objectos, surge fora dos objectos, membro estático //e vai precisar de ser inicializado, no inicio e surge int Automovel::conta = 0; //validar a matricula do automovel bool validaMatricula(const string & s) const ; public: Automovel(const string& matricula, const string& combustivel, const string& marca, const string& modelo, const int ano) : combustivel(combustivel), marca(marca), modelo(modelo) //o ano nao surge aqui fica com lixo { setMatricula(matricula); //construida por omissão setAno(ano); //construida por omissão ++conta; } string getMatricula() const { return matricula; } string getCombustivel() const { return combustivel; } string getMarca() const { return marca; } string getModelo() const { return modelo; } int getAno() const { return ano; } static int getConta(); void setMatricula(const string & matricula) { if(validaMatricula(matricula)){ this->matricula = matricula; } //this->matricula = "99-AA-99"; } void setCombustivel(const string& combustivel) { this->combustivel = combustivel; } void setMarca(const string& marca) { this->marca = marca; } void setModelo(const string& modelo) { this->modelo = modelo; } void setAno(const int ano) { if (ano > 2000 && ano < 2021) { this->ano = ano; } else { this->ano = 0; } } string getAsString()const; }; int Automovel::conta = 0; //vai ser criado logo no inicio do main int Automovel::getConta() { return conta; } string Automovel::getAsString()const { ostringstream oss; oss << "\nmatricula: " << matricula << "\ncombustivel: " << combustivel << "\nmarca: " << marca << "n\\nmodelo: " << modelo << "\nano: " << ano; return oss.str(); } bool Automovel::validaMatricula(const string & s) const { //v1 //if (s.length() != 8) //{ // return false; //} //return true; //v2 expressões regulares string patern = "((\d{2}-\d{2}-[A-Z]{2}) | (\d{2}-[A-Z]{2}-\d{2}) | (\[A-Z]{2}-\d{2}-\d{2}))"; //string patern = R"((\d{2}-\d{2}-[A-Z]{2}) | (\d{2}-[A-Z]{2}-\d{2}) | (\[A-Z]{2}-\d{2}-\d{2}))"; //string patern = R"(([A-Z]{2}-\d{2}-(\d{2}|[A-Z]{2}))|(\d{2}-(\d{2}-[A-Z]{2}|[A-Z]{2}-\d{2})))"; regex reg(patern); if(regex_match(s, reg)) { return true; } return false; } int main() { cout << "\nconta: " << Automovel::getConta() << endl; Automovel A1("11-22-CD", "gasolina", "opel", "corsa", 2020); cout << A1.getAsString(); cout << "\nconta: " << Automovel::getConta() << endl; cout << "\nfim da main"; return 0; }
………..ficha2, exercicio7 (a6,a7)
#include <string> #include <iostream> #include <sstream> #include <vector> #include <regex> using namespace std; class MSG { private: char letra; int numero; static int contador; //MSG(const MSG& ob); //i) public: MSG(char letra = 'X'); //por valor por omissão, um constutor por omissão //MSG(char letra); //alternativa que tb funcionar a aliena e) ~MSG(); //construtor por cópia MSG(const MSG& ob); char getLetra() const { return letra; } void setLetra(const char letra) { this->letra = letra; } int getNumero() const { return numero; } void setNumero(const int numero) { this->numero = contador; } string getAsString() const; }; int MSG::contador = 0; MSG::MSG(char letra) { this->letra = letra; this->numero = ++contador; cout << "\ncriado: " << getAsString() << endl; } MSG::~MSG() { cout << "\nterminado: "<< getAsString() << endl; } //construtor por cópia c) MSG::MSG(const MSG& ob) { //anular o construtor por cópia por defeito que é fornecido pelo compilador letra = ob.letra; numero = -ob.numero; //para fazer uma coisa diferente (numero simétrico) cout << "\nCriado por copia " << getAsString(); } string MSG::getAsString() const { ostringstream oss; oss << "\nletra " << getLetra() << " numero " << getNumero() << endl; return oss.str(); } void teste_g() { MSG aux('y'); } void teste_h(MSG z) { //h) //a passagem de um objecto como parametro por valor (funcionou o construtor por cópia) //(z é copia de b, e funciona o construtor por cópia) } void teste_l(MSG & z) //passar o objecto por referencia { //l) //uma referencia não tem o seu lugar proprpio, vai ser apenas outro nome para b, //z coincide em memoria com b, não surge outro objecto, é apenas outro nome //constutor e destrutor são os mesmos } MSG teste_m() { MSG m; //é criado localemnte um objecto m return m; //retornar o m por valor } MSG & teste_n() //retorno por referencia, para uma variavel que já existe { MSG m; //é criado localemnte um objecto m return m; //retornar o m com estatuto de referencia ( não existe uma cópia ) } int main() { //objectos não dinamicos, que vai ser destruido no fim do main //MSG m1('a'); //MSG m2; //para fazer uso do default //objectos dinâmicos //MSG* p = new MSG('D'); //cout << "\n vou construir D"; //delete p; //destruo o objecto apontado por p, destruido expressamente //cout << "\n vou destruir D"; //MSG & m3 = m2; //alinea b) //m3 é uma referência que se vai "colar" a m2, m3 é um outro nome para m2 //não vai ser criado mais nenhum objecto //c) //MSG m4 = m2; //não existe nenhum construtor por cópia implementado //mas funionou um //todas as classe que não tenham um construtor por cópia, o compilador fornece um //a nossa construção do construtor por cópia //MSG m4 = m2; //criado por cópia //d) atribuição //MSG m4 = m2; //criado por cópia //m1 = m2; //atribuição //e) matriz (array) de objectos //MSG mat1[] = {'M', 'N'}; //f) matriz (array) de objectos //MSG mat2[2]; //criado se e só existir um constutor por omissão //ou //MSG m1('a'); //MSG m2; //para fazer uso do default //MSG mat[] = { m1, m2 }; //ou //MSG mat[4] = { MSG('A') , MSG('B') }; //ou //MSG mat[4] = { MSG() , MSG() }; //g) /*cout << "\n alinea g)" << endl; teste_g(); cout << "\n alinea g)" << endl; teste_g();*/ //h) //MSG b; //cout << "\n alinea h)" << endl; //teste_h(b); //cout << "\n alinea h)" << endl; //teste_h(MSG('c')); //a passagem de um objecto como parametro por valor (funcionou o construtor por cópia) //(z é copia de b, e funciona o construtor por cópia) //i) e j) //em privado o construtor po cópia MSG(const MSG & ob); //mas sendo privado a cópia não vai funcionar, teste_h(b); //k) //objecto é criado com lixo, e é bloqueada a construção por cópia do compilador //l) /*MSG b; teste_l(b);*/ //m) //MSG b = teste_m(); //o valor m chegou aqui //, mas m perde a validade no primeiro }, morre aqui, é terminado //vai ser feita uma copia de m e é este que vai representar a informação a seguir ao = do teste_m() //quem actua é o construtor por cópia, o return é uma cópia //n) retorno por referência MSG b = teste_n(); // cout << "\nfim do main" << endl; return 0; }
………..ficha2, exercicio9 (a7, a8)
#include <string> #include <iostream> #include <sstream> #include <vector> #include <regex> #include <initializer_list> using namespace std; class Televisao { vector<string> canais; //estes endereços podem mudar de sítio //acrescentar elementos ao canais.push_back("rtp1"); //string s = "sic"; //canais.push_back(s); //percorrer: //for(int i = 0; i< canais.size(); i++){ // cout << canais[i]; //} //esvaziar tudo: //canais.clear(); //size a zero //alternativa será uso de vectores de ponteiros para objectos dinâmicos (dinâmicos vão estar no seu lugar) bool ligada; int volume; int canal; //indice do vector de canais +1 string nomeCanal; //o conjunto de canais definido na construção não se altera a partir do exterior da classe void setCanais(string canais0[], unsigned int n); public: Televisao(string canais0[], int n); bool isLigada()const; //is por ser booleana void ligar(); void desligar(); void aumentaVolume(); void diminuiVolume(); void mudaCanal(int c); int getCanal() const { return canal; } //para experimentar Televisao(initializer_list<string> canais0); //lista de constantes, separadas por virgulas e chavetas void setCanais(initializer_list<string> canais0); void setCanais2(vector<string> canais0); string getAsString()const; }; void Televisao::setCanais(string canais0[], unsigned int n) { //validação if(n< 0) { n = 0; } //se já tiver previamente preecnhido canais.clear(); for(unsigned int i = 0; i < n; ++i) { canais.push_back(canais0[i]); //copiar os elementos para o vector de strings } } Televisao::Televisao(string canais0[], int n) { setCanais(canais0, n); ligada = false; volume = 0; canal = 1; cout << "\nNormal" << endl; } bool Televisao::isLigada() const { return ligada; } void Televisao::ligar() { ligada = true; } void Televisao::desligar() { ligada = false; } void Televisao::aumentaVolume() { if (ligada != true) return; if (volume <= 10) volume++; } void Televisao::diminuiVolume() { if (ligada != true) return; if (volume >= 10) volume--; } void Televisao::mudaCanal(int c) { if (ligada != true) return; unsigned cc = c; if (cc > 0 && cc <= canais.size()) canal = c; } Televisao::Televisao(initializer_list<string> canais0) { setCanais(canais0); ligada = false; volume = 0; canal = 1; cout << "\nInitializer" << endl; } void Televisao::setCanais(initializer_list<string> canais0) { canais.clear(); //ou //for (const auto& c : canais) //{ // canais.push_back(c); //} //ou //for (initializer_list<string>::iterator it = canais0.begin(); it != canais0.end(); ++it){ // canais.push_back(*it); //} //ou for(auto it = canais0.begin(); it != canais0.end(); ++it) { canais.push_back(*it); } } void Televisao::setCanais2(vector<string> canais0) { canais.clear(); for (auto it = canais0.begin(); it != canais0.end(); ++it) { canais.push_back(*it); } } string Televisao::getAsString() const { ostringstream oss; //for(unsigned int i = 0; i < canais.size() ; ++i) //{ // //oss << canais[i] << " "; // oss << canais.at(i) << " "; //} //for (const string& c : canais) //c é um outro nome para cada um dos elementos da coleção // oss << c << " "; //for (string c : canais) //c é uma copia dos elementos da coleção // oss << c << " "; //for (const auto & c : canais) // oss << c << " "; //iterador aponta para os elementos do objecto e desta forma conseguimos percorrer //for (vector<string>::const_iterator it = canais.begin(); it != canais.end(); ++it) // oss << *it << " "; for( auto it = canais.begin() ; it != canais.end(); ++it) { oss << *it << " "; } if(!ligada) { oss << "desligada\n"; return oss.str(); } if(canais.empty()) { oss << "sem canais "; return oss.str(); } oss << "\nCanal" << canais[canal-1] << " " << canal << "\nvolume: " << volume << endl; return oss.str(); } int main() { //exemplos dos inicializer lists Televisao tv = { "um","dois","tres","quatro" }; Televisao tv2{ "um", "dois" }; Televisao tv3({ "um","dois" }); //outro exemplo e se for construtor e fizer uso dos () tv.setCanais2({ "um","dois","tres" }); //uniform inicialization //usar estes construtor Televisao(string canais0[], int n); string canais[] = { "um","dois" }; Televisao tv4(canais, 2); Televisao tv5{ canais, 2 }; Televisao tv6 = { canais, 2 }; cout << "\nfim do main" << endl; return 0; }
………..ficha2, exercicio5 (a10, a11)
#include <string> #include <iostream> #include <sstream> #include <vector> #include <regex> #include <initializer_list> using namespace std; class Prego { int x, y; public: Prego(int a, int b); ~Prego(); void mudaDeSitio(int a, int b); string getAsString() const; int getX()const { return x; } int getY()const { return y; } }; Prego::Prego(int a, int b):x(a), y(b) { //x = a; y = b; cout << "construindo prego em " << x << "," << y << "\n"; } Prego::~Prego() { cout << "~Prego em " << x << "," << y << "\n"; } void Prego::mudaDeSitio(int a, int b) { x = a; y = b; } string Prego::getAsString() const { ostringstream oss; oss << "Prego: ( " << x << " , " << y << " ) "; return oss.str(); } class Aviso { string texto; //Prego prego; //relação de composição. //Prego * prego; //usamos um ponteiro, já não é uma posse exclusiva //aviso é destruído, o prego fica lá.. //com ponteiro pode haver posse excluiva ou não //Prego * const prego; //não é possivel mudar o endereço do prego //recebe um valor e não pode mudar, usa-se o const const Prego * const prego; //O aviso nao te direito a fazer alterações ao Prego... const Prego //a relação entre aviso e prego é de agregação (tem o conhecimento) //porque se o aviso for destruido o prego não é //o prego pode ser partilhado por mais de um aviso //o prego já existe antes do aviso //o aviso tem o conhecimento do prego public: Aviso(const string & t, const Prego * const p); ~Aviso(); int getX() const; int getY() const; string getAsString() const; Aviso(const Aviso& ob); //construtor por cópia }; Aviso::Aviso(const string& t, const Prego * const p):texto(t), prego(p) { //prego = p //nao é possivel usar porque o Prego é um membro constante de Aviso (ou até podia ser uma referencia) //logo tem que ser usada a outra opção //os membros const e os membros referencias é obrigatório inicializar na lista de inicialização do construtor cout << " construido Aviso " << texto << endl; } Aviso::~Aviso() { cout << " ~Aviso() " << texto << endl; } int Aviso::getX() const { return prego->getX(); } int Aviso::getY() const { return prego->getY(); } string Aviso::getAsString() const { ostringstream oss; oss << "Aviso: " << texto << " " << prego->getAsString(); return oss.str(); } Aviso::Aviso(const Aviso& ob):prego(ob.prego) { texto = ob.texto+"Copia"; cout << "CCopia de aviso " << texto << endl; } int main() { Prego p(1, 2); Aviso a("quadro 1", &p); Aviso b("quadro 2", &p); cout << " A " << a.getAsString() << endl; cout << " B " << b.getAsString() << endl; p.mudaDeSitio(99, 99); cout << " A " << a.getAsString() << endl; cout << " B " << b.getAsString() << endl; //a=b; //erro //a atribuição entre dois objectos é feita membro a membro //o texto consegue atribuir, mas o prego pk tem const não consegue //assim a atribuição default dá erro, podemos é usar uma atribuição que funcione //usando o operador atribuição Aviso c = a; cout << " C " << c.getAsString() << endl; vector<Aviso> avisos; cout << "-pushback-\n"; avisos.push_back(a); Aviso* pa = &avisos[0]; //ponteiro para o primeiro elemento do vector cout << pa->getAsString() << endl; avisos.push_back(b); Aviso* pb = &avisos[0]; cout << pb->getAsString() << endl; if(pa==pb) { cout << " == \n"; }else { cout << " != \n"; } cout << avisos[0].getAsString() << endl; //avisos.erase(avisos.begin() + 1); //dá erro, pk os objectos do vector têm um membro constante //a atribuição dá erro, e o erase precisa de atribuições internamente cout << "\nfim do main" << endl; return 0; }