PAM, Plastic Army Men

Há muito tempo que não ouvia falar destes bonecos de plástico verdes, militares e em alguns casos também existiam veículos. Tantas horas que brinquei sozinho e com um amigo com estes bonecos.
Encontrei alguém que se deu ao trabalho de construir um plano para se jogar com estes bonecos. Basta ter os bonecos e construir um cenário  :)
É um projeto interessante :)

Não sou fã das versões em grande, gostei sempre das versões mais pequenas dos bonecos, sempre eram “mais realistas” para estarem juntos dos veículos.

+infos(livro): https://payhip.com/b/Ksl54

+infos(rede social): LINK

Tags :

Propostas de trabalho (no Porto)

A FABAMAQ tem em aberto várias propostas de trabalho:

SOFTWARE DEVELOPER – GAME DEVELOPMENT
Responsibilities:
– You will use your Software Development skills on our Game Development context, a fast pace development environment will be waiting for your contribution.
– From design to hands on implementation of our game features, you will work, interact and develop games along with Graphic Artists, Sound Designers, work closely with Game Testers. An agile coach will help and push you on this journey and a Product owner will work closely with our clients in order to give your team the knowledge you need to build successful games.
– Your contribution will add value to a code base that has shipped multiple products and that needs constant innovation, demands you to be eager to learn as well to question it along the way in order to improve its capability to fulfill our client’s needs.
– You will be developing games, with focus on quality, performance and reliability, so along the way your problem solving skills will be needed not only to create new features but also to solve detected bugs and improve our software health.
– We expect you to be Self-driven and excel at completing tasks in a minimally supervised environment.
Expected:
– Degree in Computer Science, related field or equivalent experience
– Good knowledge of Software Architecture and Software Patterns.
– Good Analytical, and problem solving skills.
– Experience coding in C++.
– Knowledge of Javascript fundamentals.
– Full software life-cycle application development – designing, coding, debugging, testing and documenting applications.
– Being a good team player, able to deal with different ways of working and thinking.
– Proactive mindset to fix bugs.

Digital Game Development
Responsibilities:
Development and maintenance of software related to the provision and integration of online games (fortune and chance);
Expected:
– Either/Both a degree in Computer Science (or similar area) or proven experience in software development;
– Two years of professional experience in software development or similar position;
– Proficiency in Python 2.7+ and Python 3.8+;
– Familiarity with Git;
– Competence in Unix.

Godot Game Development
Responsibilities:
– Development and maintenance of software related to Godot Engine;
– Development and maintenance of our web-based game engine for casino games (slots, bingo, poker, etc);
– Supporting the development of tools to bridge the design team work with our engine.
Expected:
– Proficiency with development in Godot Game Engine;
– Either/Both a degree in Computer Science (or similar area) or proven experience in software development;
– Familiarity with Git and Python.

+infos(oficial): https://www.fabamaq.com/

Tags :

Uma campanha pela malta da Unity Store..

A Unity Store volta e meia tem uma campanha a decorrer. Neste momento tem uma com algumas coisas interessantes. A lista é:
RPG Monster Wave Polyart
New Textures & Standard Pipeline Conversion for Book of the Dead
Animal pack deluxe
Cartoon FX Remaster
Easy Trail Effect (URP & LWRP)
Lean Touch+
Magic Arsenal
2D Pixel Unit Maker – SPUM
Polygon Arsenal
The Illustrated Nature
Character Controller Pro
ArchVizPRO Interior Vol.2
Puppet Face
Mountain Trees – Dynamic Nature
Emerald AI 3.0
Animal Controller
Dreamteck Splines
Ultimate Game Music Collection
Survival Engine – Crafting, Building, Farming
Aura 2 – Volumetric Lighting & Fog
Master Audio: AAA Sound
Toon City
Enviro – Sky and Weather

+infos(a campanha): LINK

Tags : ,

Humble Software Bundle: Unity, FPS Games & Game Dev Assets (uma campanha)

Uma campanha na plataforma Humble.. com vários assets para serem usados no Unity no desenvolvimento do género FPS e dois jogos. Da lista de prendas desta campanha consta:
UFPS: Ultimate FPS
SCI FI CHARACTERS MEGA PACK VOL 2
Character Movement Fundamentals
Highlight Plus
Tannenberg – Steam Game
Verdun – Steam Game
Polarith AI Pro | Movement with 3D Sensors
Sensor Toolkit
Super Multiplayer Shooter Template
CScape City System
3D Scifi Kit Vol 3
Impact – Physics Interaction System
Animated Hands with Weapons Pack
Post Apocalyptic World Pack
ProTips – Tooltip System
RV Smart AI
RV Honor Ai
Gun & Explosion Sounds
Colossal Game Music Collection
GUI PRO Kit – Sci-Fi Survival
Sci-Fi Gun Sounds
Sci-fi Weapons Arsenal
Footstep and Foley Sounds
CITADEL: Desert Environment Pack
JU TPS 2 : Third Person Shooter System + Vehicle Physics
Shooting Range Interiors

+infos(a campanha): LINK

Tags : , , , , , , ,

resolução de exercícios

#exame 2019-2020 e #exame 2016-2017
Exame da Época Especial – Avaliação prática – P1

==teórica)
1. Diga, justificando, se é correcto afirmar-se que o seguinte método permite apenas copiar o conteúdo de um ficheiro para outro. Se a resposta for negativa, inclua na justificação pelo menos um contra-exemplo.
public static void copy(java.io.InputStream in, java.io.OutputStream out) throws java.io.IOException
{
int c;
while ((c = in.read()) != -1){
out.write(c);
}
}

R:
pode ser usado também para leitura e escrita em sockets
as classes InputStream e OutputStream são classes abstractas, e uma classe abstracta são aquelas em que existe pelo menos um método não implementado
neste exemplo temos um método que recebe dois métodos: InputStream e OutputStream
o InputStream é uma classe abstracta que tem métodos do tipo: read, read só com um caracter, receb arrays de bytes e devolve o numero de bytes copiados, e subarrays, ..
o OutputStream é uma classe abstracta que tem métodos do tipo: tem métodos para escrever, e que permite ir buscar bytes ou um fluxo de bytes, por exemplo no ecrã, num ficheiro, numa ligação TCP, pode ser um array de bytes,..

mas a resposta é não porque são classes abstractas
posso copiar de ficheiro para ficheiro
posso copiar de ficheiro para socket
posso copiar de socket para ficheiro

para teste:
o OutputStream só permite serializar para ficheiro? ou só permite serializar para socket?
r:
não porque ao criar um objecto OutputStream passamos-lhe qualquer coisa que é OutputStream
o que o wirte and share do OutputStream precisa de receber um objecto que implemente os métodos do OutputStream, e não interessa como

para teste:
o que faz o método write object no OutputStream
r:
o write object implementa o algortimo de serialização, pega num objecto, que na realidade é uma arvore de objecto (porque depois temos referências), e o que produz num formato especifico que é um binário java, produz um fluxo de bytes contiguos que permite desctever no objecto as várias classes envolvidas,as versões, os valores, os membros, .., e que permite depois ser transmitido ou guardar

para teste:
o que um driver, o que faz um driver jbdc?
R:
o driver é um conjunto de classes que vamos buscar num jar e que tem classes/métodos que implementam a api do jbdc
o driver é a implementação dessa API, dessas classes, para acesso a servidores de BD especificos

para teste:
R:
porque não posso usar um conector mysql para aceder a uma base de dados de oracle?
têm drivers diferentes, porque muitas das coisas que as classes/métodos fazem é estabelecer uma ligação TCP ao servidor remotamente
e enviar pedidos num determinado formato que tem a ver com o protocolo e os SGBD, e quem desenvolveu o protocolo não desenvolveu nenhum protocolo de comunicação ao nivel a aplicação, entre o cliente o servidor BD, não implemntou de forma standart e por esse motivo as mensagens e as trocas de mensagens são diferentes

==teórica)
2. Geralmente, associado a plataformas de middleware que oferecem a abstracção de objecto remoto/distribuído, existem aplicações que, em termos genéricos, podem ser designadas de serviços de nomeação (por exemplo, rmiregistry.exe, tnamrserv.exe e orbd.exe). Explique quais são os seus dois objectivos principais e de que forma estes são atingidos (ou seja, enumere as principais operações/passos executados desde a fase de arranque). Na resposta, que não deve incluir código, utilize, entre outros, os termos socket, mensagem, porto e thread.
r:
conceito de RMi (ou corba)
estas têm uma aplicação autónoma, mas que têm o mesmo objectivo e que são os serviços de nomeação
rmiregistry (no RMi)
orbd (no Corba)
o rmiregistry
os dois principais objectivos são:

ao inves de saber o ip e o porto automático do servidor, mas eu coloco numa maquina qualquer com o ip conhecido e com porto fixo de 1099,
assim
o servidor quando arranca contacta (ligação TCP) o rmiregistry
e envia uma informação a dizer regista este proxy/este serviço sob este nome
uma aplicação que quer aceder ao serviço contacta o rmiregistry (ligação TCP, no ip e no porto 1099) a pedir o serviço remoto
o rmiregistry faz o lookup e devolve serializado ou envia uma excepção.
a aplicação recebe, tem uma classe, recebe um objecto do tipo, onde tem o ip e o porto da maquina(servidor) onde está o serviço

r2:
dois objectivos:
registar serviços com um determinado nome, referências para objectos remotas sob determinados nomes, e permite obter essas referencias através de queries
e permite obter a referência, isto é, permite fazer um submit e um get
e enumere as principais fazes de arranque:
é um servidor TCP concorrente, que é posto a correr,
e quando quero utilizar o serviço faço uma ligação TCP com a indicação do porto, e é enviado um pedido sobre a forma de uma mensagem

o servidor está à espera de pedidos de ligação, e como é um servidor concorrente, sempre que alguém se liga cria uma thread, aguarda o pedido e responde
(lembrar que só existe uma forma de comunicar na internet, e é através de sockets)

para teste:
o que faz, qual o objectivo este método estático e o que é desencadeado quando o chamam:
Naming.bind(“rmi://192.168.1.1/nome1”, o);
objetivo: solicitar a uma aplicação rmi, que está a correr na maquina com o ip 192.168.1.1, com o porto 1099, e enviar-lhe o registo do serviço/referencia remoto o, com o nome nome1
estabelece um ligação TCP, e enviar-lhe uma mensagem, com o regista-me aí um serviço RMi com o nome nome1, e também toma a referência serializada o
se correr bem ele acrescenta
se correr mal ou se já existir ele lança uma excepção
e ele envia uma resposta (uma excepção ou um true ou um false)

para teste:
Naming.rebind(“rmi://192.168.1.1/nome1”, o);

para teste:
o que faz, qual o objectivo este método estático e o que é desencadeado quando o chamam:
Naming.lookup(“rmi://192.168.1.1/nome2″);
contactar uma aplicação Rmi registry que está no ip 192.168.1.1, na porta 1099, de qualquer coisa que ele tem com o nome nome2
estabelece um ligação TCP, no ip e no porto
constroi uma mensagem que obtem a referencia para o nome2
serializa a mensagem, através da ligação TCP
do outro lado o registry vai receber a mensagem, e verifca se corre bem, se encontra, e devolver o resultado
e quando se recebe a mensagem desserializa-a e vê a resposta, e com base na resposta devolve a referencia remota ou lança uma excepção

==teórica)
3.Diga qual é o objectivo do seguinte método e descreva o significado de cada um dos campos que compõem a URL passada como argumento (rmi, 192.168.1.1, 1099 e RMILightBulb):
java.rmi.Remote r = java.rmi.Naming.lookup(“rmi://192.168.1.1:1099/RMILightBulb”).
r:
o objecto é obter uma referencia remota para o objecto que está registado no rmiregistry com o nome RMILightBulb
rmi, é o protocolo usado na comunicação, é o que define as mensagens trocadas entre a aplicação que chama isto e a aplicação do outro lado
192.168.1.1, é o ip onde está a correr o rmiregistry
1099, é o porto onde está a correr o rmiregistry
RMILightBulb, é o nome do serviço

para teste:
o que é que acontece por baixo com java.rmi.Remote r = java.rmi.Naming.lookup(“rmi://192.168.1.1:1099/RMILightBulb”)?
r:
estabelece uma ligação TCP naqueles ip e porto, envia uma mensagem com um pedido para uma referência remota de um objecto que se chama RMILightBulb e aguarda resposta
se a resposta for um objecto do tipo excepção faz o throw da excepção
caso contrário faz o return do que recebeu e depois temos que fazer o cast

==teórica)
4. O pedaço de código seguinte permite obter um recurso alojado um servidor Web através do protocolo HTTP, recorrendo a uma classe específica que encapsula esse tipo de interacção. Sabendo que o HTTP é um protocolo do nível de aplicação que recorre ao protocolo de transporte TCP e, por imissão, ao porto 80, deduza a sequência de acções/passos principais desencadeados pelo método openStream (1- Estabelece… 2- … m- Envia… n- Obtém… o-
Devolve…). A resposta não deve incluir código.
java.net.URL myURL = new java.net.URL (“https://moodle.isec.pt/moodle/mod/folder/view.php?id=470″);
java.net.InputStream in = myURL.openStream();
int b;

while(true){
b = in.read();

}
r:
existe um objecto do tipo:
java.net.URL myURL
depois temos
java.net.InputStream in = myURL.openStream();
e de seguida:
b = in.read();
e com tudo isto estou a receber o conteudo da resposta get que foi enviado para este servidor e para este recursoview.php?id=470

o URL pode dar-me uma excepção
quando se faz o myURL.openStream(), e
estabelece uma ligação TCP nesta maquina (https://moodle.isec.pt/)
envia um pedido get oara identificar como recurso o URI: moodle/mod/folder/view.php?id=470
e do outro lado ele vai enviar uma resposta com várias linhas de texto com vários \n \n e fecha a ligação TCP
no buffer de entrada eu vou ter os bytes enviados, que é a resposta
fica associado ao objecto java.net.InputStream in = myURL.openStream();
e ao fazer o read b = in.read();
vão ser lidos os bytes

==teórica)
5. Acrescente uma única linha de código na classe UseMyThreads ou MyThread de modo a que a thread t2 apenas inicie depois de t1 deixar de estar activa. Altere igualmente a declaração do método metodo1 de modo a que, se várias threads possuírem uma referência para a mesma instância da classe MyThread, este apenas possa ser executado por uma única thread em cada instante.
public class MyThread extends Thread {
X x;
public MyThread(X x){
this.x = x;
}

public metodo1(){

}

public void run() {

}

}

public class UseMyThreads {

public static void main(String args[]){

Thread t1 = new MyThread(new X()).start();
Thread t2 = new MyThread(new X()).start();

}
}
r:
a Thread t1 = new MyThread(new X()).start();
vai correr o run

assim e no UseMyThreads podemos usar um JOIN
Thread t1 = new MyThread(new X()).start();
t1.join;

r2:
ou até podia olhar para:
assim e no MyThread e no run() podemos fazer
synhcronized(x){…};
mas quando fazermos new MyThread(new X()).start();
estamos a criar objectos novos e não vão bloquear logo esta solução não é válida só seria se
ao invés de:
Thread t1 = new MyThread(new X()).start();
Thread t2 = new MyThread(new X()).start();
e se existir:
declaração de um X = new X
e passar o X para dentro de cada thread este mesmo X
e agora sim vem o synhcronized do X
mas isto tb não é veridico face ao não sabes como vai ser o escalonamento e isso depende do SO

atenção: não é porque no código existe uma sequencia que u output é sempre igual.. as coisas variam face ao escalonamento

r3:
segunda parte da resposta é meter o método 1 como synhcronized
na classe MyThread
public synhcronized metodo1(){ … }
eu posso fazer synhcronized ao nivel do método no run nao posso só internamente

r4 final:
primeira parte:
assim e no UseMyThreads podemos usar um JOIN
Thread t1 = new MyThread(new X()).start();
t1.join;

segunda parte da resposta é meter o método 1 como synhcronized
na classe MyThread
public synhcronized metodo1(){ … }
eu posso fazer synhcronized ao nivel do método no run nao posso só internamente

==teórica) #exame 19-20 especial
1.
considere uma api web (web service) que incluir entre outras s seguintes URI:
1) /users?address=”coimbra”
2) /users/delete?address=”coimbra”
3) /users/coimbra
4) /users/coimbra10
extras
5) /users/10/update?address=”coimbra”
6) /users/insert?id=10&name=”ana”&address=”coimbra”

a) indique para cada uma um possivel significado
r:
1) lista de utilizadores com morada em coimbra
2) manda apagar da lista de utilizadores com a morada em coimbra
3) lista de utilizadores que vivem em coimbra
4) identifica o utilizador com o codigo 10, dos utilizadores que vivem em coimbra OU a 10ª página de utilizadores de coimbra OU o registo 10 em coimbra
extras
5) um pedido de update da morada do utilizador com o codigo 10
6) inserir nos utilizadores com os dados…

b) identifique, justificando a URI que não serve os principios REST e apresente, igualmente uma alternativa que esteja correcta
olhar para as primeiras 4
2) tem um verbo, a URI só deve identificar o recurso a URI correta seria
as URI identificam o recurso, as acções é através de um verbo, que vai na mensagem http

==teórica) #exame 19-20 especial
2)
explique o conceito de callback/notificação assincrona em sistemas distribuidos e de que forma pode conseguir-se esta funcionalidade em aplicações baseadas no paradigma de objecto remoto (e.g JavaRmi). não recorra a código na resposta
explique o conceito de callback/notificação assincrona em sistemas distribuidos e de que forma pode conseguir-se esta funcionalidade em aplicações baseadas em sockets TCP (e.g., instâncias da classe java.net.Socket na linguagem java). não recorra a código na resposta
explique o conceito de callback/notificação assincrona em sistemas distribuidos e de que forma pode conseguir-se esta funcionalidade em aplicações baseadas em sockets UDP (e.g. instâncias da classe java.net.DatagramSocket na lingiagem java). não recorra código na resposta)

==teórica) #exame 19-20 especial
3.
consider a seguinte instrução:
java.rmi.Naming.unbind(“rmi://reg.isec.pt/5001/time”);
java.rmi.Naming.bind(“rmi://reg.isec.pt/5001/time”, timeService);
java.rmi.Remote r = java.rmi.Naming.lookup(“rmi://reg.isec.pt:5001/time”);

a) explique o que identificam os elementos “reg.isec.pt”, “5001”, e “time”
b) deduza a sequência de acções/passos principais desencadedos quando esta insgtrução é invocada (ligações estabelecidas, mensagens trocadas, etc.) a resposta não deve incluir código

==teórica) #exame 19-20 especial
4. para uma aplicação desenvolvida em Java aceda a um determinado sistema de gestão de base de dados (SGBD), pode recorrer-se à API JBDC. para o efeito é necessário usar um driver adequado ao tipo de SGBD acedido (por exemplo, mysql-connector-java-5.1.45-bin.jar para MySQL e obdc8.jar para oracle)
explique:
a) o que é comum a todos os drivers JDBC, independentemente do SGBD alvo;
r:
todos oferecem a API jbdc, é o api do jbdc
b) o que difere entre drivers JDBC destinados a SGBD distintos
r:
são implementados de forma diferente
o protocolo de comunicação é diferente do procotolo de comunicação MySQL

==prática)
1. (pergunta de api rest) considere a seguinte mensagem HTTP destinada a pedir, a uma determinada API/serviço web, a lista de undiades curriculares concluidas por um determinado aluno, identificado através do seu número de estudante num determinado ano lectivo e assmindo um esquema de autenticação baseado em tokes:

POST /alunos/list/ucs/concluidas HTTP/1.1
Host: api.pd.com
User-Agent: curl/7.55.1
Student-number: 201012345
Year: 202-21
Accept: */*

{“Authorization”:”TK asdasdasdsadsadsad”}

Este pedido apresenta várias incorreções relativamente à aplicação dos principios REST e à estruturação habitual de pedidos HTTP (i.e, colocação da informação no formato adequado e na parte certa da mensagem).
a) complete o pedido HTTP seguinte de modo a que este seja uma reformulação correcta da mensagem anterior
R:
as boas práticas dizem que:
na URI deveia ser um GET
GET /alunos/list/ucs/concluidas HTTP/1.1
o token deve estar no cabeçalho e num campo chamado Authorization
e o numero do aluno devia estar no corpo do pedido ou colocar mesmo na URI, mas neste caso até podiamos fazer uso do token
e também existe um erro em /alunos/list/ucs/concluidas pois o list devia surgir no final. partir de uma coisa mais genérica e vamos afunilando

ou resposta possivel (com parametros):
GET /alunos/22232323/ucs/concluidas?year=2020-21 HTTP/1.1
Host: api.pd.com
User-Agent: curl/7.55.1
Student-number: 201012345
Accept: */*
Authorization:TK asdasdasdsadsadsad

ou
GET /alunos/22232323/ucs/concluidas?year=2020-21&nota-minima=15 HTTP/1.1

b) complete a mensaem HTTP seguinte, sendo este um exemplo de resposta ao pedido anterior e considerando que é devolvida uma lista com duas unidades curriculares, sendo cada uma caracterizada por apenas dois atributos: cod_uc e nota. Pode atribuir qualquer valor aos atributos desde que façam algum sentido no contexto da pergunta
HTTP/1.1 ??????
Content-type: application/json
Date: Tue, 2 Fev 2021 10:13:05 GMT
?????

r:
HTTP/1.1 200 OK
Content-type: application/json
Date: Tue, 2 Fev 2021 10:13:05 GMT
[{“cod_uc”:”1111″,”nota”:”11″},{“cod_uc”:”2222″,”nota”:”12″}]

cuidados:
ao invés de: Content-type: application/json
pode ser application/txt
ou pode ser application/html

==prática)
2. explique, sem recorrer a código, quais são as ações principais que o método stop realiza ao ser invocado no pedaço de código abaixo (nota: não é o objectivo do méotod, ou seja, parar um senor remoto com código igual a 2, que deve explicar)
import Java.rmi.*
Remote ref = Naming.Lookup(“rmi://193.138.11.34/sensors_controller”);
ControllerInterface remoteSenosrs = (ControllerInterface) ref;
remoteSenosrs.stop(2);

a resposta deve obrigatoriamente mencionar os termos “serviço RMI”, “TCP”, “porto de escuta automático”, “endereço de IP”, “serialização binária” ou algo relacionado, “pedido” e “resposta”, entre outros possiveis. Quando referir os termos “porto de escuta automático” e “endereço IP” e “endereço IP” deve igualmente indicar onde os respetivos valores estão guardados. seja analitico e apresente a resposta soba forma de uma sequência ordenada de acções/passos (10 no máximo)

r:

==prática)
1. Pretende-se que desenvolva, em linguagem Java, um método atendendo aos seguintes requisitos:
Protótipo do método pretendido:
void processRequest(Socket s) throws Exception;

O socket TCP s já se encontra criado e conectado a um par remoto, estando pronto para o envio e recepção de dados;
O médoto processRequest vai recebendo objectos serializados do tipo Request através do socket s até que ocorra uma excepção qualquer;
A classe Request possui, entre outros, os métodos int getUdpPort(), String getIpAddress() e String getMsg();
Para cada objecto Request recebido, a string devolvida pelo método getMsg() é enviada, através do protocolo UDP (DatagramSocket) e em formato texto (i.e., sequência de caracteres) para o destino com o endereço IP e o porto estipulados;

Quando ocorre uma excepção de qualquer tipo, o método processRequest:
Encerra o socket s;
Apresenta a mensagem associada à excepção;
Volta a lançar a excepção, o que faz com que termine.

import java.net.*;
void processRequest(Socket s) throws Exception

{
. . .
while(true)
{
/* Receive a serialized Request object */
. . .
/* Transmit the specified message to the specified IP
address and UDP port.
The message is transmitted as a sequence of characters (i.e., it is not transmitted as a serialized String object).

*/
. . .
}
}

r1:
para:
O médoto processRequest vai recebendo objectos serializados do tipo Request através do socket s até que ocorra uma excepção qualquer;
temos:
criar um objecto inpuToStream
e vamos fazendo read object com cast para Request

para:
Para cada objecto Request recebido, a string devolvida pelo método getMsg() é enviada, através do protocolo UDP (DatagramSocket) e em formato texto (i.e., sequência de caracteres) para o destino com o endereço IP e o porto estipulados;
temos:
pega no Request e no getMsg() e getBytes()
e de seguida construir um dataGramPacket com o inetadress passado o byname o getIpAddress() e getUdpPort() criar o DatagramSocket e enviar
e apanhar as excepções

r2 final:
import java.net.*;
class Exame{
void processRequest(Socket s) throws Exception
{

if(s==null){
//return;
throw new NullPointerException(“socket s passado como null”);
}

DatagramSocket ds =null;//crio e vi sempre usado o mesmo socket
//e foi passado para fora do try para poder criar a excepção
try{
ObjectInputStream oin = new ObjectInputStream(s.getInutStream()); //aqui porque só se abre um ficheiro uma vez e já ta
ds = new DatagramSocket();

//para usar o DatagramPacket
while(true)
{
/* Receive a serialized Request object */
//
Request req = (Request)oin.readObject();

. . .
/* Transmit the specified message to the specified IP
address and UDP port.
The message is transmitted as a sequence of characters (i.e., it is not transmitted as a serialized String object).

*/
//se fosse necessário sair do ciclo
if(req.getMsg().equals(“EXIT”){
return;
}

DatagramPacket pkt = new DatagramPacket(req.getMsg().getBytes(), req.getMsg().getBytes().lenght, InetAddress.getByName(req.getIpAddress()), req.GetUdpPort() );
//ObjectInputStream oin = new ObjectInputStream(s.getInutStream());//sai daqui

//agora o datagramSocket para enviar a mensagem
//DatagramSocket ds = new DatagramSocket(); //sai daqui
//enviar a mensagem
ds.send(pkt);

}
} catch(Exception e){
System.out.println(“Excepcao :”+ e );
//e para lançar a excepção é preciso ainda fazer:
throw e;
}
finally{
try{
s.close(); //este try abafa a IOException que for gerada, apenas aqui
}catch(IOException e){}
if(ds!=null){ds.close();}
}
}
}

//tudo que é feito no finally é feito ao inves de usar
catch(Exception e){
s.close();

}

r3:
e se no socket podermos receber objectos do tipo Request ou do tipo XPTO
import java.net.*;
class Exame{
void processRequest(Socket s) throws Exception
{
. . .
while(true)
{
/* Receive a serialized Request object */
ObjectInputStream oin = new ObjectInputStream(s.getInutStream());
Object obj = oin.readObject();

if(obj instanceof Request){
((Request).oin).getUdpPort();
}else if(obj instanceof XPTO){
((XPTO).oin).getUdpPort();
}

. . .
/* Transmit the specified message to the specified IP
address and UDP port.
The message is transmitted as a sequence of characters (i.e., it is not transmitted as a serialized String object).

*/
. . .
}
}
}

==prática)
3. (RMi) Pretende-se que desenvolva um serviço remoto Java RMI, com um mecanismo de callback, atendendo aos seguintes requisitos:
Nome da classe que representa o serviço: MessageReflector;
Interface remota implementada pelo serviço MessageReflector:
Nome: MRInterface;
Métodos:
boolean registerClient (MRClientInterface cliRef);

Se ainda não existir, acrescenta a referência RMI passada como argumento a uma lista interna e devolve true. Se já existir, ignora o pedido e devolve false.
Notas:
1. Em vez de uma lista, também pode recorrer a um conjunto;
2. Cada cliente implementa um serviço RMI baseado na interface remota MRClientInterface.

boolean unregisterClient (MRClientInterface cliRef);
Se existir, remove a referência RMI passada como argumento da lista interna e devolve true. Caso contrário, devolve false.

void broadcastMessage(String msg);
Comunica a string passada como argumento a todos os clientes registados. Para o efeito, invoca o método void postMessage(String msg) pertencente à interface remota MRClientInterface. Qualquer problema que surja na invocação do método postMessage leva à eliminação da respectiva referência remota (i.e., do cliente) da lista interna.

int getNumRegisteredClients();
Devolve o número de clientes registados (i.e., o número de referências remotas existentes na lista interna).

r:
Class MessageReflector extends unitCastRemoteObject implments MRInterface {
//fazer o construtor vazio
MessageReflector{}
//e os métodos
boolean registerClient(){}

//enivar a todos
com broadcastMessage e ir ao arrayList e chamar

}

r2 final:
notas:
os clientes devem registar.se, isto é , invocar um método do serviço
não é preciso o main do servidor

//a base sem RMi
interface MRClientInterface extends Remote{
void postMessage(String msg) throws RemoteException;
}

public interface MTinterface{

//métodos
boolean registerClient (MRClientInterface cliRef);
boolean unregisterClient (MRClientInterface cliRef);
void broadcastMessage(String msg);
int getNumRegisteredClients();

}

//classe que implementa a interface
class MessageReflector implements MRInterface
{
//lista de referencias remotas para os clientes
List clientList = new ArrayList<>();

@Override
public boolean registerClient (MRClientInterface cliRef){
return false;
}

@Override
boolean unregisterClient (MRClientInterface cliRef){
return false;
}

@Override
void broadcastMessage(String msg){
}

@Override
int getNumRegisteredClients(){
return -1;
}

}

//agora aplicar o RMi
interface MRClientInterface extends Remote{
void postMessage(String msg) throws RemoteException;
}

public interface MTinterface extends Remote{
//métodos
boolean registerClient (MRClientInterface cliRef) throws java.rmi.RemoteException;
boolean unregisterClient (MRClientInterface cliRef)throws RemoteException;
void broadcastMessage(String msg) throws RemoteException;;
int getNumRegisteredClients() throws RemoteException;;
}

//classe que implementa a interface, e agora já é um serviço e surge extends UnicastRemoteObject
//servidor concorrente UnicastRemoteObject
//e cada cliente que se ligue vai ser criada uma thread
class MessageReflector extends UnicastRemoteObject implements MRInterface
{
//lista de referencias remotas para os clientes
List clientList = new ArrayList<>(); //este atributo é mexido por várias threads, vou então serializar

//e falta o construtor
public MessageReflector () throws RemoteException{}
//ou public MessageReflector (Listl) throws RemoteException{}

//e em todos os métodos da interface remota surge throws RemoteException
@Override
public synhcronized boolean registerClient (MRClientInterface cliRef) throws RemoteException{
//se já existe, do tipo equals
if(clientList.contains(cliRef)){
return false;
}
return clientList.add(cliRef);
}

@Override
boolean synhcronized unregisterClient (MRClientInterface cliRef) throws RemoteException{
return clientList.remove(cliRef);
}

@Override
void synhcronized broadcastMessage(String msg) throws RemoteException{
//versão1
for(MRClientInterface cli: clientList){
try{
cli.postMessage(msg);
}catch(RemoteException e){
clientList.remove(cli);
}
}
//versão2 com indices
for(int i = 0 ; i<clientList.size();i++){
try{
clientList.get(i).postMessage(msg);
}catch(RemoteException e){
clientList.remove(i–);
//i–;
}
}
}

@Override
int synhcronized getNumRegisteredClients()throws RemoteException{
return clientList.size();
}

}

//ou synhcronized por bloco
@Override
public boolean registerClient (MRClientInterface cliRef) throws RemoteException{
synhcronized{

}
return false;
}

Tags : , ,

Proposta de trabalho (em Lisboa)

“A Marmalade Game Studio PT tem neste momento 4 vagas abertas:
– Game Producer – LINK
– UX/UI Artist – LINK
– Game Designer – LINK
– QA Game Tester – LINK
Deixo as especificações de cada vaga nos comentários, e se sentirem que são um bom fit, enviem a vossa candidatura diretamente pelo site ou para o email cristiana.serra@marmalademail.com”

Game Producer, The role:
Work closely with project leads to guide projects by overseeing internal resources, observing deadlines, and escalating and resolving issues that might compromise the quality of delivery
Manage releases and submissions
Partner with multi-discipline teams such as design, art, programming, and QA on multiple projects at different stages of development
Create and update schedules and tasks
Keep issue tracking lists up to date
Reviewing bugs for clarity and provide status reports on the state of the bug database
Product testing to monitor progress and state of the project
The Ideal Candidate:
Experience in video game production or in another project management role
Excellent time management skills and ability to multitask and prioritize work
Strong organizational and planning skills
Strives for high quality and pays attention to detail
Excellent written and verbal communication skills
Ability to give and take constructive feedback
Comfortable in a fast-paced environment and can work to deadlines

UX/UI Artist, Responsibilities:
Work in a team to define the look and feel of our user interface
Be responsible for the UI of the game, producing style guides, rule sets, and templates
Create, implement and iterate on UI assets and animations
Provide concept sketching, wire-framing, and high-fidelity UX mockups/prototypes.
Work closely with art, design, production, and developers to iterate on the best solutions to UX and UI challenges
Requirements
Experience as a UX/UI Artist in the games industry or another relevant industry
Strong graphic design skills showcased by a portfolio that meets the quality of Marmalade Games
Ability to explore and create different styles
Experience creating UX prototypes and wireframes
Excellent understanding of typography, composition, color theory, visual design, and interaction design
Basic knowledge of animating assets for conceptual purposes
Ability to respond efficiently to problems and conflicts that may influence game development
Great communication skills
Knowledge of Photoshop, Illustrator, and Unity

Game Designer, The role:
Contribute with ideas for new game concepts, design features, mechanics, and new solutions for existing games
Create game design documentation, game flows, mock-ups, and paper prototypes
Work closely with the Lead Game Designer and fellow designers to iterate and improve your designs
Work closely with the producer to understand the briefs and requirements for the design function within the project
Communicate your designs to a team of artists, designers, and programmers
Analyze and test games from a user-experience point of view, proposing iterations
Basic statistic knowledge to be able to balance ingame values
The Ideal Candidate:
Previous experience as Game Designer working on professional or personal projects
Strong motivation to create games and to develop your Game Designer career
Highly creative, you are able to come up with game concepts, new features, and brilliant solutions for different projects
Good understanding of UX – you have a user-centric approach, always aiming to create the best experiences for the players
Excellent verbal, written, and visual communication skills
You understand and love an entrepreneurial environment – you won’t be a cog in a machine, you will wear many hats and have a clear impact on the products
A passion for board games is a plus
Driven-minded, proactive, able to adapt quickly, and responsible for your own work, owning multiple steps of the process
Experience with Unity is desirable but not mandatory

QA Game Tester, Responsibilities
Work in a team to define the look and feel of our user interface
Be responsible for the UI of the game, producing style guides, rule sets, and templates
Create, implement and iterate on UI assets and animations
Provide concept sketching, wire-framing, and high-fidelity UX mockups/prototypes.
Work closely with art, design, production, and developers to iterate on the best solutions to UX and UI challenges
Requirements
Experience as a UX/UI Artist in the games industry or another relevant industry
Strong graphic design skills showcased by a portfolio that meets the quality of Marmalade Games
Ability to explore and create different styles
Experience creating UX prototypes and wireframes
Excellent understanding of typography, composition, color theory, visual design, and interaction design
Basic knowledge of animating assets for conceptual purposes
Ability to respond efficiently to problems and conflicts that may influence game development
Great communication skills
Knowledge of Photoshop, Illustrator, and Unity

+infos(oficial): https://www.marmaladegamestudio.com/

Tags :

Parte 1 de 37, apontamentos

#sockets Java
na comunicação na internet entre aplicações existem dois protocolos: o UDP e o TCP
o ip identifica a máquina, e o porto ajuda a app a saber que a comunicação é para essa app

UDP – enviamos mensagens (datagramas) e que inclui:
dados da mensagem (conteúdo) e um envelope com ip, porto de destino e IP porto de origem
UDP não faz verificação, são enviadas cartas (como se fosse um envelope)

TCP – temos um fluxo de BYTES, diferente de UDP

existem classes em java importantes para proceder à comunicação:
inetadress, manipula relações com endereços e resolução de nomes
datagram packt, tem atributos e métodos e que vai ser encapsulada num datagramPackt
datagram socket, só o UDP tem isto porque se trabalha com datagrams

o Inetadress:
encapsula endereços IP
não tem construtor
tem métodos estáticos

getByName(IP ou nome)
métodos a aplicar depois:
getHostAddress
getHostName
getAllByName(array)

para saber qual o meu ip:
inetAdress localAdress = InetAddress.getLocalHost();
e uma exceção:
catch(UnknowHostException e){

}

DataGramPacket
encapsula as mensagens individuais
construção de um datagram UDP para envio

Uma mensagem tem um endereço ip, um porto e uma mensagem (conteúdo)

DataGRamPAcket packet = new DataGramPAcket(data, data.length, addr, 2000);
data vem byte [] data = new byte[128]
data.length vem 128
addr vem InetAdress addr = InetAdress.getByName(“192.168.0.1”);
2000 vem o porto

Operação de receção de um DATGRAM PACKET

assim no recetor uso outro construtor

try{
DATAGRAMPACKET packet = new DTAGRAMPACKETS (new byte[256], 206);
DATAGRAMSOKCET socekt = new DATAGRAMSOCKET(2000);
boolean finished = false;
while(!finished){
socket.receive(packet);

}
socket.close();
}catch

#protocolo UDP
a class DATAGRAMPACKET tem vários métodos:
send
receive (bloqueante)
close
setTimeout(0), desbloqueio o TIMEOUT é um no TIMEOUT

o lenght, consoante o contexto de utilização um determinado packet pode significar:
quantidade para enviar
quantidade para receber/aceitação
quantidade que foi recebida

#exemplo como enviar uma mensagem:
DATAGRAmSOCKET socket = new DATAGRAMSOCKET();
DATAGRAMPACKET packet = new DATAGRAMPACKET( new byte[256], 256);
packet.setAddress(INETADDRESS,getByName(someHost));
packet.setPort(2000);
boolean finished = false;
while(!finished){
//-> escrever no buffer do packet
seocket.send(packet);
//-> verificar se existe mais coisas para enviar
}
socket.close();

#protocolo TCP
relembrar que no UDP:
DATGRAM PACKT, que encapsula uma mensagem com endereços (endereço, porto, dados recebidos)
DATAGRAM SOCKET, end point de uma comunicação, onde enviamos e recebemos bytes
ÎNETADRESS, serve para encapsular o endereço ip e os nomes do dns

Protocolo TCP:
não é orientado a mensagens;
serve para comunicação ponto a ponto (entre dois extremos)
abstração do socket (ligação virtual)
o socket está ligado a um endereço remoto (end point), surge o conceito de fluxo de dados
o que vai ser colocado no buffer são bytes e não mensagens (é o mesmo que escrever num ficheiro)
enviar bytes para uma aplicação remote, como se estivesse a escrever num ficheiro

UDP não faz controlo de fluxo, não verifica o numero de sequência, não deteta se existem mensagens perdidas, não pede retransmissão (envio uma carta e esqueço a carta)

TCP, as instâncias de TCP, trocam informações, mensagens de controlo, confirmações, timeouts, para garantir que os bytes são colocados no socket de destino pela mesma ordem e sem haver perda de bytes no meio

#entrada/saída
input stream e output stream, são classes abstratas cujos métodos não estão implementados

vão-se é obter subclasses que vão implementar métodos.

INPUTSTREAM (vou ter um read) e OUTPUTSTREAM (vou ter um write) geram exceções IOException

usar SCOKET ou ArrayBytes ou Ficheiro, vai ser indiferente

pseudocódigo:
a conexão (servidor, recebe a ligação)
xxServerSocket // Socket socket = new Scoket (“www…”, 80);
a transferência
xx Socket

outros exemplos:
socket (host, port );
socket (host, port, bindAddress, localhost)

onde bindAddress, especifica-se a placa (por exemplo um das duas placas do portátil, rede sem fios)

onde localhost, porto do cliente

por exemplo: socket(…, …, InetAddress.getByNumber(“10.10.10.10”), 5001);
a entrada e saída de dados tem que ser feita através desta placa de rede, mas pode acontecer que não queremos restringir placas mas fixar porta 5001, então surge
socket(…, …, InetAddress.getByNumber(“0.0.0.0”), 5001);

exemplo no cliente:
try{
Socket mySocket= new Socket(“www.sol.pt”, 80);
….
}catch(Exception e){
System.err.println(“Err – ” + e);
}

O socket TCP, tem métodos:
getOutPutStream()
getInputStream()
getLocalPort
getPort, acesso ao porto remoto
GetTimeout()

por exemplo no cliente:
try{
Socket socket = new Socket(someHost, somePort);
BufferReader reader = new BufferReader(new InputStreamReader(socket.getInputStream()));
PrintStream pstream = new PrintStream(socket,getOutPutStream());
}catch(IOException e){
System.err.println(“erro – ” + e);
}

em que: socket.getInputStream(), faço o read
em que: socket,getOutPutStream(), faço write bytes

por exemplo, operação de leitura e que não fique bloqueado para sempre:
try{
Socket socket = new Socket(someHost, somePort);
socket.setTIMEOUT(2000); // onde setTIMEOUT(0);//desliga-se o TIMEOUT
BufferReader reader = new BufferReader(new InputStreamReader(socket.getInputStream()));
PrintStream pstream = new PrintStream(socket,getOutPutStream());
}catch(Interrupt IOException e){
timeoutflag = true;
}catch(IOException e){
System.err.println(“erro – ” + e);
System.exit(0);
}

#protocolo TCP
serverSocket(porta) e tem alguns métodos como é o caso do close()

o serverSocket não serve para enviar dados e receber, este só serve para aceitar ligações

#aplicações multicast
endereços de classe D (11110)
representam grupos (ou endereços)
como enviar para um grupo e como receber?
escrever via broadcast (255.255.255.255 6001)
assim todas as aplicações que estão a correr na mesma máquina no domínio de difusão e que tenham um socket associado ao porto 6001 vão receber a mensagem

exemplo:
InetAddress group = InetAddress getByName(“224.1.2.3”);
MulticastSocket socket = new MulticastSocket(port); //port é o porto de escuta
socket.joinGroup(group); //joinGroup(group) para apanhar o que aparece na rede destinada ao 22.4.1.2.3 port
socket.setTimeToLeave(1); // setTimeToLeave, tempo de vida da mensagem, neste caso (1) elimina, e fica a zero e não reencaminha

e para enviar e receber:
DATAGRAM packet = new DATAGRAM (buffer, buffer.lenght, group, port);
socket.send(packect);
//como pertenço ao mesmo grupo, também recebo
byte[] response = new byte[1024];
DATAGRAM packet = new DATAGRAMPACKET(response, response.length);
socket.receive(packet);

Exemplo:
String NICID = “127.0.0.1”,”en0″,…
NETWORKINTERFACE nif;
try{
nif = NETWORKInterface.getByInetAddress.getByName(NICID));
}catch(Exception ex){
nif = NETWORKInterface.getByName(NICID);
}
socket = new MultiCast(port);
socket.joingroup(new InetSocketAddress(group, port), nif);

em que:
joingroup, associo a um grupo
InetSocketAddress, completo IP+porto
nif, qual a interface de rede a associar ao grupo

#serialização de objectos
Esta é a forma mais simples de trocar informação
A informação está encapsulada em objectos
Serialização vs DesSerialização

a Serialização é binária, mas exibe em formato de texto como o JSON

#serialização de objectos, ligações TCP
exemplo:
s = new Socket(serverAddress, serverPort); // estabelecer a ligação
in = new ObjectInputStream(s.getInputStream());
out = new ObjectOutPutStream(s.getOutPutStream()); //enviar
out.writeObject(object to transmit); //escrever no object
//ou out.writeUnShared(object to transmit); //deve ser usado, por exemplo para enviar um arraylist então o usado é o unshared para evitar caching
out.flush();

ou usar writeobject mas fazer antes o out.reset() e ficaria:
out.reset();
out.writeObject(object to trnsmit);

//e do outro lado faz-se a leitura
returnObject = (MyClass)in.readObject();

#serialização de objectos ligações UDP

o UDP não tem fluxo de bytes, datagrams)

exemplo para o envio:
s = new DatagramSocket();
bout = new ByteArrayOutputStream();
out = new ObjectOutputStream(bout);
out.writeObject(Object to transmite);
//ou
out.writeUnshared(object to transmite);
out.flush();
packet = new DatagramPacket(bout.toBytetoarray(), bout.size(), serverAdress, serverPort);
s.send(packet);

exemplo para receber:
packet = new DATAGRAM(new Byte[MAX_SIZE], MAX:SIZE);
s.receive(packet);
n = new ObjectInputStream(new ByteArrayInutStream, packet.getData), 0, packet.getLenght());
returnObject = (MyCalss) in.readObject();

#threads
processo é diferente de thread
todas as threads pertencem ao mesmo processo, as threads são linhas de execução

as threads podem ser iniciadas em dois modos distintos:
modo por omissão, modo normal (modo utilizador) // bloqueante
modo através do daemon(serviço para correr em background) // não bloqueante

Uma aplicação em java termina quando já não existe qualquer, em que já não existem threads em modo utilizador activas.
As thraeds activas em modo de utilizador, mesmo chegando ao fim do main elas continuam activas, se forem as threads em modo daemon, chegada ao fim do main elas terminam

public class RunnableThreadDemo implements java.long.Runnable
{
public void run(){
SystemOut.println(“….”);
}
public static void main (String args[]){
System.Out.println(“…”);
Runnable run = new RunnableThreadDemo();
System.Out.println(“…”);
thread t1 = new Thread(run, “thread 1”); //run, é o nome da thread
System.Out.println(“…”);
thread t2 = new Thread (run, “trhead 2”); //run é o nome da thread
System.Out.println(“…”);
t1.start();
t2.start();
}
}

a diferença entre os dois modo de criar threads pode ser importante
assim o método II é melhor que o método I, já que posso criar várias threads baseadas no mesmo objecto runabble e elas vão partilhar os mesmos membros. posso assim ter várias threads concorrentes mas a trabalhar sobre os mesmos dados.
E outra vantagem é contornar uma das limitações do já de não haver herança múltipla

class ExtendThreadDemo extends java.long.thread // esta classe não pode estender outro tipo de objecto

assim consigo dar a volta a isso fazendo/usando:
class ExtendThreadDemo implements java.long.thread

eu posso implementar vários tipos de classes mas só posso derivar de uma classe

threads, faz-se o new thread mas depois tem que se fazer o start, e  só depois do start o new cria um objecto que representa uma thread, mas o start lança de forma efectiva

#interromper threads

é desaconselhável

thread sleep- > interreupt -> resume
alternativa é a thread que a lançar, fechar a socket, ao fechar é gerada uma exceção na thread e antes de fechar o socket eu coloco um atributo na thread para ela saber que é para terminar

#parar threads usar o stop

fazer uso de uma boolean e “avisar” que vai ter que encerrar

#operações sobre threads

verificar se ainda está viva:
if(t1.isAlive(){ //booleand

}

e nunca usar um while..

#método join

bloqueia, e só regressa depois da thread estar inactiva
t1.join(1000,10000);
em que 1000, é o numero máximo de segundos milésimo de segundos
100000, são nanosegundos

exemplo:
thread die = new WaitForDeath(); //a thread
die.start(); //inica a thread
die.join(); // bloqueia ate a thread terminar

#sincronização de threads

concorrência no acesso a recursos partilhados
solução: serializar o acesso ao recurso partilhado, isto é, enquanto uma thread está a mexer nos recursos, as outras threads que pretendam aceder aos recursos ficam bloqueadas, ou seja, surge então o objecto sincronização

acesso mutuamente exclusivo
assim se surgir outra thread que quer aceder a métodos não podem executar esse ou outro métodos do objecto

a sincronização pode se feita:
método // bloqueia apenas alguns dos métodos
bloco de código

#sincronização ao nível do método// thread safe

public synchronized void mudaData() {…}

public synchronized void changeData() {…}

exemplo:
public class someClass{
public synchonized void ChangeData(){…}
}

O = new someClass();
t1 e t2 têm a referêcnia para O
t1 chama o método changeData
e se t1 chamar o méotodo changeData, fica bloqueada

#sincronização ao nivel do bloco de código

sincronização referente a um bloco
não é necessário os métodos serem synchronized
existe o thread-safe (serializado) sem necessidade de ter acesso ou alterar o código fonte
synchronized (Object O){

}

esta forma dá mais flexibilidade

se for só um classe minha será mais fácil colocar o método sincronized mas se for uma que já existe será o modo bloco

#grupos de threads
é limitado, um conjunto de operações limitado

#comunicação entre threads
no mesmo processo, no mesmo espaço de endereçamento é feito através de pipes de comunicação:
_troca directa de dados entre threads
_comunicação bidirecional
(temos usado um BufferedReader bin = …

#notificação entre threads
surgem os métodos:
Object.wait();
Object.notify();
Object.notifyAll();

#prioridades das threads
abordagem round-robin
prioridades variam entre:
1 mais baixa
10 mais alta

com uso de:
MAX_PRIORITY
NORM_PRIORITY
MIN_PRIORITY

métodos:
t.setPriority(thread.MIN_…)

#servidores TCP concorrentes

while(true){
cliente = socket.accepts();
t = new thread();
t.start();

}

#computação paralela baseada em múltiplas threads
processamento real

#exercicio
resolver um proxy: é uma aplicação que serve de intermediário entre duas aplicações em rede
usando TCP: (guarda log dos acessos)

o proxy para fazer logs do que é trocado

um proxy para servidor é uma ponte. o servidor do mail do isec pop-isec.pt:110

um server socket no porto 8080, e crio uma thread que vai tratar o que se pasa no socket, mas essa thread tem outra socket para comunicar com o servidor de mail do isec (cliente-servidor)
para cada cliente exist uma thread cirada
essa thread tem um socket para comunicar com o cliente
essa thread tem um socket para comunicar com o pop.isec (servidor)

mais ainda não se consegue receber um char e reencaminhar porque existe um sistema de bloqueio de espera de mensagem no socket
usar um timeout não se pode fazer porque é espera activa, assim para cada cliente vai ser necessário duas threads, e as duas threads têm acesso aos mesmos sockects
uma thread tem acesso a ler bloqueada num socket e aquela que recebe envia para outro socket e outra faz o inverso

#arquitectura n-tier
separação lógica e física
a arquitetura 3-tier é mais habitual:
apresentação
lógica (do negócio)
dados (MySQL)

o 3-tier, é parecido com o MVC:
camada de apresentação -> cliente
camada lógica -> SGRDS e servidores
camada de dados -> usar o MySQL

#JDBC
java database connectivity

Connection con = DriverManager.getConnection(BD, username, password);
statment stmt = con.createStatment();
resultset rs = stmt.executeQuery(“select * from table;”);
while(rs.next){
int x = rs.getInt(“a”);
String s = rs.getString(“b”);
float x = rs.getFloat(“c”);
}

porque é que temos que usar drivers diferentes para bases de dados diferentes? se tiver que usar SQL, porque é que tenho que usar um driver diferente se tiver que usar ORACLE?
porque o protocolo de comunicação é diferente

#inovação remota de métodos
o middleware, sistema que vai abstrair o programador dos aspectos de baixo nivel, nomeadamente de:
troca de mensagens/comunicação
protocolo de comunicação
sistemas operativos
hardware

exemplos de middleware:
RMi
RPC
CORBA
NetRemoting

um proxy que tem os métodos, e eu localmente tenho um objecto que tem os mesmos métodos
RPC é o inicio da história para o paradigma dos sistemas distribuídos (miiddleware)

os passo do RPC
passo1: o servidor fica a correr e vai-se registar na porta 111
passo2: o cliente solicita o porto do servidor
passo3: recebe a porta
passo4: faz o pedido
passo5: recebe a resposta

#introdução ao java RMi
agora ao invés de se chamar funções, vou chamar métodos usando objetos remotos

o input ao sistema é uma interface (conjunto de protótipos de métodos)

#arquitectura java RMi
existem servidores, clientes, RMI registry

os passos do RMi:
1_ o servidor regista no Rmi registry
2_ o RMiregistry providencia referências ao cliente

o que é que um serviço e um proxy têm em comum?
a interface, os métodos que implementam

o Sturb (ou proxy) é do lado do cliente e actua como um proxy. Implementa neste a interface remota, é invocado pelo cliente, envia mensagem ao serviço.
o Skeleton é do lado do servdor, aguarda pedidos na aplicação servidora, invoca o método pretendido, devolve o resultado ao Sturb.

A comunicação é feita via serialização e por isso todos os argumentos que se passam em funções e resultados têm que ser serializados

porque razão é que o java RMi nas interfaces remotas tem que ter os argumentos e os resultados serializados?
porque o sistema, invocamos o método remoto e o que acontece é que é enviado um objecto que representa um pedido para o servidor, e o RMi faz a serialização dos objetos logo o pedido vai ter a identificação do método, etc, e assim tem que ser tudo serializado

#Arquitectura RMi
permite chamar os métodos de um serviço que não está na minha máquina, sendo que existem três componentes principais e que são: servidor RMi, cliente RMi, RMi registry

o servidor RMi: usa TCP, com um server socket à escuta num porto, é concorrente (sempre que existe um pedido de ligação cria uma thread, essa thread recebe pedidos, vê qual o objecto e qual o método para executar, e executa e devolve o resultado na origem.) No servidor só temos que especificar o que o método faz

o cliente RMi: aplicação que tem referências para objectos remotos. O cliente quando contacta o RMi registry recebe o Sturb. E no Sturb tem dois membros obrigatórios: o ip da maquina e o porto de escuta

o RMi registry: é o serviço que está à escuta num porto automático TCP, sendo que os clientes contactam o RMi Registry TCP

#Passos principais
1) definir a interface remota: métodos, com argumentos e valor de retorno (Sendo que tudo o que é valor de retorno tem que ser serializavel)
2) implementar o serviço: ter classes que implementam a interface
3) é preciso um servidor (uma aplicação que cria objecto, vai registar no RMi registry)
4) os clientes (é uma aplicação que tem que invocar o método no serviço XPTO, assim em vez desta aplicação fazer um NEW, vai obter uma referência remota, contact o servidor, e se o serviço existir eu obtenho o sturb/proxy (referencia remota))
5) lançar o RMi registry (1099, TCP)
6) lançar o servidor
7) correr os clientes

#interfaces remotas
por exemplo controlar uma lâmpada remotamente

surge então uma aplicação em java, em que no main faz-se um NEW controlador (que poderia ter alguns parametros) e nesta app apenas surge a opção do menu de ligar e desligar.
ainda no main do servidor, teria que criar um server socket que vai fazer accepts, se quiser qe seja concorrente lanço threads
então e na comunicação posso usar mensagens curtas, booleans, ou objectos serializados com mais campos

do lado do cliente existe um socket que constroi os pedidos
usando o RMi vamos abstrairnos desta situação, com o RMi vai ser mais simples pois não se pensa em mensagens, mas sim nos servidores, e quais os métodos que temos nos servidores e as apps clientes vão invocar métodos do utilizador (gets, sets, ..) (por baixo existe o TCP, serialização, mas não somos nós a tratar disso)

No RMi temos que obrigatóriamente usar em todos os métodos o throws java.rmi.remoteException
public void on() throws java.rmi.remote.exception

e as interfaces remotas têm que ser:
public interface Classe extends java.rmi.remote {
public void ont() throws java.rmi.remote.exception

muito importante:
throws java.rmi.remote.exception
e
public interface Classe extends java.rmi.remote

assim:
1) no servidor existem métodos
2) os clientes vão invocar os métodos no utilizador (gets, sets…)

no servidor java RMi, vai pensar no que quero que seja invocado remotamente

no servidor, exemplo:
public interface RMiLight extends java.rmi.remote{
public void on() throws java.rmi.remoteException;
public void off() throws java.rmi.remoteException;
public void isOn() throws java.rmi.remoteException;
}

os métodos podem lançar para fora excepções que eu entender, em que, e é muito importante:
todos os métodos têm que lançar a expeção java.rmi.exception
as interfaces remotas extends java.rmi.remote

implementar o serviço, exemplo:

public class RMiLight extends java.rmi.unicastRemoteObject implements RMiLight{
public RMiLight()throws java.rmi.remote.exception{

}
public void on()throws java.rmi.remoteException {

}
}

em que:
public class RMiLight extends java.rmi.unicastRemoteObject implements RMiLight é um servidor base que não executa nada TCP
public RMiLight()throws java.rmi.remote.exception é um construtor obrigatorio. os construtores não aparecem na interface remota, mas os serviços remoto precisam de construtor que lançam excepções remotas (nem que seja vazio)

nos serviços tenho:
os métodos que pretendo que sejam invocados remotamente

só os métodos que fazem parte da interface remota é que precisam do RemoteException?
assim os outros métodos do serviço que não fazem parte da interface remota já não vão dar

assim ao criar uma instância da classe RMiLightBullImp no servidor vem que, exemplo do servidor:
public class void main(){
try{
//lançar uma thread em ciclo que cria +1 thread para cada cliente em paralelo que espera pedido de ligação
RMi bs = new RMiLightImp();
RemoteRef location = bs.getRef(); //não é necessário
string registry = “localhost”; //ip do registry e nó do serviço
if(args.lenght >1) { registry = args[0]; }
string registration = “rmi//” + registry + “/RMiLightBulb”; //registo do serviço
naming.rebind(registration, bs); //RMi e serviço
}catch(Remote Exception e){
}
}

apesar de chegar ao fim do main, ainda existe uma thread no modo de utilizador, e as aplicações em java só terminam se não existir mais threads de modo utilizador a decorrer

as aplicações agora só precisam de saber qual o IP onde está e qual o porto do servidor

naming.rebind(registration, bs);
em que:
se estabelece uma ligação TCP
no porto 1099 (porto de escuta do RMi registry)
manda-lhe uma margem para registar como o nome RMi Light bulb a referencia ao objecto Bs

rmi://192.10.10.10/xpb
o que faz quando se faz naming rebind

isto não estabelece uma ligação com um serviço
naming.lookup(rmi://192.10.10.10/xpb);

o naming.lookup no cliente para ele obter a referência para um serviço com este nome

quando se faz o lookup o que é feito é uma ligação TCP com qualquer coisa no IP no porto 1099 que é do registry e quero obter uma referência para um objecto com o nome xpb, esta referência tem interface e tem IP e porto

qual a diferença entre o método Bind e Rebind? (Bind e Rebind, tem a ver com tabelas no registry)
Com o rebind se existir é substituído senão existir cria
com o bind se não existir cria e se já existir cria uma excepção

no cliente o que é que faz o ON em bullbService.on(); sabendo que existiu
SErviceRmi bullBservice = (serviçoRmi) remoteSErvice

o cliente não faz um NEW local do objecto o que ele faz é um naming.lookup
no cliente depois vou ter um objecto que implementa a interface do serviço (on, off, …)
into é em sturb, e vai ser enviado ao fazer on, envia serializado a operação que tem que ser executada e que é o on, e o serviço recebe o pedido, executa e devolve o resutlado

qual é o aspecto comum entre proxy/sturb e o serviço?
é a interface, tem um conjunto de métodos coincidentes isto é, no serviço existe um on() e no sturb também existe um on() que na realidade envia uma mensagem para o outro lado para ligar

#cliente RMi

naming.lookup(registry);
isto faz uma ligação TCP com o RMi registry. faz um pedido do RMi registry e recebe um array de strings com o nome dos serviços registados
registry é o ip da maquina

relembrar que no RMi registry podemos solicitar:
lookup, pedir uma referÊncia para o objecto
bind/rebind, regista um serviço

#funcionalidades adicionais
para alunar uma referência que está na tabela
naming.unbind(“rmi://192.0.0.1/RMiLightBuld”)

para terminar no servidor e no main:
unexportObject(bulbSErvice, true);
em que bulbSErvice é o serviço

No servidor pode ser criado algo do tipo, prima qualquer tecla para terminar o serviço e com a inclusão do endpoint Object termina a thread em modo de utilizador
e só termina depois dos clientes serem atendidos, não é de forma abrupa, nas se for false termina logo tudo

o que significa?
endPoint(10.20,4,128.77:53561);
10.20,4,128.77 é o IP do serviço
53561 é o porto automático, criado pelos server socket
quando o cliente faz o lookup do registry obtêm uma referencia remota, o que se indica no lookup é o ip do registry e o porto (do registry) mas aqui é isto que eu obtenho

#funcionalidades adicionais
no servidor vou lançar o registry da maquina:
createRegistry
getRegistry

#invocação remota dos métodos
desenvolver aplicações remotas sem ter que se preocupar com sockets, sem usar o paradigma de troca de mensagens, sem usar TCP/UDP directamente
no cliente temos um Sturb (proxy), uma referência para o objecto remoto
no servidor existe o Skeleton, um servidor TPC, concorrente que recebe os pedisos, serializados, serialização binária do java.rmi, identifica qual o método que é para invocar, e argumentos, invoca e envia o resultado, e o método no cliente regressa e não é proxy

o que é que é comum entre o serviço (servidor) e a referência remota (Sturb, no cliente)?
é a interface implementada
o proxy não faz aquilo que é suposto o método fazerem, o que ele faz é pegar nos argumentos e envia para o servidor (Skeletton) que no servidor vai ser executado, que depois serializa e envia a resposta e o Sturb devolve a resposta ao cliente

quando o serviço é lançado (no servidor) ele regista-se no RMi registry (que é tipo um DNS) onde fica registado o IP e o porto onde pode ser encontrado o serviço

o cliente contacta o RMi registry à procura do serviço

o que acontece inernamente (por baixo) no cliente RMi quando ele faz so dos métodos, por exemplo em:
bulbSErvice.isOn()
é feito um pedido de envio
aguarda resposta
o pedido é serialziado
e é devolvida a resposta

situação de dois clientes acederem ao mesmo objecto ao mesmo tempo?
o cliente através do lookup contacta o registry (TCP, 1099) e envia o pedido para o que quer
o cliente depois recebe a referência remota do objecto, que tem a interface pretendida (métodos…) e também tem o ip e porto do serviço (serviço APi)
no servidor depois de contactado cria uma thread que vai cuidar desse cliente
e se existir outro cliente vai também ser o mesmo procedimento, e no serviço (servidor) é criada outra thread
assim eu tenho que verificar se é critico os acessos concorrentes, dois clientes têm acesso a um determinado serviço, estão a aceder ao mesmos erviço e mesmos recursos, então eu terei que colocar nas classes concretas/serviços o sincronized
por exemplo:
private boolean lightOn() sincronized;
pois pode ser alterada pelos vários clientes logo estes métodos têm que ser sincronized

#callBacks Rmi
callback são notoificações assincronas (o observador observável), por exemplo:

as vistas são actualizadas quando existem alterações no modelo, esta operação é o callback

quando existe um alteração no modle é notificada (avisada) a vista, por exemplo:

o cliente tem a referêcnai remota do serviço
o cliente quer saber sempre quando existe uma alteração em um membro do serviço
o cliente é um observador e o serviço um observavel
ambos estão na mesma maquina virtual
o servidor vai ter uma lista, coleção de referecnias para aplicações (observador/clientes) que esão interessados em ser notificados, é uma lista de sockets
do lado do cliente existe uma thread que está sempre à escuta, que recebe a mensagem e atualiza a vista

mas agora usamos objectos remotos, a lista no servidor vai ter coisas que implementam interfaces remotas nos clientes
os clientes passam a ter uma interface remota que vai ser usada pelo servidor
é muito importante perceber: os clientes implementam uma interface remota

o cliente vai logo terminar?
no main do cliente encontra-se:
tenho uma referencia
obtive a temperatura
crio o serviço (NEW…)
registo o sensor (temperature change…)
mas a aplicação do cliente não termina porque foi criado um objecto do tipo unicast object, que tem uma thread que está à escuta no server socket e que é um serviço

#protocolo HTPP em java
no HTTP temos um pedido (get) e uma resposta, através de uma ligação TCP
na resposta surge sempre um código de 3 digitos, e um cabeçalho e um corpo (opcional)

#URi
URi ou URL,
o URi, é um identificador
o URL, é um locator
ambos querem dizer a mesma coisa, servem para identificar recursos

o que é que isto identifica?
RMi://services.isec.pt/servicosacademicos

RMi registry, que é uma base de dados com uma tabela que tem nome e caminho remoto (dos sturbs)
em que servicosacademicos é nome do serviço

na tabela surgem referências remotas, do tipo javaRMi remote

com o método lookup, obtenho o valor correspondente aos servicosacademicos
com o método nbing, serve para apagar
com o método bing ou rebind, serve para acrescentar (bind) ou para substituir (rebind)

#campos cabeçalho
expansivel – campos prédifinidos
pedido – usando o método get, recurso, protocolo, mudança de linha
get / widget / xpto / 3 / http/1.1 \n\n
repsosta – http/1.1 200 ok
em que 200 é o código

se for feito um post serve para actualziar recursos nos ervidor, ou submeter autenticação

#java.net.url
o que faz o openStramÎnputStream in = myURL.openStream();
faz uma ligação TCP no porto adequado no URL, envia para lá um get com o ficheiro não identificado por omissão

#URL connection
prmite aceder aos códigos de estado das mensagens de resposta

#alguns métodos de autenticação HTTP
fazer um pedido HTTP, reebo uma resposta por parte do servidor
básico: em cada pedido tenho o login e password que vai no cabeçalho, e no cabeçalho vem
Authorization: basic usernamepassword
codificado em base 64, e é apenas uma forma de codificar

#token
o token depois de ser feita a autenticação é dado ao utilziador um token que só lhe pertence e esse token é unico, só do individuo
este é o token que permite ao utilziador fazer as suas operações depois do login

//—– perguntas de exame:
==1)
aparece este bocado de código:
PrintStream pout = new PrintStream(out);
pout.printl(new Java.util.date());
pout.flush();
1) o que faz este código?
o new java.util.date() é escrito no pout
2) concorda com a seguinte afirmação:
“este pedaço de código escreve no ecrã a hora atual seguida de uma mudança de linha”
Não, não é totalmente coreto, pode ser mas também pode não ser, porque o printStream está a receber um objeto do tipo outputStream e o outputstream não é só System.out, não é só fileOutPutStream, ele pode estar a escrever isto para um ficheiro, ou para o ecrã pode ser para um socket TCP, como ode ser um byteArray outpuStream (temos aqui uma questão de polimorfismo)

==2)
multicast(subclasse de DATAGRAMSOCKET)

em que:
multicast: quando queremos também receber as mensagens que são enviadas para o grupo
DATAGRAMSOCKET: se eu só pretendo enviar para um grupo de multicast é o envio de um DATAGRAMSOCKET UDP clássico, enviar para um determinado IP/porto

não existe nenhum servidor de gestão de grupos

==3)
as threads podem ser iniciadas em dois modos distintos:
modo por omissão, modo normal (modo utilizador) // bloqueante
modo através do daemon(serviço para correr em background) // não bloqueante

Uma aplicação em java termina quando já não existe qualquer, em que já não existem threads em modo utilizador activas.
As thraeds activas em modo de utilizador, mesmo chegando ao fim do main elas continuam activas, se forem as threads em modo daemon, chegada ao fim do main elas terminam

public class RunnableThreadDemo implements java.long.Runnable
{
public void run(){
SystemOut.println(“….”);
}
public static void main (String args[]){
System.Out.println(“…”);
Runnable run = new RunnableThreadDemo();
System.Out.println(“…”);
thread t1 = new Thread(run, “thread 1”); //run, é o nome da thread
System.Out.println(“…”);
thread t2 = new Thread (run, “trhead 2”); //run é o nome da thread
System.Out.println(“…”);
t1.start();
t2.start();
}
}

a diferença entre os dois modo de criar threads pode ser importante
assim o método II é melhor que o método I, já que posso criar várias threads baseadas no mesmo objecto runabble e elas vão partilhar os mesmos membros. posso assim ter várias threads concorrentes mas a trabalhar sobre os mesmos dados.
E outra vantagem é contornar uma das limitações do já de não haver herança múltipla

class ExtendThreadDemo extends java.long.thread // esta classe não pode estender outro tipo de objecto

==4)
threads, faz-se o new thread mas depois tem que se fazer o start,e  só depois do start o new cria um objecto que respresenta uma thread, mas o start lança de forma efectiva

==5)
complete o código, em que temos:
for(i = 0; i< nThreads; i++){
threads[i] = new ParallelPi(i+1, nThreads, nIntervals);
threads[i].start();
}

se eu estou a criar a minha thread com new ParallelPi, quer dizer que ParallelPi extends thread, se fosse implements runnable eu teria que ter um new Thread e em argumento um new ParallelPi
se existe um new ParallelPi e depois faço um start então é porque é extends thread e não implements Runnable

==6)
porque é que temos que usar drivers diferentes para bases de dados diferentes? se tiver que usar SQL, porque é que tenho que usar um driver diferente se tiver que usar ORACLE?
porque o protocolo de comunicação é diferente

==7)
um proxy que tem os métodos, e eu localmente tenho um objecto que tem os mesmos métodos
RPC é o inicio da história para o paradigma dos sistemas distribuídos (miiddleware)

os passo do RPC
passo1: o servidor fica a correr e vai-se registar na porta 111
passo2: o cliente solicita o porto do servidor
passo3: recebe a porta
passo4: faz o pedido
passo5: recebe a resposta

==8)
o que é que um serviço e um proxy têm em comum?
a interface, os métodos que implementam

==9)
porque razão é que o java RMi nas interfaces remotas tem que ter os argumentos e os resultados serializados?
porque o sistema, invocamos o método remoto e o que acontece é que é enviado um objecto que representa um pedido para o servidor, e o RMi faz a serialização dos objetos logo o pedido vai ter a identificação do método, etc, e assim tem que ser tudo serializado

==10)
só os métodos que fazem parte da interface remota é que precisam do RemoteException?
assim os outros métodos do serviço que não fazem parte da interface remota já não vão dar

==11)
naming.rebind(registration, bs);
em que:
se estabelece uma ligação TCP
no porto 1099 (porto de escuta do RMi registry)
manda-lhe uma margem para registar como o nome RMi Light bulb a referencia ao objecto Bs

==12)
rmi://192.10.10.10/xpb
o que faz quando se faz naming rebind

isto não estabelece uma ligação com um serviço
naming.lookup(rmi://192.10.10.10/xpb);

o naming.lookup no cliente para ele obter a referência para um serviço com este nome

quando se faz o lookup o que é feito é uma ligação TCP com qualquer coisa no IP no porto 1099 que é do registry e quero obter uma referência para um objecto com o nome xpb, esta referência tem interface e tem IP e porto

==13)
qual a diferença entre o método Bind e Rebind? (Bind e Rebind, tem a ver com tabelas no registry)
Com o rebind se existir é substituído senão existir ria
com o bind se não existir cria e se já existir cria uma excepção

==14)
no cliente o que é que faz o ON em bullbService.on(); sabendo que existiu
SErviceRmi bullBservice = (serviçoRmi) remoteSErvice

o cliente não faz um NEW local do objecto o que ele faz é um naming.lookup
no cliente depois vou ter um objecto que implementa a interface do serviço (on, off, …)
into é em sturb, e vai ser enviado ao fazer on, envia serializado a operação que tem que ser executada e que é o on, e o serviço recebe o pedido, executa e devolve o resutlado

==15)
qual é o aspecto comum entre proxy/sturb e o serviço?
é a interface, tem um conjunto de métodos coincidentes isto é, no serviço existe um on() e no sturb também existe um on() que na realidade envia uma mensagem para o outro lado para ligar

==16)
o que significa?
endPoint(10.20,4,128.77:53561);
10.20,4,128.77 é o IP do serviço
53561 é o porto automático, criado pelos server socket
quando o cliente faz o lookup do registry obtêm uma eferencia remota, o que se indica no lookup é o ip do registry e o porto (do registry) mas aqui é isto que eu obtenho

==17)
o que é que é comum entre o serviço (servidor) e a referência remota (Sturb, no cliente)?
é a interface implementada
o proxy não faz aquilo que é suposto o método fazerem, o que ele faz é pegar nos argumentos e envia para o servidor (Skeletton) que no servidor vai ser executado, que depois serializa e envia a resposta e o Sturb devolve a resposta ao cliente

quando o serviço é lançado (no servidor) ele regista-se no RMi registry (que é tipo um DNS) onde fica registado o IP e o porto onde pode ser encontrado o serviço

==18)
o que acontece inernamente (por baixo) no cliente RMi quando ele faz so dos métodos, por exemplo em:
bulbSErvice.isOn()
é feito um pedido de envio
aguarda resposta
o pedido é serialziado
e é devolvida a resposta

==19)
situação de dois clientes acederem ao mesmo objecto ao mesmo tempo?
o cliente através do lookup contacta o registry (TCP, 1099) e envia o pedido para o que quer
o cliente depois recebe a referência remota do objecto, que tem a interface pretendida (métodos…) e também tem o ip e porto do serviço (serviço APi)
no servidor depois de contactado cria uma thread que vai cuidar desse cliente
e se existir outro cliente vai também ser o mesmo procedimento, e no serviço (servidor) é criada outra thread
assim eu tenho que verificar se é critico os acessos concorrentes, dois clientes têm acesso a um determinado serviço, estão a aceder ao mesmos erviço e mesmos recursos, então eu terei que colocar nas classes concretas/serviços o sincronized
por exemplo:
private boolean lightOn() sincronized;
pois pode ser alterada pelos vários clientes logo estes métodos têm que ser sincronized

==20)
callbacks RMi
o cliente vai logo terminar?
no main do cliente encontra-se:
tenho uma referencia
obtive a temperatura
crio o serviço (NEW…)
registo o sensor (temperature change…)
mas a aplicação do cliente não termina porque foi criado um objecto do tipo unicast object, que tem uma thread que está à escuta no server socket e que é um serviço

==21)
o que é que isto identifica?
RMi://services.isec.pt/servicosacademicos

RMi registry, que é uma base de dados com uma tabela que tem nome e caminho remoto (dos sturbs)
em que servicosacademicos é nome do serviço

na tabela surgem referências remotas, do tipo javaRMi remote

com o método lookup, obtenho o valor correspondente aos servicosacademicos
com o método nbing, serve para apagar
com o método bing ou rebind, serve para acrescentar (bind) ou para substituir (rebind)

==22)
o que faz o openStramÎnputStream in = myURL.openStream();
faz uma ligação TCP no porto adequado no URL, envia para lá um get com o ficheiro não identificado por omissão

Tags : , ,

Proposta de trabalho (em Lisboa)

“SENIOR GAME DESIGNER
Miniclip is looking for a Senior Game Designer to hire in our Lisbon (Portugal) Games Development Studio. This is a full-time position.
This is a fantastic opportunity to develop your free-to-play design career in mobile help bring new titles to market, and work on highly successful live games at a leading mobile studio that’s just 10 minutes from the beach!

Your Primary Responsibilities Will Include
Work with the team to design and craft gameplay experiences and game features that deliver strong player engagement, virality, retention, and monetisation.
Work with the team to create and craft game content to delight players, and devise & balance meta-game economies to maximise game performance.
Write, review and give feedback on game/feature design documents, builds, and game roadmap plans.
Participate as a key member of the product team across the product life-cycle, working on new titles, games in production, and live titles, proposing high-impact updates to our existing portfolio of games.
Help identify and deconstruct new markets and opportunities, expanding the portfolio of the company and staying in the cutting edge of the mobile gaming industry.
Collaborate with other designers to improve overall output, and support the team in growing & developing their design capabilities.
Assist with reviewing, scheduling & prioritising design team workload.
Skills & Experience

We are looking for a social, hard-working person who enjoys working in a team, and is passionate about games, and mobile free-to-play. The ideal candidate will be articulate, proactive & energetic, with the following attributes
Significant experience designing successful free-to-play published titles, preferably on mobile.
Experience across the product life cycle, from prototyping, through production, to updating a live free-to-play game.
Strong knowledge of the mobile & social game space, with exceptional understanding of current design techniques to deliver excellent engagement, retention, and monetisation.
Highly numerate, with experience designing virtual currencies and managing in-game economies.
Experience with reviewing game analytics, designing AB tests, and producing insights based on data to make better informed design decisions.
Strong grasp of mobile user-experience design, and ability to consider & empathise with many different types of players.
Mature judgment, able to balance between innovation and setting reasonable goals.
Collaborative & effective communicator, with an ability to work with multinational teams, with a variety of cultural backgrounds.
A hard worker, with drive, initiative, and ability to self-manage effectively.
Highly organised, with a track-record of guiding & advising others (some management experience is ideal).
Ability to compromise and prioritise appropriately to deliver to tight deadlines.
Additional Information

You will be working in our fashionable, open plan studio in Lisbon with enthusiasts and professionals from the games industry. We like to maintain a very friendly and relaxed atmosphere, with regular team building and social events. We understand that being tied to a desk all day is not fun and that’s why there is a games area and fridge with complimentary drinks and fruit for all staff.

+infos(rede social): LINK

Tags :

Tileset generator

Encontrei mais uma aplicação para a construção de tiles para videojogos!

+infos(oficial): https://yusastudios.itch.io/tileset-generator

Tags : ,

Pixelorama

Encontrei esta ferramenta que permite desenhar no formato de “pixels”. É uma ferramenta de uso gratuito e que foi desenvolvida com a ajuda do software Godot.

Ainda não testei, mas parece ser uma ferramenta bastante simples de se usar, mas com todas as funcionalidades para quem pretende usar a estratégia de “pixéis” para gerar o grafismo/sprites 2D para um videojogo.

+infos(oficial): https://orama-interactive.itch.io/pixelorama

Tags : ,

naavik, análises aos negócios dos videojogos

Encontrei esta referência à naavik que se destina à análise do mercado dos videojogos. Tem como base “A research, consulting, and advisory firm Enabling you to master the business of gaming” e que partilha com a comunidade algumas informações de forma gratuita e que são interessantes.

noticias – LINK
investigação/análises – LINK
entrevistas – LINK
podcast – LINK

+infos(oficial): https://naavik.co/

Tags : , ,

Dia do programador..

Dia 13 de setembro é o dia do programador.. não sou programador mas gosto de escrever linhas de código em:
C
C++
Java
html/css/javascript (eu sei que isto não são consideradas linguagens de programação, mas faço uso delas de forma regular)

Tags :

Game Dev Camp 2021

O Game Dev Camp está de volta a Portugal. Desta vez apenas no formato digital vai ser possivel aceder e participar num conjunto de palestras relacionadas com o desenvolvimento de Video Jogos. Para já é possivel ir consultando os convidados e comprar o bilhete de acesso.

+infos(social): https://www.facebook.com/gamedevcamp/

+infos(bilhete): LINK

Tags :

game development team, um portal

Este portal é uma espécie de portal de procura de trabalho mas com a possibilidade de se procurar um grupo que queira/esteja a desenvolver e em conjunto um determinado tipo de projeto! :)
Interessante a ideia já que permite juntar pessoas por opções de tipologias de projetos

+infos(game dev): https://www.develteam.com/Browse/Games

Tags :

Proposta de trabalho (em Coimbra)

Encontrei esta proposta de trabalho:
“Gostavas de trabalhar na criação de Efeitos Visuais para Jogos? Ou como developer/programador? Há vagas para um VFX Artist Junior e um Unity Developer (programador) na Golden Bug.
Esta é a tua hipótese de aprenderes efeitos visuais para jogos e trabalhares na área de Game Development em Coimbra, Portugal.

+infos(oficial): LINK

+infos(estudio): https://www.gabrielaguiarprod.com/

Tags :

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

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 : , , , ,

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

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 : , , , ,

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

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

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

POO, introdução

A programação é orientada não pela decomposição de tarefas mas pela identificação das entidades que constituem o problema e como são modelizadas e manipuladas

os mecanismos:
Encapsulamento;
Herança;

Encapsulamento:
integridade da informação numa única estrutura a informação, e as funções que trabalham essa informação
acesso à informação é muito controlada

Herança:
coisas em comuns entre conceitos
(funcionários, funcionário administrativo, gestor, …)
sub-classes, surgem as estruturas que derivadas ou herdar do “pai”

Polimorfismo:
poli, várias, morfismos, formas
a mesma instrução pode ser usada em diferentes ações com significado análogo

as Classes, têm:
Estruturas
Classes
Construtores
Destrutor
Funções membros inline
Membros variáveis estáticos
Funções membros estáticas
Funções membros constantes
Funções friend
Construtores – lista de inicialização
Construtores – membros constantes não estáticos
Construtores – membro referência
Membros variáveis inicializados na declaração ( C++11)
Construtores que chamam construtores ( C++11)
Membros default e delete ( C++11)

passagens por referencia vs passagem por valor

nas classes deve haver relações explicitas entre a estrutura e as funções surgem as funções membros
. é a notação para aceder aos membros das classes

os membros podem ser:
privados (por defeito se fosse uma struct era ao contrário), em privado, as variáveis públicas, as funções membro por norma (funções: set, imprimir..)

funções:
get, servem para obter valores, para comparar (retornam copias dos valores)
criamos as funções/métodos usando :: (por exemplo: Estrutura::get..)
:: são funções que pertencem à classe, não são globais

funções inline:
o código é expandido no local da chamada
funções pequenas
chamadas muitas vezes
p.e. detetar se um numero é par
declara-se a função com a expressão inline
inline int par(int numero){

}

funções overloaded:
têm o mesmo nome no mesmo contexto
distinguem-se pelo número de argumentos
p.e.
data(“11/11/11”);
data(11,11,11);
void data (char * s)
void data(int n1, int n2, int n3)

função destrutor:
funciona automaticamente, quando um objeto é destruído ou perde a validade;
podemos precisar numa classe;
usada quando o objeto é destruído e precisamos de executar uma ação de seguida;
libertar por exemplo um espaço de memória dinâmica
o destrutor não tem parâmetros como o construtores
Os objetos locais não estáticos são destruídos quando a execução do programa sai do bloco onde foram declarados.
Os objetos globais são destruídos quando o programa termina.
Os objetos dinâmicos são destruídos com o operador delete.
e os objetos são destruídos por ordem inversa da construção

funções com argumentos por omissão:
A lista de parâmetros com os valores por omissão deve estar apenas na declaração da função cuidado com os erros de ambiguidade (onde existe mais do que uma hipótese)

membros e funções membros estáticos:
têm que ser criados fora dos construtores
são partilhados por todos os objetos da classe
existe apenas uma única versão
está sempre fora dos objetos
p.e.
um predio e um elevador
o prédio tem andares que são objectos
o elevador é o membro estático, que todos usam
e quem usar o elevador pode deixar lá um aviso/atualização
(é uma especie de global na classe)
também existem funções estáticas
a chamada de uma função estática deve ser sempre com ::, mesmo se o objeto existir

funções
no fim, não altera os membros dos objetos

Funções membros constantes, const :
não podem alterar os membros variáveis do objecto
são funções de consulta
poem-se na declaração e na implementação
se um objecto é const, então todas as funções têm que ser const, mesmo que essa função não altere nada
Apenas uma função membro declarada como constante pode ser invocada por objectos constantes.
p.e.:
const int * p;
ou
int const * p;
const antes do *, o ponteiro é um ponteiro que só serve para consultar o apontado, não altera o apontado, mas pode ser apontando para outro local em memória
const depois do *, o ponteiro é constante, tem um endereço e não pode ter outro, não pode apontar para outro sitio
int * const p = &i;
ponteiro constante para constante, const antes e depois do *
const int * const p = &i;
ou
int const * const p = &i;
aponta para uma localização de memória e não se pode alterar essa localização de memória
e também não pode alterar o apontado

parâmetros do tipo ponteiro para constante:
apenas se passa o endereço
garantia de não se alterar a variável
p.e.:
void g(const Elemento * p) //eficiência e segurança
int main(){
Elemento val;
g(&val);
}
ou
void f(const Elemento & arg) //referencia por constante: eficiência e segurança – c++

Funções friend
é uma função que, não sendo membro da classe, tem acesso aos seus membros privados
cuidado que isto é uma quebra do encapsulamento e da integridade dos dados
só deve ser usada com uma justificação forte!

vectores:
notação:
vector v1 = {…};
ou
vector v1(..);
limpar vectores:
v1.clear()
percorrer vectores:
for (const string &c : canais0) {canais.push_back(c);}
ou usando interadores
for(auto it = canais0.begin; it!= canais0.end(); ++it){
canais.push_back(*it);
}
o iterador trata-se como se fosse um ponteiro

initializer_list:
é uma coleção de vectores constantes de um tipo especificado
p.e.
class Televisao{
public:
Televisao(initializer_list<string>canais0);
void setCanais(initializer_list<string>canais0);
}
para criar um objecto do tipo Televisao:
Televisao tv ={“um”, “dois”}; //tv é um objecto Televisao
Usar initializer_list como argumento:
tv.setCanais({“um”, “dois”});
Criar um objeto anónimo
tv = {“um”, “dois”};

inicialização de vectores com construtores:
class Televisao{
vector canais;
public:
Televisao(string canais0[], int n);
}
em que p.e.:
string canais[] = {“um”, “dois”};
Televisao tv = {canais, 2};
ou
Televisao tv {canais, 2};

dedução de tipo: auto
o compilador determina automaticamente o tipo de uma variável
p.e.:
vector::const_rever_interator pesquisa();
p.e.:
int tabela[10];
for(auto & elemento : tabela)
instrução
o uso da referência &, podemos alterar os elementos da coleção (mais eficiente, não faz cópias)
o não uso da referência &, é uma copia do coleção
ou em alternativa para obter eficiência e segurança
for(const auto & elemento : tabela) //não alteramos nada

o nulltpr, é uma constante que representa um ponteiro nulo
0 e NULL são do tipo int em funções overloaded

as referências:
é um outro nome para uma variável, é como que um ponteiro constante que automaticamente conduz ao objeto apontado
p.e.:
void f(int &n);

int main(){
int i =0;
f(i);
cout << x << endl; //100
}

void f(int &n){
n=100;
}

uma referencia como retorno:
int & f();
int x = 0;//global
int main(){
f() = 100;
cout << x << endl; // 100
}
int & f(){
return x;
}

………..construtores, membros constantes não estáticos:
se numa classe existem membros const é obrigatório inicializar no construtor
class Test
{
const int t;
public:
Test(int t0) : t(t0)

………..construtores, membro referência:
class Test2
{
int & t;
public:
Test2(int &t0) : t(t0)
{
};

int getT() const
{
return t;
}

};

int main()
{
int x = 10;
Test2 t2(x);
cout << t2.getT() << endl;

}

membro default:
construtor = default, damos à classe um comportamento default
respeita a inicialização na zona privada
assim o default disponibiliza

membro delete:
vai tornar indisponível a implementação de construtor por omissão, construtor por cópia, operador atribuição, e destrutor
assim o delete impede/proíbe que exista:
construtor por omissão, construtor por cópia, operador atribuição, e destrutor

………..Variáveis em memória dinâmica:
operador new: requisitar memória, e que invoca o construtor
operador delete: para libertar a memória dinâmica
p.e.:
pVar = new tipo;
delete pVar;
p.e.:
Produto* p = new Produto();
cout << p->getAsString() << endl;
delete p;

posso fazer uma reserva com:
int *v2 = new int() //() garantem que vem 0
delete v2

objectos em memória dinâmica:
uso do new, reserva memória para uma variável do tipo classe, e desencadeia o construtor
uso do delete, activa a execução do destrutor

p.e.:
class Ponto {
int x; // abcissa
int y; // ordenada
public:
Ponto() { cout << “Construindo \n”; x = 0; y = 0; }
~Ponto() { cout << “Destruindo \n”; }
void imprime() { cout << “x=” << x << ” y=” << y << endl; } }; int main(void) { Ponto * p = new Ponto; p->imprime();
delete p;
}

existe uma alternativa a:
Ponto * p = new Ponto;
que pode ser com argumentos
Ponto * p = new Ponto{2,2};
criando por exemplo:

criando por exemplo:
Ponto(int x0, int y0) { cout << “Construindo \n”; x = x0; y = y0; }

………..criar um array dinâmico de variváveis de um tipo:
criar:
Ponto * p = new Ponto[4];
libertar:
delete [] pVar

os operadores:
o ponteiro this:
implicitamente nas funções normal membro, não estáticia, a palavra this representa o objecto que invocou a função

………..operadores overloaded:
p.e. existem dois ou mais objectos de uma determinada classe
podemos querer aplicar os operadores que se usam para os tipos primitivos, como é o caso de:
+

*
/
%
=
+=
e vão ter as mesmas regras de prioridade e associatividade
expandidmos assim para operandos das classes
usamos assim o operator
p.e. operator+

………..operadores binários:
p.e.: se o operador estiver relacionado com a atribuição, =, em que os dois operandos não têm o mesmo estatuto é um operador membro, para dar resposta a z+=x ou (z+=x)=y, e também para dar resposta a operações de cadeia
public:
Complexo & operator+=( const Complexo & x); //operador membro
//global, mas membro da classe,
Complexo & Complexo::operator+=( const Complexo & x){
a += x.a;
b += x.b;
return *this; //estatuto de referência
}
//a opção agora é global, porque têm o mesmo estatutuo, são consultados apenas
Complexo operator+(const Complexo & x, const Complexo & y){
// const Complexo & -> para funcionar em cadeia, p.e., para responder a z = x + y +z; (exame)
return Complexo( x.getA() + y.getA() , x.getB() + y.getB() );
}
//e global
ostream & operator<<( ostream & saida, const Complexo & x){
// recebe cout: ostream & saida -> é alterado logo usa-se o &, com a informação do objecto
// ostream & operator -> para funcionar em cadeia, p.e., para responder a cout << x << y; (exame)
return saida << “(“<<x.getA() << ” , ” << x.getB() << “)”;
}
para fazer:
z = x + y;
cout << z << endl;

………..os operadores unários:
++

que podem ser:
pre-fixados (recomendado que sejam membros), p.e.: ++a, que vai ser interpretada como aa.operator++()
ou
pos-fixados (recomendado que sejam membros), p.e.: a++, que vai ser interpretada como aa.operator++(0)

p.e.:
pre-fixado
public:
Complexo & operator++();
e global
Compelxo & Complexo::operator++(){
a +=1;
retun *this;
}

pos-fixado
public:
Complexo operator++(int);
e global
Compelxo Complexo::operator++(int){
Complexo anterior(a,b); //guardamos o valor velho num outro objecto
a +=1;
retun anterior; //retornamos o velho
}
//neste caso não retrno uma referência

………..operador []
usado em classes, classes com coleções, como arrays ou vectores
operator[]()
x[y] é equivalente x.operator[](y)
serve:
para acedermos a um elemento da coleção, e quebra com o encapsulamento
p.e.:
class Tabela {
static const int DIM = 10;
static double erro;
double a[DIM];
int n; // numero de elementos utilizados
public:
// …
double & operator[](int i);
};
double Tabela::erro = 0;
usando:
double & Tabela::operator[](int i) {
if (i >= 0 && i < DIM) return a[i];
else {
cout << “\nIndice ” << i << ” fora dos limites”;
return erro;
}
}
int main() {
Tabela x;
x[0] = 20; // equivalente a x.operator[](0) = 20;
cout << “\n x[0]=” << x[0] << endl;
x[40] = 55;
}

………..operador chamada de função
usada em situações bidimensionais, por exemplo obter um numero de uma matriz bidimensional
usa dois parentesis curvos
operação tem que ser membro
chama.se usando operator()()
p.e.:
class Matriz {
static const int DIM = 10;
static double erro;
double a[DIM][DIM];
int lin; // numero de linhas utilizadas
int col; // numero de colunas utilizadas
public:
//….
double & operator()(int i, int j);
};
double Matriz::erro = 0;

double & Matriz::operator( )(int i, int j) {
if (i >= 0 && i < DIM && j >= 0 && j < DIM)
return a[i][j]; //com estatuto de referência
else {
cout << “\nIndices i=”
<< i << ” e j=” << j << ” fora dos limites”;
return erro;
}
}

int main() {
Matriz x;
x(1, 0) = 44; // x.operator()( 1,0) = 44; (escrever 44 lá..)
cout << “\n x(1,0)=” << x(1, 0);
x(-1, 100) = 12.1;
}

Tags : , , , , ,

POO, introdução III

………..herança
se for composição um classe tem outras classes
se for derivação, sendo um caso particular com caracteristicas adicionais
uma classe derivada: tem membros herdados, e membros adicionais

class Terrestre : public Veiculo { // classe derivada: Terrestre, classe base: Veiculo
int velocidade;
public:
// …
};
a classe derivada acede aos gets e sets das funções que herdou

class Terrestre : public Veiculo
por se usar public:
herança publica
os membros publicos da classe base, são também da classe derivada
e por essa via será também um membro publico da classe derivada

class Terrestre : private Veiculo
ou
class Terrestre : Veiculo
por se usar private:
os membros publicos da herança, são privados de terrestre

o uso de protected:
é um nivel de acesso
são visiveis na classe
nas classes derivadas são visiveis
no código exterior, que não a classe ou classe derivadas não são acessiveis

Forma de derivação
private
membros que na classe base são:
private
protected
public
na classe derivada são:
inacessíveis
private
private

Forma de derivação
protected
membros que na classe base são:
private
protected
public
na classe derivada são:
inacessíveis
private
private

Forma de derivação
public (normal)
membros que na classe base são:
private
protected
public
na classe derivada são:
inacessíveis
protected
public

p.e.:
class Veiculo {
int peso;
protected:
int comprimento;
public:
Veiculo( int p = 0, int c=0): peso (p), comprimento(c){}
int getPeso()const{ return peso; }
int getComprimento()const{ return comprimento; }
void setPeso( int p){ peso = p;}
void setComprimento( int c){ comprimento = c;}
};

class Terrestre : public Veiculo {
int velocidade;
public:
Terrestre(int p=0,int c=0,int vel=0):Veiculo(p,c) {
velocidade = vel;
}

int getVelocidade()const{ return velocidade; }

void setVelocidade( int vel){ velocidade = vel;}

void imprime(ostream & saida )const{
saida << “Peso: ” << getPeso() << endl;
saida << “Compr: ” << comprimento << endl;
saida << “Veloc: ” << velocidade << endl;
}
};

int main(){
Veiculo v(700);
cout << “Peso: ” << v.getPeso() << endl;
//cout <<“Compr:” << v.comprimento << endl; ERRO , é protected em veiculo

Terrestre t(600, 4, 90);
cout << “Peso: ” << t.getPeso() << endl;
//cout <<“Compr:” << t.comprimento << endl; ERRO, é protected em veiculo

cout<<“Veloc: “<< t.getVelocidade() << endl;
t.imprime( cout);
}

Quando um objecto de uma classe derivada é destruído, são chamados os destrutores por ordem inversa da ordem de derivação: primeiro o destrutor da classe derivada, depois o destrutor da classe base

situação:
temos duas classes iguais, temos que usar o nome da herança Herança::funcao

situação: uma classe derivada e composta
p.e.:
class Base {
int i;
public:
Base(int ii = 0) : i(ii) { cout << “Base(int ii)\n”; }
~Base() { cout << “~Base()\n”; }
void imprime(ostream& saida)const {
saida << “Base: i=” << i << endl;
}
};

class Membro {
int k;
public:
Membro(int kk = 0) : k(kk) { cout << “Membro(int kk)\n”; }
~Membro() { cout << “~Membro()\n”; }
void imprime(ostream& saida)const {
saida << “Membro: k=” << k << endl;
}
};
class Derivada : public Base {
int j;
Membro m;
public:
Derivada(int jj) : Base(jj), j(jj), m(jj) {
cout << “Derivada(int jj)\n”;
}
~Derivada() { cout << “~Derivada()\n”; }
void imprime(ostream& saida)const {
saida << “Derivada: j=” << j << endl;
Base::imprime(saida);
m.imprime(saida);
saida << endl;
}
};
int main() {
Derivada d(2);
cout << “\nValores em d:\n”;
d.imprime(cout);
// chamada ao destrutor para d
}

situação: a classe derivada nao tem construtor nem destrutor
p.e.:
class Base {
int i;
public:
Base(int ii = 0) : i(ii) { cout << “Base(int ii)\n”; }
~Base() { cout << “~Base()\n”; }
void imprime(ostream& saida)const {
saida << “Base: i=” << i << endl;
}
};

class Membro {
int k;
public:
Membro(int kk = 0) : k(kk) { cout << “Membro(int kk)\n”; }
~Membro() { cout << “~Membro()\n”; }
void imprime(ostream& saida)const {
saida << “Membro: k=” << k << endl;
}
};

class Derivada : public Base {
Membro m;
public:
void imprime(ostream& saida)const {
saida << “Derivada: \n”;
Base::imprime(saida);
m.imprime(saida);
saida << endl;
}
};

int main() {
Derivada d;
cout << “\nValores em d:\n”;
d.imprime(cout);
// destruição de d
}

análise:
surge o construtor gerado automaticamente
é chamado o construtor da base e do membro
e na destruição invoca o membro e depois a base
também é respeitado o funcionamento da base e derivada, pela ordem com que são construídos e destruídos

………..funções com tratamento especial relativamente à herança
situações:
Construtores:
um construtor de uma classe derivada chama explicitamente ou implicitamente o construtor da classe base correspondente.
Construtor por cópia:
no construtor por cópia de uma classe derivada é preciso chamar explicitamente o construtor por cópia da classe base.
Destrutores:
um destrutor de uma classe derivada chama o destrutor da classe base correspondente.
Operador atribuição:
a atribuição entre dois objectos de uma classe pode não ser suficiente para fazer a atribuição entre dois objectos de uma classe derivada. O operador atribuição não é herdado normalmente como pode ver-se no exemplo seguinte.

p.e.:

class Base {
int i;
public:
Base(int ii) : i(ii) {}
Base(const Base & b) : i(b.i) {
cout << “Base(const Base &)\n”;
}
Base & operator=(const Base & b){
i = b.i;
cout << “Base::operator=()\n”;
return *this;
}
void imprime( ostream & saida)const{
saida << “Base: i=” << i << endl;
}
};

class Membro {
int k;
public:
Membro(int kk) : k(kk) {}
Membro(const Membro& m) : k(m.k) {
cout << “Membro(const Membro&)\n”;
}
Membro & operator=(const Membro & m){
k = m.k;
cout << “Membro::operator=()\n”;
return *this;
}
void imprime( ostream & saida)const{
saida << “Membro: k=” << k << endl;
}
};

class Derivada : public Base {
int j;
Membro m;
public:
Derivada(int jj) : Base(jj), j(jj), m(jj) {}

void imprime( ostream & saida)const{
saida << “Derivada: j=” << j << endl;
Base::imprime(saida);
m.imprime(saida);
}
};
int main() {
Derivada d(2);
cout << “\nConstrução por copia : ” << endl;
Derivada d2 = d; // construção por copia
cout << “\nValores em d2:\n”;
d2.imprime(cout);
Derivada d3(3);
cout << “\nAtribuicao: ” << endl;
d3 = d; // atribuição

cout << “\nValores em d3:\n”;
d3.imprime(cout);
}

………..herança, composição e construtor por cópia
outra versão da classe Derivada, com construtor por cópia e operador atribuição explícitos.
se nada dissermos na derivada, o construtor que é chamado é o da base por omissão e ainda assim temos que ter em atenção de que Base pode preencher com coisas por default
assim é necessário que se explicitem nestas chamadas a lista de inicialização do construtor por cópia, seriam chamados em seus lugares os correspondentes pois caso não sejam, construtores por defeito. O sub-objecto adquirido por herança e os membros objectos seriam inicializados pelos construtores por defeito em vez de receberem cópias dos correspondentes sub-objectos do objecto da classe Derivada considerado origem da cópia.
p.e.:

class Base {
int i;
public:
Base(int ii) : i(ii) {}
Base(const Base& b) : i(b.i) {
cout << “Base(const Base &)\n”;
}
Base& operator=(const Base& b) {
i = b.i;
cout << “Base::operator=()\n”;
return *this;
}
void imprime(ostream& saida)const {
saida << “Base: i=” << i << endl;
}
};

class Membro {
int k;
public:
Membro(int kk) : k(kk) {}
Membro(const Membro& m) : k(m.k) {
cout << “Membro(const Membro&)\n”;
}
Membro& operator=(const Membro& m) {
k = m.k;
cout << “Membro::operator=()\n”;
return *this;
}
void imprime(ostream& saida)const {
saida << “Membro: k=” << k << endl;
}
};
class Derivada : public Base {
int j;
Membro m;
public:
Derivada(int jj) : Base(jj), j(jj), m(jj) {}
Derivada(const Derivada& d) : Base(d), m(d.m), j(d.j) {
cout << “Derivada(const Derivada&)\n”;
}
Derivada& operator=(const Derivada& d) {
Base::operator =(d);
m = d.m;
j = d.j;
cout << “Derivada::operator=()\n”;
return *this;
}
void imprime(ostream& saida)const {
saida << “Derivada: j=” << j << endl;
Base::imprime(saida);
m.imprime(saida);
}
};

………..polimorfismo, clases derivadas
uma espécie de, ou um tipo de, é uma herança
o upcasting, é feito do tipo ascendente, e não é preciso fazer nada, nenhum cast explicito.
p.e.:
class Veiculo {
/* … */
};
class Terrestre : public Veiculo {
/* … */
};
class Automovel : public Terrestre {
/* … */
};
assim é possivel que:
conversão de um ponteiro para Terrestre num ponteiro para Veiculo;
conversão de um ponteiro para Automovel num ponteiro para Veiculo;
conversão de uma referência para Terrestre numa referência para Veiculo;
conversão de uma referência para Automovel numa referência para Veiculo.
isto é:
class Veiculo {
/* … */
};
class Terrestre : public Veiculo {
/* … */
};
int main(){
Veiculo *p;
Veiculo v;
Terrestre t;
p=&v;
p=&t; // upcasting
Veiculo & r = t; // upcasting
}

p=&t; // upcasting
um ponteiro para uma classe base pode receber um endereço de um objecto de uma classe derivada ou derivada da derivada..
pode assim ser feito por inteiro ou pode ser feito por referencia:
Veiculo & r = t; // upcasting

o upcasting é sempre verdade
o downcasting nem sempre é verdade

uso na base da expressão virtual na base e nas suas funções (desta forma será sempre usada a referência para o objeto que é referido)
e na derivada faz-se uso nas funções de override

Um ponteiro ou uma referência para uma classe base podem apontar para, ou referir, um objecto dessa classe ou de uma classe derivada directa ou indiretamente e é invocada:
é executada a versão da função da classe correspondente ao ponteiro ou referência, se a função não for virtual;
é executada a versão da função correspondente à classe a que pertence o objecto, se a função for virtual;

p.e.:
class Veiculo { //classe base
int peso;
public:
Veiculo(int p = 0) : peso(p) {}
virtual void imprime(ostream& saida) const { //virtual
saida << “\nPeso: ” << peso << endl;
}
};

class Terrestre : public Veiculo { //classe derivada
int velocidade;
public:
Terrestre(int p = 0, int vel = 0) : Veiculo(p), velocidade(vel) {}
void imprime(ostream& saida)const override { //lidar com o virtual
Veiculo::imprime(saida);
saida << “Veloc: ” << velocidade << endl;
}
};

class Automovel :public Terrestre { //classe derivada de derivada
int cilindrada;
public:
Automovel(int p = 0, int vel = 0, int cil = 0) : Terrestre(p, vel), cilindrada(cil) {}
void imprime(ostream& saida)const override { //lidar com o virtual
Terrestre::imprime(saida);
saida << “Cilind: ” << cilindrada << endl;
}
};

class Aereo :public Veiculo {
int altura_voo;
public:
Aereo(int p = 0, int a = 0) : Veiculo(p), altura_voo(a) {}
//não tem imprime recebe por herança da base
};
ostream& operator<<(ostream& saida, const Veiculo& x) {
x.imprime(saida);
return saida;
}

int main() {
Veiculo* a[] = { // array de ponteiros para a classe base, Veiculo
new Veiculo(700), // inicialização
new Terrestre(800,80), // inicialização: upcasting
new Automovel(900,90,1400), // inicialização: upcasting
new Aereo(2000,50) // inicialização: upcasting
};
int n = sizeof(a) / sizeof(Veiculo*); //contar elementos
for (int i = 0; i < n; i++) //perocrrer o array
a[i]->imprime(cout); // ou cout << *a[i];

for (int i = 0; i < n; i++)
delete a[i];
}

………..polimorfismo, classes abstractas e funções virtuais
uma classe é abstracta se a classe tem pelo menos um função virtual pura
uma classe abstracta não pode criar objetos
uma classe abstracta pode ter ponteiros e referências
faz sentido existir um prototipo da função que representa apenas um interface comum das classes desta hierarquia
p.e.:
virtual string meio() = 0; // é uma função virtual pura e fica uma classe abstracta
e esta classe pode conter ou pode não conter uma definição da função.
vais er necessário definir na classe derivada todas as funções virtuais puras adquiridas por herança

a classe derivada continua abstracta, se não for concretizada pelo menos uma função virtual pura adquirida por herança e por esse motivo não pode haver objectos desta classe

p.e.:
class Veiculo { //classe abstracta
int peso;
public:
Veiculo(int p = 0) : peso(p) {}
virtual void imprime(ostream & saida) const = 0; //função abstracta, ou virtuais puras
virtual string meioOndeSeDesloca()const = 0; //função abstracta, ou virtuais puras
int getPeso()const { return peso; }
};

class Terrestre : public Veiculo {
int velocidade;
public:
Terrestre(int p = 0, int vel = 0) :
Veiculo(p), velocidade(vel) {}
void imprime(ostream & saida)const override {
saida << “\nPeso: ” << getPeso() << endl << “Veloc: ” << velocidade << endl;
} //faz o overide da função abstracta imprime, da base: herdou duas, concretizou uma
// não se define ainda a função meioOndeSeDesloca(), e por este motivo esta é uma classe abstracta
};

class Automovel :public Terrestre { //esta classe tem as duas funções concretas: concretizou meioOndeSeDesloca e redefiniu a concreta imprime
int cilindrada;
public:
Automovel(int p = 0, int vel = 0, int cil = 0) : Terrestre(p, vel), cilindrada(cil) {}
virtual void imprime(ostream & saida)const override {
Terrestre::imprime(saida);
saida << “Cilind: ” << cilindrada << endl;
} //redefine a função imprime
string meioOndeSeDesloca()const override {
return string(” desloca-se em estrada \n”);
}//herdou uma função asbtracta e concretizou
};
class Aereo :public Veiculo { //concretizou as duas funções, logo é uma classe concreta
int alturaVoo;
public:
Aereo(int p = 0, int a = 0) : Veiculo(p), alturaVoo(a) {}
void imprime(ostream & saida)const override {
saida << “\nPeso: ” << getPeso() << endl << “Altura de voo: ” << alturaVoo << endl;
}
string meioOndeSeDesloca()const override {
return string(” desloca-se por via aerea \n”);
}
};
ostream & operator<<(ostream & saida, const Veiculo & x){
x.imprime(saida);
return saida;
}
int main() {
Veiculo* a[] = { //pode-se criar um array de ponteiros de classes abstractas
//new Veiculo(700), // ERRO, é uma classe abstracta, e não se podem criar objectos de classes abstractas
//new Terrestre(800,80), // ERRO, é uma classe abstracta, e não se podem criar objectos de classes abstractas
new Automovel(900,90,1400), //é uma classe concreta
new Aereo(2000,50) //é uma classe concreta
};
int n = sizeof(a) / sizeof(Veiculo*);
for (int i = 0; i < n; i++)
cout << *a[i] << a[i]->meioOndeSeDesloca();
delete a[0];
delete a[1];
}

………..polimorfismo, destrutores virtuais
O destrutor de uma classe base pode não ser suficiente para “destruir” um objecto de uma classe derivada
o uso delete, vai invocar o destrutor:
se o destrutor for virtual na classe do ponteiro, vai ser usado o destrutor de classe apontado
se o destrutor não for virtual na classe do ponteiro, vai ser usado o destrutor da classe ponteiro, que não é o destrutor da classe do objeto que está a ser destruído

na herança, o destrutor da classe derivada é executado mas depois chama o destrutor da base

p.e.:
class Veiculo {
int peso;
public:
Veiculo(int p = 0) : peso(p) {}
virtual ~Veiculo() { cout << “Destruindo Veiculo\n”; } //é virtual
};
class Aereo :public Veiculo {
int altura_voo;
string * historico;
int n;
public:
Aereo(int p = 0, int a = 0) : Veiculo(p), altura_voo(a), historico(nullptr), n(0) {}
virtual ~Aereo()override { //foi feito o override
delete[] historico;
cout << “Destruindo Aereo\n”;
}
};
int main() {
Veiculo* p = new Aereo(2000, 50);
// …
delete p; // funciona o destrutor de Aereo
// porque o destrutor foi declarado como virtual na classe Veiculo
}

………..polimorfismo, Colecção polimórfica e composição, duplicação polimórfica
existem agora elementos diferentes na colecção
(ver exemplo do aquário)
queremos fazer uma copia (duplicar), se fossem todos iguais eram com o new, mas neste caso temos elementos diferentes.
a solução:
duplicação polimorfica
na classe base é definida uma função virtual que duplica o objeto
mas não podem haver objectos da classe base, porque ela é a abstracta
nas classes derivadas é concretizada a função duplica, e esta função vai fazer o return new Derivada(*this) <-“é o construtor por cópia gerado automaticamente” a funcionar
e na classe base, surge na função de atribuição a duplicação dos objetos, recorrendo a Peixe* p = orig.peixes[i]->duplica();

p.e.:
class Peixe {
// …
};
class TetraPeixe : public Peixe { //classe derivada
// …
};
class NeonPeixe : public Peixe { //classe derivada
// …
};

class Aquario {
// o aquario contém uma colecção de peixes que podem ser de diversos tipos
vector<Peixe*> peixes; //vector de ponteiros para peixes, e pode ser cada um de sua classe, é um vector polimorfico
// …
public:
Aquario() = default;
// Os peixes são criados e destruídos no aquario
// A relação entre o aquário e os peixes é de composição
Aquario(const Aquario& orig); // construtor por copia
Aquario& operator=(const Aquario& orig); // operador atribuicao
virtual ~Aquario(); // destrutor
// …

// funcao abstracta, nao se podem criar objectos desta classe
virtual void alimentar(int quantidade, Aquario* aquario) = 0;
// duplicação polimórfica dos peixes
// como a classe é abstracta, esta função também tem que ser abstracta porque
// não se podem criar objectos da classse Peixe
virtual Peixe* duplica()const = 0; //duplicação polimórfica
};

Aquario::~Aquario() {
for (Peixe* p : peixes) {
delete p;
}
}

class TetraPeixe : public Peixe {
// …
public:
// …
// cria uma cópia de si mesmo em memória dinâmica
Peixe* duplica()const override;
};
Peixe* TetraPeixe::duplica()const { //garante a duplicação
return new TetraPeixe(*this);
}

class NeonPeixe : public Peixe {
// …
public:
// …
// cria uma cópia de si mesmo em memória dinâmica
Peixe* duplica()const override;
};
Peixe* NeonPeixe::duplica()const { //garante a duplicação
return new NeonPeixe(*this);
}

Aquario& Aquario::operator=(const Aquario& orig) { //operador atribuição
// prevencao da auto-atribuicao
if (this == &orig) {
return *this;
}
// libertar memoria dinamica do primeiro membro da atribuição
for (int i = 0; i < peixes.size(); i++) {
delete peixes[i];
}
//esvaziar o vector
peixes.clear();
// copiar a informacao de orig, duplicando os objectos dinamicos do tipo Peixe
for (int i = 0; i < orig.peixes.size(); i++) {
Peixe* p = orig.peixes[i]->duplica();
peixes.push_back(p);
}
// …
return *this;
}

Aquario::Aquario(const Aquario& orig) { //construtor por cópia
//funcionou o construtor por omissao do vector de ponteiros
//o vector está vazio
// não há ponteiros com valores indefinidos
*this = orig;
}

Tags : , , , , ,