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;
}
Tags : , , , ,

0 thoughts on “objetos dinâmicos, matrizes dinâmicas, classes com construtores por cópia, operador de atribuição e destrutor”

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.