herança e polimorfismo

………..ficha7, exercicio1 (a19)

#include <string>
#include <iostream>
#include <sstream>
#include <vector>
#include <regex>
#include <initializer_list>
#include <fstream>

using namespace std;


class Imovel
{
	float preco;
	float area;
	string codigo;
	static int ordem; //para formar o codigo
//para ser usado por classes derivadas
protected: //nao deixamos o codigo exterior alterar, mas apenas as classes derivadas
	void setCodigo(const string& c);
public:
	Imovel(float p, float a);
	virtual ~Imovel();

	float getPreco() const;
	void setPreco(const float preco);
	float getArea() const;
	string getCodigo() const;
	
	static int getOrdem();

	virtual string getAsString()const;
};

ostream& operator << (ostream& saida, const Imovel& i); //operador do cout

int Imovel::ordem = 0;


void Imovel::setCodigo(const string& c)
{
	codigo = c;
}

Imovel::Imovel(float p, float a):preco(p), area(a)
{
	//ou
	//ostringstream oss;
	//oss << (++ordem);
	//codigo = oss.str();
	//ou
	codigo = to_string(++ordem);
}

Imovel::~Imovel()
{
	
}

float Imovel::getPreco() const
{
	return preco;
}

void Imovel::setPreco(const float preco)
{
	this->preco = preco;
}

float Imovel::getArea() const
{
	return area;
}


string Imovel::getCodigo() const
{
	return codigo;
}

int Imovel::getOrdem()
{
	return ordem;
}

string Imovel::getAsString() const
{
	ostringstream oss;
	oss << "  codigo: " << codigo << "\n   preco: " << preco << "\n   area " << area << endl;
	return oss.str();
}

ostream& operator<<(ostream& saida, const Imovel& i)
{
	saida << i.getAsString();
	return saida;
}

//apartamento deriva de imovel, : public .. e recebe por herança
class Apartamento : public Imovel
{

	int numeroAssoalhadas;
	int andar;

public:
	Apartamento(float area0, int andar0, int numeroAssoalhadas0);
	//getAstring é por herança
	//precisa de ser redifinida com o override
	string getAsString()const override;

};

//o construtor d euma classe derivada já manda executar o construtor da calsse base: Imovel
Apartamento::Apartamento(float area0, int andar0, int numeroAssoalhadas0):Imovel(10* area0, area0), andar(andar0),numeroAssoalhadas(numeroAssoalhadas0)
{
	setCodigo("apartamento-" + getAsString());
}

string Apartamento::getAsString() const
{
	ostringstream oss;
	//preco area -Imovel::getAsString()
	oss << "apartamento \n" << Imovel::getAsString() << " andar: " << andar << "\n n. assoalhadas: " << numeroAssoalhadas << endl;
	
	return oss.str();
}
class LojaComercial : public Imovel
{
	//nao tem membros privados
public:
	LojaComercial(float area);

	string getAsString()const override;

};

LojaComercial::LojaComercial(float area):Imovel(15*area, area) 
{
	setCodigo("lojaComercial-" + getAsString());
}

string LojaComercial::getAsString() const
{
	ostringstream oss;
	//preco area -Imovel::getAsString()
	oss << "lojaComercial \n" << Imovel::getAsString() << "   andar: R/C" << endl;

	return oss.str();
}


class Imobiliaria
{

//"não deve utilizar uma estrutura de dados para cada tipo diferente de bem imobiliário"
//não usar multiplos vectores, um para cada tipo, mas um para todos
//assim:
	vector<Imovel*> imoveis; //coleção de vários tipos de imoveis
	//um ponteiro de uma classe derivada pode apontar para a classe base, upcasting
	//relação entre imobiliaria e imoveis : agregação
	
	string nome;

	int pesquisa(string codigo)const;
public:
	Imobiliaria(string nome);


	void acrescentaImovel(Imovel* imovel); //recebemos um imovel qualquer
	//ponteiro para a base

	bool setPreco(string codigo, float preco);
	float getPreco(string codigo)const;
	bool remover(string codigo);
	
	string getAsString()const;
	string getAsString(string codgio0)const;
};

ostream& operator << (ostream& saida, const Imobiliaria& i); //operador do cout

int Imobiliaria::pesquisa(string codigo) const
{
	for(unsigned int i = 0; 0 < imoveis.size() ; i++)
	{
		if(codigo == imoveis[i]->getCodigo())
		{
			return i;
		}
	}
	return -1;
}

Imobiliaria::Imobiliaria(string nome):nome(nome)
{
}

void Imobiliaria::acrescentaImovel(Imovel* imovel)
{
	if(imovel != nullptr)
	{
		//pode surigr uma loja ou apartamento
		imoveis.push_back(imovel);
	}
}

bool Imobiliaria::setPreco(string codigo, float preco)
{
	if (preco < 0){
		return false;
	}
	int qual = pesquisa(codigo);
	if (qual == -1)
	{
		return false;
	}
	imoveis[qual]->setPreco(preco);
	return true;
}

float Imobiliaria::getPreco(string codigo) const
{
	int qual = pesquisa(codigo);
	if(qual == -1)
	{
		return 0;
	}
	return imoveis[qual]->getPreco();
}

bool Imobiliaria::remover(string codigo)
{
	int qual = pesquisa(codigo);
	if(qual == -1)
	{
		return false;
	}
	//relação de agregação faz-se apenas o erase
	imoveis.erase(imoveis.begin() + qual);
	return true;
}

string Imobiliaria::getAsString() const
{
	ostringstream oss;
	oss << "Imobiliaria " << nome << endl;
	for(unsigned int i = 0; i < imoveis.size(); i++)
	{
		oss << imoveis[i]->getAsString() << endl;
	}
	return oss.str();
}

string Imobiliaria::getAsString(string codgio0) const
{
	int qual = pesquisa(codgio0);
	if(qual == -1)
	{
		return "codigo nao existe";
	}
	return imoveis[qual]->getAsString();
}

ostream& operator<<(ostream& saida, const Imobiliaria& i)
{
	saida << i.getAsString();
	return saida;
}

//extra Interaccao
class Interaccao {
	Imobiliaria* imobiliaria; //classe que envolve toda a lógica
public:
	Interaccao(Imobiliaria* imobiliaria0);
	int escolheOpcao(vector<string> opcoes);
	int lerInt(string msg);
	float lerFloat(string msg);
	void opcaoAcrescentarApartamento();
	void opcaoAcrescentarLoja();
	void opcaoPesquisarImovelPorCodigo();
	void opcaoPesquisarPrecoDeImovelPorCodigo();
	void opcaoActualizarPrecoDeImovelPorCodigo();
	void opcaoRemoverImovelPorCodigo();
	void corre();
};

Interaccao::Interaccao(Imobiliaria* imobiliaria0) {
	imobiliaria = imobiliaria0;
}

int Interaccao::escolheOpcao(vector<string> opcoes) {
	for (unsigned int i = 0; i < opcoes.size(); i++)
		cout << endl << i << " - " << opcoes[i];

	int opcao = -1;
	do {
		opcao = lerInt("\n\nopcao > ");
	} while (opcao < 0 || opcao > opcoes.size());
	return opcao;
}
int Interaccao::lerInt(string msg) {
	int valor;
	bool leu = false;
	do {
		cout << msg;
		string s;
		cin >> s;
		istringstream iss(s);
		if (iss >> valor) // se correu bem a leitura
			leu = true;
	} while (!leu);
	return valor;
}
float Interaccao::lerFloat(string msg) {
	float valor;
	bool leu = false;
	do {
		cout << msg;
		string s;
		cin >> s;
		istringstream iss(s);
		if (iss >> valor) // se correu bem a leitura
			leu = true;
	} while (!leu);
	return valor;
}
void Interaccao::opcaoAcrescentarApartamento() {
	float area;
	int andar;
	int nAss;
	cout << "\nAcrescentar apartamento";
	area = lerFloat("   area: ");
	andar = lerInt("   andar: ");
	nAss = lerInt("   n. de assoalhadas: ");
	imobiliaria->acrescentaImovel(new Apartamento(area, andar, nAss));
}
void Interaccao::opcaoAcrescentarLoja() {
	float area;
	cout << "\nAcrescentar loja: ";
	area = lerFloat("   area: ");
	imobiliaria->acrescentaImovel(new LojaComercial(area));
}

void Interaccao::opcaoPesquisarImovelPorCodigo() {
	string codigo;
	cout << "\nPesquisar imovel por codigo\n   codigo: ";
	cin >> codigo;
	cout << imobiliaria->getAsString(codigo) << endl;
}
void Interaccao::opcaoPesquisarPrecoDeImovelPorCodigo() {
	string codigo;
	cout << "\nPesquisar preco de imovel por codigo\n   codigo: ";
	cin >> codigo;
	cout << imobiliaria->getPreco(codigo) << endl;
}
void Interaccao::opcaoActualizarPrecoDeImovelPorCodigo() {
	string codigo;
	float preco;
	cout << "\nActualizar preco de imovel por codigo\n   codigo: ";
	cin >> codigo;
	cout << imobiliaria->getAsString(codigo) << endl;
	preco = lerFloat("\n   preco: ");
	imobiliaria->setPreco(codigo, preco);
}
void Interaccao::opcaoRemoverImovelPorCodigo() {
	string codigo;
	cout << "\nRemover imovel por codigo\n   codigo: ";
	cin >> codigo;
	cout << imobiliaria->getAsString(codigo) << endl;
	cout << "\n   Remover ";
	if (imobiliaria->remover(codigo))
		cout << " removeu ";
	else cout << " nao removeu ";
}

void Interaccao::corre() {
	vector<string> opcoes;
	opcoes.push_back("Sair");
	opcoes.push_back("Listar");
	opcoes.push_back("Acrescentar apartamento");
	opcoes.push_back("Acrescentar loja");
	opcoes.push_back("Pesquisar imovel por codigo");
	opcoes.push_back("Pesquisar preco de imovel dado o codigo");
	opcoes.push_back("Actualizar o preco de um imovel dado o codigo");
	opcoes.push_back("Remover imovel dado o codigo");

	int opcao = 0;
	do {
		opcao = escolheOpcao(opcoes);
		switch (opcao) {
		case 0: cout << "\nSair\n";
			break;
		case 1: cout << *imobiliaria << endl;
			break;
		case 2:	opcaoAcrescentarApartamento();
			break;
		case 3: opcaoAcrescentarLoja();
			break;
		case 4: opcaoPesquisarImovelPorCodigo();
			break;
		case 5: opcaoPesquisarPrecoDeImovelPorCodigo();
			break;
		case 6: opcaoActualizarPrecoDeImovelPorCodigo();
			break;
		case 7:	opcaoRemoverImovelPorCodigo();
			break;
		}

	} while (opcao != 0);

}


int main()
{

	Imobiliaria* imobiliaria = new Imobiliaria("Imobiliaria");
	Interaccao interaccao(imobiliaria);
	interaccao.corre();
	delete imobiliaria;
	cout << "\nfim do main.." << endl;
	return 1;
}

………..ficha7, exercicio3 (a19,a20)

#include <string>
#include <iostream>
#include <sstream>
#include <vector>
#include <regex>
#include <initializer_list>
#include <fstream>

using namespace std;

#include <string>
#include <iostream>
#include <sstream>
#include <vector>
#include <regex>
#include <initializer_list>
#include <fstream>

using namespace std;

/*
+---------------------------------------- + -------------------------- - +
| operador		| membro / não membro |
+---------------------------------------- + -------------------------- - +
| todos os operadores unários p.e: ++a, a++   | membro                    |
| = () -> ->*				  | têm sempre que ser membro |
| += -= /= *= &= |= %= >>= <<=	      | membro                    |
| todos os restantes operadores binários, ==,<<...     | globais |
+---
*/


//relação de agregaçao, memoria dinâmica
class Livro
{
	string titulo;
	string autor;
	long isbn;
	
public:
	Livro(const string& titulo0, const string& autor0, const long isbn0);
	virtual ~Livro(); //classe de hierarquia, boa pratica

	string getTitulo() const;
	void setTitulo(const string& titulo);
	string getAutor() const;
	void setAutor(const string& autor);
	long getIsbn() const;
	void setIsbn(const long isbn);
	
	virtual string getAsString()const; //para adaptar aos objectos das classes derivadas
	
	virtual Livro* duplica() const;  
};
//comparação de dois livros
bool operator==(const Livro& ob1, const Livro& ob2);
// cout objecto-de-livro
ostream& operator<<(ostream& saida, const Livro& lv);

Livro::Livro(const string& titulo0, const string& autor0, const long isbn0):titulo(titulo0), autor(autor0), isbn(isbn0)
{
}

Livro::~Livro()
{
}

string Livro::getTitulo() const
{
	return titulo;
}

void Livro::setTitulo(const string& titulo)
{
	this->titulo = titulo;
}

string Livro::getAutor() const
{
	return autor;
}

void Livro::setAutor(const string& autor)
{
	this->autor = autor;
}

long Livro::getIsbn() const
{
	return isbn;
}

void Livro::setIsbn(const long isbn)
{
	this->isbn = isbn;
}

string Livro::getAsString() const
{
	ostringstream oss;
	cout << "\ntitulo: " << titulo << " autor: " << autor << " isbn " << isbn << endl;
	
	return oss.str();
}

//criar um clone
Livro* Livro::duplica() const
{
	//ou
	//return new Livro(*this);
	//ou
	Livro* lv = new Livro(*this);
	return lv;
	
}

bool operator==(const Livro& ob1, const Livro& ob2)
{
	return ob1.getIsbn() == ob2.getIsbn();
}

ostream& operator<<(ostream& saida, const Livro& lv)
{
	saida << lv.getAsString();
	return saida;
}


class LivroFiccao : public Livro
{
	string nomePlaneta;
	int anoAccao;
	bool realidadeAccao; //0 realista, 1 fatansiosa
public:
	LivroFiccao(const string& titulo0, const string& autor0, const long isbn0, const string& nome_planeta, const int ano_accao, const bool realidade_accao);

	string getNomePlaneta() const;
	int getAnoAccao() const;
	bool getRealidadeAccao() const;
	string getAsString() const override;
	Livro * duplica() const override;
};

LivroFiccao::LivroFiccao(const string& titulo0, const string& autor0, const long isbn0, const string& nome_planeta, 
	const int ano_accao, const bool realidade_accao) : Livro(titulo0, autor0, isbn0), nomePlaneta(nome_planeta),
	anoAccao(ano_accao),realidadeAccao(realidade_accao){
	}

string LivroFiccao::getNomePlaneta() const
{
	return nomePlaneta;
}

int LivroFiccao::getAnoAccao() const
{
	return anoAccao;
}

bool LivroFiccao::getRealidadeAccao() const
{
	return realidadeAccao;
}

string LivroFiccao::getAsString() const
{
	ostringstream oss;
	oss << endl << Livro::getAsString() << " planeta " << nomePlaneta << " ano " << anoAccao << endl;
	if(realidadeAccao)
	{
		oss << " realista \n";
	}else
	{
		oss << " fantasiosa \n";
	}
	
	return oss.str();
}

Livro* LivroFiccao::duplica() const
{
	return new LivroFiccao(*this);
}


class LivroPolicial: public Livro
{
	string nomeDetective;
	int numeroTiros;
public:
	LivroPolicial(const string& titulo0, const string& autor0, const long isbn0, const string& nomeDetective0, int numeroTiros = 0);

	string getNomeDetective() const;
	int getNumeroTiros() const;
	string getAsString()const override;

	Livro* duplica()const override;
};


LivroPolicial::LivroPolicial(const string& titulo0, const string& autor0, const long isbn0,
                             const string& nomeDetective0, int numeroTiros0):Livro(titulo0, autor0, isbn0),
nomeDetective(nomeDetective0),numeroTiros(numeroTiros0)
{
}

string LivroPolicial::getNomeDetective() const
{
	return nomeDetective;
}

int LivroPolicial::getNumeroTiros() const
{
	return numeroTiros;
}

string LivroPolicial::getAsString() const
{
	ostringstream oss;
	oss << endl << Livro::getAsString() << " detective: " << nomeDetective << endl;
	if(numeroTiros > 10)
	{
		oss << " nao aconcelhado a criancas \n";
	}else
	{
		oss << " n. de tiros " << numeroTiros << endl;
	}
	return oss.str();
}

//nas classes concretas tem que haver um duplica
Livro* LivroPolicial::duplica() const
{
	//ou
	//return new LivroPolicial(*this);
	//ou
	LivroPolicial* lvp = new LivroPolicial(*this);
	return lvp;
}

//bibliteca tem relação de composição com o livro
//posse exclusiva, implementar: destrutor, construtor por copia, operador atribuição
class Biblioteca
{
	string morada;
	//qualquer tipo de livros: ponteiros para a classe base, que depois tem acesso às derivadas
	vector<Livro *> livros; //vector polimorfico, <Livro *>
	
	int pesquisaLivro(long isbn0) const; //indice, int
public:
	Biblioteca(const string& morada);
	

	bool acrescentarLivro(Livro * livro);
	bool removerLivro(long isbn0);

	//por haver relação de composição, os livros não sobrevivem à destruição da biblioteca
	//e destrutor
	virtual ~Biblioteca();
	//e construtor por copia
	Biblioteca(const Biblioteca& ob);
	//e operador atribuição
	Biblioteca& operator=(const Biblioteca & ob);
	
	string getAsString()const;
};

ostream& operator<<(ostream& saida, const Biblioteca& bibl);

int Biblioteca::pesquisaLivro(long isbn0) const
{
	for(unsigned int i=0; i<livros.size(); i++)
	{
		if(isbn0 == livros[i]->getIsbn())
		{
			return i;
		}
	}
	return -1;
}

Biblioteca::Biblioteca(const string& morada)
{
}

bool Biblioteca::acrescentarLivro(Livro* livro)
{
	if(livro == nullptr || pesquisaLivro(livro->getIsbn())!=-1)
	{
		return false;
	}
	Livro* lv = livro->duplica(); //é duplicado com o livro->duplica();, não aceito o que me dão
	livros.push_back(lv);
	return true;
}

bool Biblioteca::removerLivro(long isbn0)
{
	int qual = pesquisaLivro(isbn0);
	if(qual == -1)
	{
		return false;
	}
	//liberta o obejcto apontado por livro[i]
	delete livros[qual]; //só por ser relação de composição
	//retirar o vector o pionteito que aponta para memoria já libertada
	livros.erase(livros.begin() + qual);
	return true;
}

Biblioteca::~Biblioteca()
{
	for(Livro * l: livros)
	{
		delete l;
	}
}

Biblioteca::Biblioteca(const Biblioteca& ob)
{
	//nao ha ponteiros com valores lixo para limpar
	//funcionou o construtor por omissão do vector que criou
	//um vector vazio (sem ponteiros)
	//e do membro do tipo string
	
	//se houvesse ponteiros com valores lixo punha-se a nullptr
	//porque precisamos de preparar o objecto que esta aser criado
	//para invocar o operador de atribuição que limpa a memoria velha
	//do objecto que o invoca, o primeiro membro da atribuição
	*this = ob; //chama o operador atribuicao e copia os dados
	//de acordo com o que tem implementado: duplicando
	//a memoria dinmica que o destrutor liberta
}

Biblioteca& Biblioteca::operator=(const Biblioteca& ob)
{
	//prevenção de auto atribuição
	if(this == & ob)
	{
		return *this;
	}
	//limpesa da memoria velha do primeiro membro de atribuicao
	for(Livro * lv: livros)
	{
		delete lv;
	}
	//esvaziar o vector que agora só aponta para memoria ja nao reservada
	livros.clear();
	//duplicar os objectos dinamicos, copiar a informacao de ob
	for(Livro * lv: livros)
	{
		Livro* p = lv->duplica();
		livros.push_back(lv);
	}
	//e nao esquecer os restantes membros
	morada = ob.morada;
	return *this;
}

string Biblioteca::getAsString() const
{
	ostringstream oss;
	oss << "\nmorada: " << morada << endl;
	for(unsigned int i=0; i<livros.size(); i++)
	{
		oss << livros[i]->getAsString();
	}
	return oss.str();
}

// cout objecto-de-livro
ostream& operator<<(ostream& saida, const Biblioteca & bibl)
{
	saida << bibl.getAsString();
	return saida;
}


int main()
{
	Biblioteca* b = new Biblioteca("aldeia de coimbra");

	Livro* p = new LivroPolicial("coimbra", "coimbra", 12345,"coimbra", 1);
	b->acrescentarLivro(p);
	cout << b->getAsString();

	cout << "\nfim do main" << endl;
	return 1;
}

………..ficha?, exercicio? (a21), aquario polimorfico

#include <string>
#include <iostream>
#include <sstream>
#include <vector>
#include <regex>
#include <initializer_list>
#include <fstream>

using namespace std;

class Pargo;
class Pescada;
class Aquario;
class Peixe;

//peixe é uma classe abstracta, não se podem criar objectos deste tipo
class Peixe
{
	string nomeEspecie;
	string cor;
	int peso;
	int numSerie;

	static int sequencia;
	//constantes iguais para todos:
	static const int INICIAL_PESO = 10;

	bool vivo = true; //importante, subs estadio

protected:
	void aumentaPeso(int quant0);
public:
	Peixe(string nomeEspecie0, string cor0 = "cinzento");
	//nao existe aqui construtor default
	//assim a classe derivada precisa de um construtor que alimente a classe base
	Peixe(const Peixe& orig); //existe porque precisamos que os peixes tenham um num de seq diferente
	//tudo é copiado mas o num de série é diferente.
	///se fosse o natrual copiaava tudo
	
	int getNumSerie() const;
	int getPeso() const;
	
	bool isVivo()const;

	virtual string getAsString()const;

	//funcao abstracta nao se podem criar objectos desta classe
	//pode haver "Peixe *" e "Peixe &"
	virtual void alimentar(int quant, Aquario* aquario) = 0; 
	virtual Peixe* duplica()const = 0;
	//serve para criar diferentes tipos de peixes: pargo e pescada
	static Peixe* fabrica(string tipo0, string cor0="cinzento");
	virtual ~Peixe();
	bool setVivo(bool v);
	
};

ostream& operator<<(ostream& saida, const Peixe& p);

void Peixe::aumentaPeso(int quant0)
{
	peso +=quant0;
}

Peixe::Peixe(string nomeEspecie0, string cor0) :nomeEspecie(nomeEspecie0), cor(cor0), peso(INICIAL_PESO), numSerie(sequencia++)
{
}

Peixe::Peixe(const Peixe& orig):nomeEspecie(orig.nomeEspecie), cor(orig.cor), peso(orig.peso), numSerie(sequencia++)
{
	//o peixe construido por copia tem outro numero de série
}


int Peixe::getPeso() const
{
	return peso;
} 


int Peixe::getNumSerie() const
{
	return numSerie;
}


bool Peixe::isVivo() const
{
	return vivo;
}

Peixe* Peixe::fabrica(string tipo0, string cor0)
{
	if(tipo0 == "pargo")
	{
		return new Pargo(cor0);
	}else if(tipo0 == "pescada")
	{
		return new Pescada;
	}
	return nullptr;
}

bool Peixe::setVivo(bool v)
{
	vivo = v;
}

ostream& operator<<(ostream& saida, const Peixe& p)
{
	saida << p.getAsString();
	return saida;
}

string Peixe::getAsString() const
{
	ostringstream oss;

	oss << "\nPeixe: " << nomeEspecie << "\ncor: " << cor << "\npeso: " << peso << "\nnumSerie: " << numSerie << endl;
	return oss.str();
}

int Peixe::sequencia = 499; //num. para cada peixe

//NOVO: surgem duas espécies de peixes

class Pargo: public Peixe
{
	static const int LIMITE_PESO = 50;
public:
	Pargo(string cor0 = "cinzento");

	void alimentar(int quant0, Aquario* aquario) override;
	Peixe* duplica()const override;
};

Pargo::Pargo(string cor0):Peixe("pargo",cor0)
{
	//importante pargo precisa de passar o que o construtor da base precisa, o Peixe
	//porque a base não é default
}

void Pargo::alimentar(int quant0, Aquario* aquario)
{
	if(quant0<=0 || aquario==nullptr)
	{
		return;
	}
	aumentaPeso(quant0);
	if(getPeso()>LIMITE_PESO)
	{
		//aquario->eliminaPeixe(getNumSerie()); //perigo
		setVivo(false);
	}
}

Peixe* Pargo::duplica() const
{
	//duplicação polimórfica
	return new Pargo(*this);
}

class Pescada : public Peixe
{
	static const int LIMITE_SOLIDAO = 1;
	static const int LIMITE_MULTIDAO = 10;
public:
	Pescada();
	
	void alimentar(int quant0, Aquario* aquario0) override;
	Peixe* duplica()const override;
	
};

Pescada::Pescada():Peixe("pescada")
{
}

void Pescada::alimentar(int quant0, Aquario* aquario0)
{
	if(quant0<=0 || aquario0 == nullptr)
	{
		return;
	}
	int num = aquario0->getQuantosPeixes(); //uma estragégia para aceder ao aquario
	//ou colocar na classe peixe um ponteiro para aquario
	//assim as derivadas teriam sempre acesso
	
	if(num> LIMITE_SOLIDAO && num < LIMITE_MULTIDAO)
	{
		aumentaPeso(quant0);
	}else
	{
		aumentaPeso(quant0 / 2);
	}
}

Peixe* Pescada::duplica() const
{
	return new Pescada(*this);
}

//aquario é uma classe abstracta
class Aquario
{
	vector<Peixe*> peixes; //vector de ponteiros

	int pesquisaPeixe(int numSerie0)const;
	void eliminarMortos();
public:
	Aquario() = default;  //qd criado é um vector vazio

	//quando um peixe e posto no aquario, este assume a
	//sua posse e controlo total
	Aquario(const Aquario& orig); //construtor por cópia
	Aquario& operator=(const Aquario& orig); //operador atribuição

	virtual ~Aquario();

	bool addPeixe(string tipo0, string cor0 = "cinzento");
	const Peixe* getPeixe(int numSerie) const;
	void alimentar(int quantidade0);
	void removePeixe(int numSerie);
	bool eliminaPeixe(int numSerie0);

		string getAsString()const;

	unsigned int getQuantosPeixes()const;
};

void Aquario::alimentar(int quantidade0)
{
	//for (Peixe* p : peixes)
	//{
	//	p->alimentar(quantidade0, this); //mt cuidado com isto, usa o vector<Peixe*> novos;
	//}
	//v2
	for(int i = 0; i < peixes.size(); i++)
	{
		peixes[i]->alimentar(quantidade0, this); //percorrer o vector 
	}
	eliminarMortos(); //vou verificar o boolenao vivo dos peixes
}

string Aquario::getAsString() const
{
	ostringstream oss;
	oss << "\nAquario; " << endl;
	//neste caso vai ser contatenada a informação
	//para o objecto que estiver a ser apontado
	//não interessa qual
	for (Peixe* p : peixes)
	{
		oss << p->getAsString();
	}
	return oss.str();
}

unsigned Aquario::getQuantosPeixes() const
{
	return peixes.size();
}

bool Aquario::addPeixe(string tipo0, string cor0) {
	Peixe* peixe = Peixe::fabrica(tipo0, cor0); //fabrica é static por isso ::
	if(peixe==nullptr)
	{
		return false;
	}
	peixes.push_back(peixe);
	return true;
}

const Peixe* Aquario::getPeixe(int numSerie) const
{
	int qual = pesquisaPeixe(numSerie);
	if(qual == -1)
	{
		return nullptr;
	}
	return  peixes[qual];
};

int Aquario::pesquisaPeixe(int numSerie0)const
{
	for (int i = 0; i < peixes.size(); i++)
	{
		if (peixes[i]->getNumSerie() == numSerie0)
		{
			return i;
		}
	}
	return -1;
}

void Aquario::eliminarMortos()
{
	//formula
	//ou
	//for(vector<Peixe*>::iterator it = peixes.begin() ; it != peixes.end(); )
	//ou
	for (auto it = peixes.begin(); it != peixes.end();)
	{
		if (!(*it)->isVivo())
		{
			delete (*it);
			it = peixes.erase(it);
		}
		else
		{
			++it;
		}
	}
}


Aquario::~Aquario()
{
	for (Peixe* p : peixes)
	{
		delete p;
	}
	cout << "\n~Aquario()" << endl;
}

Aquario::Aquario(const Aquario& orig)
{
	//funcionou o constru por defeito do vector
	//o vector está vazio
	//não há ponteiros com lixo
	*this = orig;
}

Aquario& Aquario::operator=(const Aquario& orig)
{
	//prevenção da auto atribuição
	if (this == &orig)
	{
		return  *this;
	}
	//libtertar mem dina velha
	for (Peixe* p : peixes)
	{
		delete p;
	}
	//esvaziar o vector
	peixes.clear();
	//copiar a informacao de orig, duplicando os objectos dinamicos
	for (Peixe * peixe : orig.peixes) {
		Peixe * p = peixe->duplica();
		peixes.push_back(p);
	}
	return *this;
}

void Aquario::removePeixe(int numSerie)
{
	int qual = pesquisaPeixe(numSerie);
	if (qual == -1)
	{
		return;
	}
	delete peixes[qual];
	peixes.erase(peixes.begin() + qual);
}

bool Aquario::eliminaPeixe(int numSerie0)
{
	int qual = pesquisaPeixe(numSerie0);
	if(qual == -1)
	{
		return false;
	}
	//remove o peixe do aquario, é destruido
	delete peixes[qual];
	//depois de feito o dele (libertada a memoria)
	//precisamos de retirar do vector
	//o ponteio para memoria ja nao reservada
	peixes.erase(peixes.begin() + qual);
	return true;
}

int main()
{
	

	cout << "\nfim do main" << endl;
	return 1;
}
#include <string>
#include <iostream>
#include <sstream>
#include <vector>

using namespace std;

class Caderno
{
private:
	//membros variáveis
	string marca;
	string cor;
	int numFolhas;
	string tamanho;
public:

	Caderno(const string& marca, const string& cor, const int num_folhas, const string& tamanho)
	//const não consigo alterar o argumento que vem da main, assim fica mais eficiente/seguro,
	//e tambem assim posso fazer uso de uma const, usando por exemplo "marca"
	//o int pode ter const ou não e referencia, e porque é uma coisa pequena
		: marca(marca),
		  cor(cor),
		  numFolhas(num_folhas),
		  tamanho(tamanho)
	{
	}

	//membros funções
	//funções get
	//os consts sigificam que não podem alterar nada, é uma função de consulta
	string getMarca() const
	{
		return marca;
	}
	string getCor() const
	{
		return cor;
	}
	int getNumfolhas() const
	{
		return numFolhas;
	}
	string getTamanho() const
	{
		return tamanho;
	}
	
	//funções set
	void setMarca(const string & marca)
	{
		this->marca = marca;
	}
	void setCor(const string & cor)
	{
		this->cor = cor;
	}
	void setNumfolhas(int num_folhas)
	{
		if(num_folhas>0){
			numFolhas = num_folhas;
		}else
		{
			numFolhas = 0;
		}
	}
	void setTamanho(const string& tamanho)
	{
		this->tamanho = tamanho;
	}

	string getAsString()const;
};

string Caderno::getAsString()const
{
	ostringstream oss;
	oss << "\nmarca: " << marca
		<< "\ncor: " << cor
		<< "\nnum folhas: " << numFolhas
		<< "n\ntamanho: " << tamanho;
	return oss.str();
}


int main()
{
	const Caderno Cad1("bic","branca",2,"a4"); //const não posso alterar
	cout << Cad1.getAsString();

	cout << "\nfim do main" << endl;

	return 0;
}

………..ficha?, exercicio? (a21, a22), aquario polimorfico v2

#include <string>
#include <iostream>
#include <sstream>
#include <vector>
#include <regex>
#include <initializer_list>
#include <fstream>

using namespace std;

class Aquario;
class Pargo;
class Pescada;

//peixe é uma classe abstracta, não se podem criar objectos deste tipo
class Peixe
{
	string nomeEspecie;
	string cor;
	int peso;
	int numSerie;

	static int sequencia;
	//constantes iguais para todos:
	static const int INICIAL_PESO = 10;

	bool vivo = true; //importante, subs estadio

	//v2
	Aquario* aquario = nullptr;

protected:
	void aumentaPeso(int quant0);
	Aquario* getAquario(); //v2
public:
	Peixe(Aquario* aq0, string nomeEspecie0, string cor0 = "cinzento"); //v2
	//nao existe aqui construtor default
	//assim a classe derivada precisa de um construtor que alimente a classe base
	Peixe(const Peixe& orig); //existe porque precisamos que os peixes tenham um num de seq diferente
	//tudo é copiado mas o num de série é diferente.
	///se fosse o natrual copiaava tudo
	
	int getNumSerie() const;
	int getPeso() const;
	
	bool isVivo()const;

	virtual string getAsString()const;

	//funcao abstracta nao se podem criar objectos desta classe
	//pode haver "Peixe *" e "Peixe &"
	//virtual void alimentar(int quant, Aquario* aquario) = 0;
	virtual void alimentar(int quant) = 0; //v2 
	virtual Peixe* duplica()const = 0;
	//serve para criar diferentes tipos de peixes: pargo e pescada
	static Peixe* fabrica(string tipo0, Aquario * aq0, string cor0="cinzento");
	virtual ~Peixe();
	bool setVivo(bool v);

	//v3
	void setAquario(Aquario* aqua0);
}; 

ostream& operator<<(ostream& saida, const Peixe& p);

void Peixe::aumentaPeso(int quant0)
{
	peso +=quant0;
}

Aquario* Peixe::getAquario()
{
	return aquario;
}

Peixe::Peixe(Aquario * aq0, string nomeEspecie0, string cor0) :aquario(aq0),nomeEspecie(nomeEspecie0), cor(cor0), peso(INICIAL_PESO), numSerie(sequencia++)
{
}

Peixe::Peixe(const Peixe& orig):nomeEspecie(orig.nomeEspecie), cor(orig.cor), peso(orig.peso), numSerie(sequencia++)
{
	//o peixe construido por copia tem outro numero de série
}


int Peixe::getPeso() const
{
	return peso;
} 


int Peixe::getNumSerie() const
{
	return numSerie;
}


bool Peixe::isVivo() const
{
	return vivo;
}

Peixe* Peixe::fabrica(string tipo0, Aquario * aqu0, string cor0)
{
	if(tipo0 == "pargo")
	{
		return new Pargo(aqu0, cor0);
	}else if(tipo0 == "pescada")
	{
		return new Pescada(aqu0);
	}
	return nullptr;
}

bool Peixe::setVivo(bool v)
{
	vivo = v;
}

void Peixe::setAquario(Aquario* aqua0)
{
	this->aquario = aqua0;
}

ostream& operator<<(ostream& saida, const Peixe& p)
{
	saida << p.getAsString();
	return saida;
}

string Peixe::getAsString() const
{
	ostringstream oss;

	oss << "\nPeixe: " << nomeEspecie << "\ncor: " << cor << "\npeso: " << peso << "\nnumSerie: " << numSerie << endl;
	return oss.str();
}

int Peixe::sequencia = 499; //num. para cada peixe

//NOVO: surgem duas espécies de peixes

class Pargo: public Peixe
{
	static const int LIMITE_PESO = 50;
public:
	Pargo(Aquario * aqua0, string cor0 = "cinzento");

	void alimentar(int quant0) override;
	Peixe* duplica()const override;
};

Pargo::Pargo(Aquario* aqua0, string cor0):Peixe(aqua0, "pargo",cor0)
{
	//importante pargo precisa de passar o que o construtor da base precisa, o Peixe
	//porque a base não é default
}

void Pargo::alimentar(int quant0)
{
	if(quant0<=0 || getAquario()==nullptr)
	{
		return;
	}
	aumentaPeso(quant0);
	if(getPeso()>LIMITE_PESO)
	{
		//aquario->eliminaPeixe(getNumSerie()); //perigo
		setVivo(false);
	}
}

Peixe* Pargo::duplica() const
{
	//duplicação polimórfica
	return new Pargo(*this);
}

class Pescada : public Peixe
{
	static const int LIMITE_SOLIDAO = 1;
	static const int LIMITE_MULTIDAO = 10;
public:
	Pescada(Aquario * aqu0);
	
	void alimentar(int quant0) override;
	Peixe* duplica()const override;
	
};

Pescada::Pescada(Aquario* aqu0):Peixe(aqu0, "pescada")
{
}

void Pescada::alimentar(int quant0)
{
	if(quant0<=0 || getAquario() == nullptr) //v2
	{
		return;
	}
	int num = getAquario()->getQuantosPeixes(); //uma estragégia para aceder ao aquario, v2
	//ou colocar na classe peixe um ponteiro para aquario
	//assim as derivadas teriam sempre acesso
	
	if(num> LIMITE_SOLIDAO && num < LIMITE_MULTIDAO)
	{
		aumentaPeso(quant0);
	}else
	{
		aumentaPeso(quant0 / 2);
	}
}

Peixe* Pescada::duplica() const
{
	return new Pescada(*this);
}

//aquario é uma classe abstracta
class Aquario
{
	vector<Peixe*> peixes; //vector de ponteiros

	int pesquisaPeixe(int numSerie0)const;
	void eliminarMortos();
public:
	Aquario() = default;  //qd criado é um vector vazio

	//quando um peixe e posto no aquario, este assume a
	//sua posse e controlo total
	Aquario(const Aquario& orig); //construtor por cópia
	Aquario& operator=(const Aquario& orig); //operador atribuição

	virtual ~Aquario();

	bool addPeixe(string tipo0, string cor0 = "cinzento");
	const Peixe* getPeixe(int numSerie) const;
	void alimentar(int quantidade0);
	void removePeixe(int numSerie);
	bool eliminaPeixe(int numSerie0);

	string getAsString()const;

	unsigned int getQuantosPeixes()const;
};

void Aquario::alimentar(int quantidade0)
{
	//for (Peixe* p : peixes)
	//{
	//	p->alimentar(quantidade0, this); //mt cuidado com isto, usa o vector<Peixe*> novos;
	//}
	//v2
	for(int i = 0; i < peixes.size(); i++)
	{
		peixes[i]->alimentar(quantidade0); //percorrer o vector, v2
	}
	eliminarMortos(); //vou verificar o boolenao vivo dos peixes
}


string Aquario::getAsString() const
{
	ostringstream oss;
	oss << "\nAquario; " << endl;
	//neste caso vai ser contatenada a informação
	//para o objecto que estiver a ser apontado
	//não interessa qual
	for (Peixe* p : peixes)
	{
		oss << p->getAsString();
	}
	return oss.str();
}

unsigned Aquario::getQuantosPeixes() const
{
	return peixes.size();
}



bool Aquario::addPeixe(string tipo0, string cor0) {
	Peixe* peixe = Peixe::fabrica(tipo0, this, cor0); //fabrica é static por isso ::, v2
	if(peixe==nullptr)
	{
		return false;
	}
	peixes.push_back(peixe);
	return true;
}

const Peixe* Aquario::getPeixe(int numSerie) const
{
	int qual = pesquisaPeixe(numSerie);
	if(qual == -1)
	{
		return nullptr;
	}
	return  peixes[qual];
};

int Aquario::pesquisaPeixe(int numSerie0)const
{
	for (int i = 0; i < peixes.size(); i++)
	{
		if (peixes[i]->getNumSerie() == numSerie0)
		{
			return i;
		}
	}
	return -1;
}

void Aquario::eliminarMortos()
{
	//formula
	//ou
	//for(vector<Peixe*>::iterator it = peixes.begin() ; it != peixes.end(); )
	//ou
	for (auto it = peixes.begin(); it != peixes.end();)
	{
		if (!(*it)->isVivo())
		{
			delete (*it);
			it = peixes.erase(it);
		}
		else
		{
			++it;
		}
	}
}


Aquario::~Aquario()
{
	for (Peixe* p : peixes)
	{
		delete p;
	}
	cout << "\n~Aquario()" << endl;
}

Aquario::Aquario(const Aquario& orig)
{
	//funcionou o constru por defeito do vector
	//o vector está vazio
	//não há ponteiros com lixo
	*this = orig;
}

Aquario& Aquario::operator=(const Aquario& orig)
{
	//prevenção da auto atribuição
	if (this == &orig)
	{
		return  *this;
	}
	//libtertar mem dina velha
	for (Peixe* p : peixes)
	{
		delete p;
	}
	//esvaziar o vector
	peixes.clear();
	//copiar a informacao de orig, duplicando os objectos dinamicos
	for (Peixe * peixe : orig.peixes) {
		Peixe * p = peixe->duplica();
		p->setAquario(this); //para aponter para o aquario novo, v3
		peixes.push_back(p);
	}
	return *this;
}

void Aquario::removePeixe(int numSerie)
{
	int qual = pesquisaPeixe(numSerie);
	if (qual == -1)
	{
		return;
	}
	delete peixes[qual];
	peixes.erase(peixes.begin() + qual);
}

bool Aquario::eliminaPeixe(int numSerie0)
{
	int qual = pesquisaPeixe(numSerie0);
	if(qual == -1)
	{
		return false;
	}
	//remove o peixe do aquario, é destruido
	delete peixes[qual];
	//depois de feito o dele (libertada a memoria)
	//precisamos de retirar do vector
	//o ponteio para memoria ja nao reservada
	peixes.erase(peixes.begin() + qual);
	return true;
}

int main()
{
	Aquario* aq1 = new Aquario;
	aq1->addPeixe("pescada");
	aq1->addPeixe("pargo", "laranja");
	cout << aq1->getAsString() << endl;

	Aquario* aq2 = new Aquario;
	aq2->addPeixe("pargo", "azul");
	cout << aq2->getAsString() << endl;

	*aq2 = *aq1;
	cout << aq2->getAsString() << endl;
	aq2->alimentar(10);
	cout << aq2->getAsString() << endl;

	
	cout << "\nfim do main" << endl;
	return 1;
}

………..ficha7, exercicio4 (a22, a23) exercicio global

#include <string>
#include <iostream>
#include <sstream>
#include <vector>
#include <regex>
#include <initializer_list>
#include <fstream>

class Ginasio;

using namespace std;

class Tarifario
{
	//sem usar contentores da STL
	//(vector, lista, maps.. )
	//e implica: memoria dinamica, destrutor, operador atribuição, construtor por cópia
	//deve ser usado um array dinamico de inteiros
	unsigned int* treinos; //ponteiro para o array dinamico
	unsigned int quantos; //quantidade de elementos, pois não podemos usar o size(), serve para controlar qts
	//vai ser implementada pelas derivadas
	//esta função apenas se destina a calcular o pagamento
	//a função calculaPagamentoEApagaTreinos invoca esta e apaga os treinos
	virtual unsigned int calculaPagamento()const = 0; //abstracta

public:
	void acrescentaTreino(unsigned int at);
	unsigned int calculaPagamentoEApagaTreinos();

	//é preciso o construtor para inicializar o ponteiro e a variavel quantos
	Tarifario(); //este é um construtor por omissão
	//vai ser preciso ter o destrutor para devolver a memoria ocupada pela matriz dinamica
	virtual ~Tarifario(); //existem derivas esta é virtual
	//justificação de:
	//a matriz dinamica de inteiros(treinos) pertence exclusivamente a cada objeto
	//de tarifario mas nao e automaticamente copiada quando se copiam ou atribuem estes
	//objectos (apenas o ponteiro e copiado lvando a partilha de matriz entre objectos
	//e mais tarde a deletes repetidos da mesma matriz, entre outras incoerencias)
	// => é preciso fazer o operador de atribuição e o construtor por cópia
	Tarifario(const Tarifario& orig);
	Tarifario& operator=(const Tarifario& orig);

	unsigned int getNumTreinos()const;
	unsigned int getTreino(unsigned int i)const;
	
	virtual string getAsString() const;

	//tem que ser abstracta tb. nao se pode construir
	//um tarifario ainda porque é classe abstracta
	virtual Tarifario* duplica()const = 0;  //duplicação polimorfica, por causa do operador atribuição do cliente
	
};

void Tarifario::acrescentaTreino(unsigned at)
{
	//ao inves do push back
	unsigned int* aux = new unsigned int[quantos + 1];
	for(unsigned int i=0; i< quantos; i++)
	{
		aux[i] = treinos[i];
	}
	aux[quantos] = at;
	quantos++;
	delete[] treinos;
	treinos = aux;
}

unsigned Tarifario::calculaPagamentoEApagaTreinos()
{
	//vai chamar a função correspondente a classe do objeto que invoca
	unsigned int conta = calculaPagamento(); //definido nas classes concretas calculaPagamento();
	delete[] treinos;
	treinos = nullptr;
	quantos = 0;
	return conta;
}

Tarifario::Tarifario()
{
	treinos = nullptr; //inicialmente nao existem treinos
	quantos = 0;
}

Tarifario::~Tarifario()
{
	delete[] treinos; //libertar a memoria dinamica
}

Tarifario::Tarifario(const Tarifario& orig)
{
	//pre inicialização para que o operador de atribuição
	//consiga trabalhar bem ( precisa de ter o objecto num estado
	//coerente dai a inicialização previa
	//para acontecer o delete apenas a um valor de um ponteiro
	//nulo ou com um valor dado por new
	treinos = nullptr; //treinos é um vector ponteiro que nasce com lixo, por isso é impts isto!
	quantos = 0;
	//usar o operador de atribuição
	*this = orig;
}

Tarifario& Tarifario::operator=(const Tarifario& orig) //a= b
{
	//testa auto-aribuição para evitar trabalho desnecssário e possivel incorencia
	//e libertação dos treinos da orgem da copia (que coincide com o destino)
	//na memoria diamica se nao o mesmo -> ja sao iguaos = concluido
	if(this == &orig)
	{
		return *this;
	}
	//devolve os recursos ocupados pelo objecto alvo da atribuição
	delete[] treinos; //treinos é um vector ponteiro que nasce com lixo
	treinos = nullptr; 
	quantos = 0;
	//se o outro objecto tambem tem 0 treinos ja estamos iguais. concluido.
	if(orig.treinos == nullptr)
	{
		return * this;
	}
	//senão:
	//criar recursos iguais (copiar) aos do outro objecto
	//alocar matriz dnamica para tantos treinos como os do outro objecto
	//copiar dos dados: o conteudo da matriz e restantes membros
	treinos = new unsigned int[orig.quantos];
	quantos = orig.quantos;
	for(unsigned int i = 0 ; i < quantos; i++)
	{
		treinos[i] = orig.treinos[i]; //copiar todos
	}
	return *this;
}

unsigned Tarifario::getNumTreinos() const
{
	return  quantos;
}

unsigned Tarifario::getTreino(unsigned i) const
{
	if(i<= 0|| (i>=quantos))
	{
		return 0;
	}
	return treinos[i];
}

string Tarifario::getAsString() const
{
	ostringstream oss;
	oss << " tarifario: " << endl;
	return oss.str();
}

//relação com tarifario é de composição, sento Apressado uma sub-classe
//apressado é uma classe derivada concreta e tem que existir:
//tem que se concretirar tdoas as funções abstractas
//tem que haver um construtor que alimenta a classe base, se tiver argumentos o construtor da base
//mas neste caso é um construtor por omissão
class Apressado :public Tarifario
{
	unsigned int calculaPagamento() const override; //é abstracta na classe tarifario (virtual)
public:
	Tarifario * duplica() const override; //é abstracta na classe tarifario (virtual)

	string getAsString() const override;
};

unsigned Apressado::calculaPagamento() const
{
	unsigned int custo = 0;
	unsigned int numTreinos = getNumTreinos();

	for(unsigned int i = 0 ; i< numTreinos; i++)
	{
		unsigned int treino = getTreino(i);
		if(treino <=10)
		{
			custo += 10;
		}else if(treino > 10 && treino < 20)
		{
			custo += 15;
		}else
		{
			custo += 25;
		}
	}
	return  custo;
}

Tarifario* Apressado::duplica() const
{
	return new Apressado(*this);
}

string Apressado::getAsString() const
{
	ostringstream oss;
	oss << " apressado " << endl;
	return oss.str();
}

//cliente genérico, significa que é uma classe base de uma hierarquia
class Cliente
{
	string nome;
	unsigned int bi; //ou string
	Tarifario* tarifario;  //aponta para um qualquer tipo de tarifario que exista
	int horarioInicio;

	//para impedir a copia e a atribuição de objectos
	//se for solicitado era:
	//Cliente(const Cliente& cli) = delete;
	//Cliente& operator=(const Cliente& cli) = delete;
	
public:
	//nao podem existir clientes sem tarifario, é necessário o construtor
	Cliente(const string& nome, unsigned long bi, Tarifario* const tarifario);

	//destrutor para apagar tarifario
	virtual ~Cliente();

	void iniciaTreino(int hora);
	void terminaTreino(int hora);
	unsigned int paga();

	//pergunta exame
	//um método generico que não pode ser já implementado, é uma função abstracta, virtual e =0
	//e vao ter codigo nas classes derivadas
	virtual void reageEntrada(Ginasio* g) = 0; 
	virtual void reageSaida(Ginasio* g) = 0;

	void mudaTarifario(Tarifario* tarifario);

	unsigned int getBi()const;
	bool estarATreinar()const;

	//a c.5)
	Cliente(const Cliente& cli);
	Cliente& operator=(const Cliente& cli);

	virtual string getAsString()const;

	//tem que ser virtual pura (cliente é abstracta)
	virtual Cliente* duplica()const = 0;
	
};

Cliente::Cliente(const string& nome, unsigned long bi, Tarifario* const tarifario) : nome(nome), bi(bi), tarifario(tarifario)
{
	horarioInicio = -1; //nao esta a treinar quando é criado
}

Cliente::~Cliente()
{
	delete tarifario;
	cout << "~Cliente" << endl;
}

void Cliente::iniciaTreino(int hora)
{
	if(horarioInicio==-1)
	{
		horarioInicio = hora;
	}
}

void Cliente::terminaTreino(int hora)
{
	if(horarioInicio != -1)
	{
		tarifario->acrescentaTreino(hora - horarioInicio);
		horarioInicio = -1;
	}
}

unsigned Cliente::paga()
{
	//quem calcula é o tarifario, e o cliente tem
	return tarifario->calculaPagamentoEApagaTreinos();
}

void Cliente::mudaTarifario(Tarifario* tarifario)
{
	if(this->tarifario != nullptr)
	{
		//so muda se o novo tarifario existir mesmo
		//apaga tarifario anterior (deixa de servir)
		//(obs: os treinos do antigo tarifario ficaram
		//por pagar deixa-se pagar antes de mudar de tarifario
		delete this->tarifario;
		this->tarifario = tarifario;
		
	}
}

bool Cliente::estarATreinar() const
{
	return horarioInicio != -1;
}

Cliente::Cliente(const Cliente& cli)
{
	//efectua pre inicilização para compatibilizar com o operador
	//neste caso basta colocar o ponteiro tarifario num estacio inciial coerente
	tarifario = nullptr;
	//usa operador atribuicao
	*this = cli;
}

Cliente& Cliente::operator=(const Cliente& cli)
{
	//testa a auto atribuição para evitar trabalho desnecessario
	//e libertacao do tarifario da origem da copia (que coincide com o destino)
	if(this == &cli)
	{
		return *this;
	}
	//liberta recursos atuais do objecto da atribuicao
	//neste caso so o objeto tarifario
	delete tarifario;
	//cria/copia recursos (iguais ao) do outro objeto
	//no caso do tarifario, pode ser de qualquer tipo
	//usar o new nao e viavel ( nao se sabe o tipo )
	//o tarifario que se duplique
	//tem que ser pela via do "duplica" (implementar no tarifario e derivadas)
	nome = cli.nome;
	bi = cli.bi;
	horarioInicio = cli.horarioInicio;
	tarifario = cli.tarifario->duplica();

	return *this;
}

string Cliente::getAsString() const
{
	ostringstream oss;
	oss << nome << " - bi: " << bi;
	return oss.str();
}

//classe concreta
//e)
class Sociavel: public Cliente
{
	
public:
	Sociavel(const string& nome, const unsigned long bi, Tarifario* const tarifario);

	void reageEntrada(Ginasio* g) override;
	void reageSaida(Ginasio* g) override;
	
	Cliente* duplica() const override;

	string getAsString() const override;
	
};

Sociavel::Sociavel(const string& nome, const unsigned long bi, Tarifario* const tarifario) : Cliente(nome, bi, tarifario)
{
}

void Sociavel::reageEntrada(Ginasio* g)
{
	//nao faz nada
}

void Sociavel::reageSaida(Ginasio* g)
{
	if(g->getNumClientesATreinar()==1) //se for só ele
	{
		g->saiClienteDoTreino(getBi());
	}
}

Cliente* Sociavel::duplica() const
{
	return  new Sociavel(*this);
}

string Sociavel::getAsString() const
{
	ostringstream oss;
	oss << "sociavel - " << Cliente::getAsString();
	return oss.str();
}

//os clientes pertencem ao ginasio
//qd se destroi o ginasio o cliente tambem serão
class Ginasio
{
	//clientes de diversos tipos
	//vector de ponteiros para a classe base
	//* para validar o polimorfismo
	vector<Cliente*>  clientes;

	unsigned int relogio;
	unsigned int pesquisaClienteDadoBi(unsigned int bi);
public:
	void avancaRelogio(int tempo);
	bool acrescentaCliente(Cliente* c);
	unsigned int paga(unsigned int bi);

	void entraClienteNoTreino(unsigned int bi);
	void saiClienteDoTreino(unsigned int bi);
	void removeCliente(unsigned int bi);
	
	Ginasio();
	~Ginasio();
	
	unsigned int getNumClientesATreinar()const;
	bool saiClienteDoTreino(int s);

	Ginasio& operator=(const Ginasio& orig);
	Ginasio(const Ginasio& orig);
	string getAsString() const;
};

unsigned Ginasio::pesquisaClienteDadoBi(unsigned bi)
{
	for(unsigned int i = 0; i<clientes.size(); i++)
	{
		if(bi == clientes[i]->getBi())
		{
			return i;
		}
	}
	return -1;
}

void Ginasio::avancaRelogio(int tempo)
{
	relogio += tempo;
}

bool Ginasio::acrescentaCliente(Cliente* c)
{
	if(c == nullptr)
	{
		return false;
	}
	//se existem clientes com o mesmo bi
	if(pesquisaClienteDadoBi(c->getBi()) != -1)
	{
		return false;
	}
	clientes.push_back(c->duplica());
	return true;
}

unsigned Ginasio::paga(unsigned bi)
{
	//procura cliente. sera devolvida a posicao no vector
	unsigned int indice = pesquisaClienteDadoBi(bi);
	if(indice != -1)
	{
		//se encontrou..
		return clientes[indice]->paga();
	}
	return 0;
}

void Ginasio::entraClienteNoTreino(unsigned bi)
{
	unsigned int indice = pesquisaClienteDadoBi(bi);

	if(indice == -1)
	{
		return;
	}
	//verificar se o cliente ainda não estava a treinar
	if(clientes[indice]->estarATreinar() == true)
	{
		return;
	}
	//avisa os outros clientes a treinar que entrou na sala
	for(unsigned int i=0; i< clientes.size(); i++)
	{
		if(clientes[i]->estarATreinar()){
			clientes[i]->reageEntrada(this);
		}
	}
	//o cliente inicia o treino
	clientes[indice]->iniciaTreino(relogio);
}

void Ginasio::saiClienteDoTreino(unsigned bi)
{
	unsigned int indice = pesquisaClienteDadoBi(bi);
	if(indice == -1)
	{
		return;
	}
	//cliente pode nao estar a treinar
	if(clientes[indice]->estarATreinar() == false)
	{
		return;
	}
	//primeiro tira da sala de treino e so depois avisa os que ficaram que saiu um
	clientes[indice]->terminaTreino(relogio);
	//avisa os outros clientes a treinar que saiu um da sala
	for(unsigned int i = 0; i< clientes.size(); i++)
	{
		if(clientes[i]->estarATreinar())
		{
			clientes[i]->reageSaida(this);
		}
	}
}

void Ginasio::removeCliente(unsigned bi)
{
	//procura o cliente na base de dados de clientes
	unsigned int indice = pesquisaClienteDadoBi(bi);
	if(indice == -1)
	{
		return;
	}
	//encontrou manda sair do treino
	saiClienteDoTreino(bi);

	//antes de ir embora pagar a conta
	clientes[indice]->paga();

	//apaga, os clientes pertencem ao ginasio
	delete clientes[indice];
	//retira do vector o ponteiro para memoria já libertada
	clientes.erase(clientes.begin() + indice);
}

Ginasio::Ginasio():relogio(0)
{
}

Ginasio::~Ginasio()
{
	//apaga as fichas
	for(unsigned int i = 0; i< clientes.size(); i++)
	{
		delete clientes[i]; //os clientes pertencem ao ginasio
	}
}

unsigned Ginasio::getNumClientesATreinar() const
{
	unsigned int n = 0;
	for(unsigned int i = 0; i<clientes.size();i++)
	{
		if(clientes[i]->estarATreinar())
		{
			n++;
		}
	}
	return n;
}

Ginasio& Ginasio::operator=(const Ginasio& orig)
{
	//testar a auto atribuição se sao o mesmo objecto, "ja nao sao iguais"
	//nao se libertam recursos dos destino da atribuição porque coincide com a origem
	if(this == &orig)
	{
		return *this;
	}
	//apaga o conceudo ja existente no "alvo" da atribuicao (*this)
	for(unsigned int i = 0; i< clientes.size(); i++)
	{
		delete clientes[i]; //apaga mesmo os clientes (eram do ginasio)
	}
	//os clientes foram apagados, mas os ponteiros
	clientes.clear(); //ainda estão no vector, o qual deve ser esvaziado

	for(unsigned int i = 0; i<clientes.size(); i++)
	{
		//independentemente do tipo do cliente, duplica
		clientes.push_back(orig.clientes[i]->duplica());
	}
	//copiar o valor do relgio
	relogio = orig.relogio;
	return *this;
	
}

Ginasio::Ginasio(const Ginasio& orig)
{
	//nao é preciso pre inicialização explicita porque o vector e
	//inicializado automaticamente com o seu construtor por omissao
	//um avez que nao foi usado nenhum outro na lista de inicializaca deste construtor
	//e que o deixa  vazio e pronto a usar. noutros casos poderia ser necessario algo aqui
	*this = orig;
}

string Ginasio::getAsString() const
{
	ostringstream oss;

	oss << "\n ginasio" << "(tempo " << relogio << ")" << "clientes: " << endl;
	for(unsigned int i = 0 ; i < clientes.size(); i++)
	{
		oss << clientes[i]->getAsString() << endl;
	}
	oss << "\na treinar " << endl;
	for(unsigned int i = 0; i< clientes.size(); i++)
	{
		if(clientes[i]->estarATreinar())
		{
			oss << clientes[i]->getAsString() << endl;
		}
	}
	return oss.str();
}

int main()
{


	cout << "\nfim do main" << endl;
	return 1;
}

}

………..ficha7, exercicio5 (a24)

#include <string>
#include <iostream>
#include <sstream>
#include <vector>
#include <regex>
#include <initializer_list>
#include <fstream>

using namespace std;


class Tagarela;
class FalaPouco;

//classe base, abstracta, relação de 
class Tarifario
{
	//nao existem dados, quem tem é o Cartao
	//nao tem informação
public:
	//só tem funções
	Tarifario() = default;

	virtual float calculaCustoChamada(int s) const = 0; //virtual e =0
	virtual float fazCarregamento(float quantia) const = 0;
	virtual bool autorizaChamada(int saldo) const = 0;

	virtual string getNome()const = 0;
	virtual Tarifario* duplica() const = 0; //por causa do operador atribuição na classe rede

	static Tarifario* fabrica(string tipo); //fabrica de tarifarios, para os arrumar

	virtual string getAsString() const;
};

Tarifario* Tarifario::fabrica(string tipo)
{
	if(tipo=="Tagarela")
	{
		return new Tagarela;
	}else if(tipo == "FalaPouco")
	{
		return new FalaPouco;
	}else
	{
		return nullptr;
	}
}

string Tarifario::getAsString() const
{
	ostringstream oss;
	oss << "tarifario: " << endl;
	return oss.str();
}

//classe derivada
class Tagarela : public Tarifario
{
	//existem constantes desta classe
	static const float PRIMEIRO_MINUTO;
	static const float MINUTOS_SEGUINTES;
	static const float BONUS;
	static const float BASE;
public:
	float calculaCustoChamada(int s) const override;
	float fazCarregamento(float quantia) const override;
	bool autorizaChamada(int saldo) const override;
	string getNome() const override;
	Tarifario* duplica() const override;
	string getAsString() const override;
};
//concretizar as constantes
const float Tagarela::PRIMEIRO_MINUTO = 0.02f;
const float Tagarela::BONUS = 5.0f;
const float Tagarela::BASE = 25.0f;
const float Tagarela::MINUTOS_SEGUINTES = 0.02f;


float Tagarela::calculaCustoChamada(int s) const
{
	if(s<=0) //saldo
	{
		return 0;
	}
	float aux_custo = PRIMEIRO_MINUTO;
	if(s>60)
	{
		aux_custo += MINUTOS_SEGUINTES * (s - 60) / 60.0;
	}
	return aux_custo;
}

float Tagarela::fazCarregamento(float quantia) const
{
	if(quantia<BASE)
	{
		return 0;
	}else if(quantia>=2*BASE)
	{
		quantia += BONUS;
	}
	return quantia;
}

bool Tagarela::autorizaChamada(int saldo) const
{
	return saldo >= -PRIMEIRO_MINUTO;
}

string Tagarela::getNome() const
{
	return  "Tagarela";
}

Tarifario* Tagarela::duplica() const
{
	return  new Tagarela(*this);
}

string Tagarela::getAsString() const
{
	ostringstream oss;
	oss << "tagarela: " << endl;
	return oss.str();
}

//classe derivada
class FalaPouco : public Tarifario
{
	static const float TODOS_MINUTOS;
	static const float CARREGAMENTOS;
	static const float BONUS_CARREGAMENTOS;
public:
	float calculaCustoChamada(int s) const override;
	float fazCarregamento(float quantia) const override;
	bool autorizaChamada(int saldo) const override;
	string getNome() const override;
	Tarifario* duplica() const override;
	string getAsString() const override;
};
//concretizar as constantes
const float FalaPouco::TODOS_MINUTOS = 0.25f;
const float FalaPouco::CARREGAMENTOS = 10.0f;
const float FalaPouco::BONUS_CARREGAMENTOS = 0.2f;

float FalaPouco::calculaCustoChamada(int s) const
{
	if(s<0)
	{
		return 0;
	}
	return TODOS_MINUTOS * s / 60.0;
}

float FalaPouco::fazCarregamento(float quantia) const
{
	if(quantia<CARREGAMENTOS)
	{
		return 0;
	}
	int n = rand() % 10; //de 0 a 9
	if(n<2) //<2 é 20%
	{
		quantia *= 2;
	}
	return quantia;
}

bool FalaPouco::autorizaChamada(int saldo) const
{
	//ou talvez meu
	if(saldo<=(TODOS_MINUTOS*10))
	{
		return false;
	}
	return true;
	//ou
	//return saldo >= - TODOS_MINUTOS * 10;
}

string FalaPouco::getNome() const
{
	return "FalaPouco";
}

Tarifario* FalaPouco::duplica() const
{
	return new FalaPouco(*this);
}

string FalaPouco::getAsString() const
{
	ostringstream oss;
	oss << "falapouco" << endl;
	return oss.str();
}

class Cartao
{
	long numero;
	float saldo;
	Tarifario* tarifario;
public:
	Cartao(const long numero, Tarifario* const tarifario);
	virtual ~Cartao();


	long getNumero() const;
	float getSaldo() const;
	string getNomeTarifario() const;

	void setTarifario(Tarifario* const tarifario0);

	bool autorizaChamada()const;
	void registaChamada(int saldo);
	bool fazCarregamento(float quantia);

	string getAsString()const;

};
bool operator==(const Cartao& orig1, const Cartao& orig2); //para dois tarifários iguais!!

Cartao::Cartao(const long numero0, Tarifario* const tarifario0):numero(numero0), tarifario(tarifario0), saldo(0){}

long Cartao::getNumero() const
{
	return numero;
}

float Cartao::getSaldo() const
{
	return saldo;
}

string Cartao::getNomeTarifario() const
{
	return tarifario->getNome();
}

void Cartao::setTarifario(Tarifario* const tarifario0)
{
	this->tarifario = tarifario0;
}

bool Cartao::autorizaChamada() const
{
	//função polimorfica, conforme o tarifario
	return tarifario->autorizaChamada(saldo);
}

void Cartao::registaChamada(int saldo0)
{
	//função polimorfica, conforme o tarifario
	float aux_custo = tarifario->calculaCustoChamada(saldo0);
	saldo = -aux_custo;
}

bool Cartao::fazCarregamento(float quantia0)
{
	//função polimorfica, conforme o tarifario
	float aux_carregamento = tarifario->fazCarregamento(quantia0);
	saldo += aux_carregamento;
	return aux_carregamento > 0;
}

string Cartao::getAsString() const
{
	ostringstream oss;
	oss << "(numero " << numero << " saldo: " << saldo << " tarifario " << tarifario->getNome() << ")";
	return oss.str();
}

bool operator==(const Cartao& orig1, const Cartao& orig2)
{
	return orig1.getNumero() == orig2.getNumero();
}


class Rede
{
	string nome;
	//tarifarios é uma classe abstracta
	//logo não pode haver objectos de uma classe abstracta
	//vector <Tarifario> tarifarios;
	//e queremos ponteiros para a classe base, e uma coleção polimorfica
	vector <Tarifario*> tarifarios;
	//cartoes não tem derivadas
	//e podia ser vector <Cartao> cartoes;
	vector <Cartao*> cartoes;

	Tarifario* procuraTarifario(const string& nome) const;
public:
	Rede(const string& nome0);

	//rede composição: qd a rede deixar de existir os tarifários tb deixam
	Rede(const Rede& ob);
	Rede & operator=(const Rede& ob); //tem uma dificuldade
	~Rede();

	void setNome(const string& nome0);

	bool acrescentaTarifario(const string& nomeTarifario);
	bool acrescentaCartao(long num, const string& nomeTarifa);

	int procuraCartao(long i)const;
	bool removeCartao(long i);

	bool registaChamada(long numero, int duracao);
	bool fazCarregamento(long numero, float quantia);
	bool autorizaChamada(long n)const;

	string getAsString() const;
	
};
ostream& operator<<(ostream& saida, const Rede& rede);

Tarifario* Rede::procuraTarifario(const string& nome) const
{
	for(Tarifario *t : tarifarios)
	{
		if(t->getNome() == nome)
		{
			return t;
		}
	}
	return nullptr;
}

Rede::Rede(const string& nome0):nome(nome0)
{
}

Rede::Rede(const Rede& ob)
{
	*this = ob;
}

Rede& Rede::operator=(const Rede& ob) //immportante, complicado
{
	//prevenção da auto atribuicao
	if(this == &ob)
	{
		return  *this;
	}
	//libertar mem. dinamica apontada pelo primeiro membro da atribuicao
	//e esvaziar os vectores
	for(Tarifario *t: tarifarios)
	{
		delete t;
	}
	tarifarios.clear();
	for(Cartao *c: cartoes)
	{
		delete c;
	}
	cartoes.clear();
	//copiar os dados do segundo membro da atribuição
	nome = ob.nome;
	for(Tarifario * t: ob.tarifarios)
	{
		tarifarios.push_back(t->duplica());
	}
	//depois de todos os tarifários do primeiro membro da atribuição copiados
	for(Cartao *c: ob.cartoes)
	{
		Cartao* novo = new Cartao(*c);
		//cópia do cartao
		//que aponta para um tarifario do segundo membro da atribuicao
		string nomeTarifario = c->getNomeTarifario();

		//identifica do seu tarifario
		//procura tarifario com nomeTarifario no vector do primeiro membro da atribuicao 
		Tarifario* t = procuraTarifario(nomeTarifario);
		novo->setTarifario(t);
		
		cartoes.push_back(novo);
	}
}

Rede::~Rede()
{
	//porque sao vectres de ponteiros para objectos dinamicos
	for(Tarifario *t: tarifarios)
	{
		delete t;
	}
	for(Cartao *c: cartoes)
	{
		delete c;
	}
	//e o que o destrutor libetra
	//o construtor por copia e o operador atribuicao tem que duplicar
	cout << "destr da rede " << nome << endl;
}

void Rede::setNome(const string& nome0)
{
	this->nome = nome0;
}

bool Rede::acrescentaTarifario(const string& nomeTarifario)
{
	Tarifario* tarifario0 = procuraTarifario(nomeTarifario);
	if(tarifario0 != nullptr)
	{
		return  false;
	}
	Tarifario* novoTarifario = Tarifario::fabrica(nomeTarifario);
	if(novoTarifario == nullptr)
	{
		return false;
	}
	tarifarios.push_back(novoTarifario);
	return true;
}

bool Rede::acrescentaCartao(long num, const string& nomeTarifa)
{
	if(procuraCartao(num) != -1)
	{
		return false;
	}
	Tarifario* tf = procuraTarifario(nomeTarifa);
	if(tf == nullptr)
	{
		return false;
	}
	cartoes.push_back(new Cartao(num, tf));
	return true;
}

int Rede::procuraCartao(long i) const
{
	for(unsigned int indice = 0; indice < cartoes.size(); indice++)
	{
		if(cartoes[indice]->getNumero() == i)
		{
			return indice;
		}
	}
	return -1;
}

bool Rede::removeCartao(long i)
{
	int aux = procuraCartao(i);
	if(aux == -1)
	{
		return false;
	}
	//relação de composição
	delete cartoes[aux]; //libetra o objecto
	cartoes.erase(cartoes.begin() + aux);//tira o ponteiro do vector
	return true;
}

bool Rede::registaChamada(long numero, int duracao)
{
	int aux = procuraCartao(numero);
	if(numero == -1)
	{
		return  false;
	}
	cartoes[aux]->registaChamada(duracao);
	return true;
}

bool Rede::fazCarregamento(long numero, float quantia)
{
	int aux = procuraCartao(numero);
	if(aux== -1)
	{
		return false;
	}
	return cartoes[aux]->fazCarregamento(quantia);
}

bool Rede::autorizaChamada(long n) const
{
	int aux = procuraCartao(n);
	if(aux == -1)
	{
		return false;
	}
	return cartoes[aux]->autorizaChamada();
}
string Rede::getAsString() const
{
	ostringstream oss;
	oss << "\nRede: " << nome << endl << " tarifarios: ";
	for(Tarifario *t : tarifarios)
	{
		oss << t->getNome() << "\t";
	}
	oss << "\nCartoes: " << endl;
	for(Cartao *c : cartoes)
	{
		oss << c->getAsString() << endl;
	}
	return oss.str();
}

ostream& operator<<(ostream& saida, const Rede& rede)
{
	saida << rede.getAsString();
	return saida;
}


int main(){
	
	Rede* rede = new Rede("meo");
	rede->acrescentaTarifario("Tagarela");
	rede->acrescentaTarifario("FalaPouco");
	rede->acrescentaCartao(10, "Tagarela");
	rede->acrescentaCartao(20, "FalaPouco");
	cout << rede->getAsString();
	rede->removeCartao(10);
	cout << rede->getAsString();
	
	delete rede;
	

	cout << "\nfim do main" << endl;
	return 0;
}
Tags : , , , ,

0 thoughts on “herança e polimorfismo”

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.