Resolução do Exame de 1ª época
Introdução à Programação
IGE e ETI
1º semestre de 2001/2002
ISCTE
Deve preencher todos os espaços indicados por um sublinhado (___) com V ou F. Qualquer espaço não preenchido será considerado como uma resposta errada.
Em geral as alíneas podem ter zero ou mais respostas correctas. Cada resposta correctamente assinalada vale 0,5 valores.
Nas alíneas em que apenas uma resposta está correcta (se existirem estão assinaladas no texto), responder com mais ou menos do que um V anula a cotação. A resposta correcta corresponde à cotação completa. Qualquer outra resposta corresponde a zero valores.
Em todos os casos em que não é explicitamente referida a
localização de uma instrução, considere que esta é dada na função
main()
do programa seguinte (Atenção: o código não tem erros
de compilação, mas pode ter erros lógicos):
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Dicionário {public:
Dicionário(string const& língua);
string const& língua() const;
bool contém(string const& palavra) const;
int númeroDePalavras() const;
void insere(string const& palavra);
void transfereDe(Dicionário origem);
void mostra() const;
private:vector<string> palavras;
string const língua_;
};
Dicionário::Dicionário(string const& língua): língua_(língua)
{}
void Dicionário::insere(string const& palavra)
{
palavras.push_back(palavra);
}
void Dicionário::transfereDe(Dicionário origem)
{
while(not origem.palavras.empty()) {
palavras.push_back(origem.palavras.back());
origem.palavras.pop_back();
}}
...
int main()
...
{
string const português("Português");
Dicionário dicionário_de_português(português);
Dicionário const dicionário_de_expressões_usadas_no_vácuo("Expressão no vácuo");
}
1.1 Admita que qualquer uma destas instruções é
dada na função main()
imediatamente após a definição das
variáveis. Quais das seguintes instruções estão correctas?
V Dicionário d(dicionário_de_expressões_usadas_no_vácuo.lingua());
F
Dicionário d;
A classe
Dicionário
não tem um construtor por omissão.
F Dicionário d(italiano);
O construtor da classe
Dicionário
tem como parâmetro uma referência constante para umastring
.
[cotação: 1,5]
1.2 Admita que qualquer uma destas instruções é
dada na função main()
do programa acima. Quais das seguintes instruções
estão correctas?
V bool contém_palavra = dicionário_de_português.contém("exame");
F
dicionário_de_português.lingua() = "Castelhano";
lingua()
é uma função membro constante que devolve umastring
por referência constante, pelo que não se lhe podem atribuir valores.
F português =
dicionário_de_expressões_usadas_no_vácuo.lingua();
português
é umastring
constante, pelo que não se lhe podem atribuir novos valores.
V int
const n = dicionário_de_expressões_usadas_no_vácuo.
númeroDePalavras()
;
[cotação: 2]
1.3 Assuma que as seguintes instruções são dadas
dentro de uma função ou procedimento membro da classe Dicionário
e que não são
declaradas quaisquer variáveis ou constantes dentro dessa função ou procedimento
(que não tem quaisquer parâmetros). Quais das seguintes instruções estão
correctas?
F palavras =
númeroDePalavras()
;
palavras
é umvector
, pelo que não se lhe pode atribuir um valor do tipoint
.
F
língua_ =
"Castelhano"
;
língua_
é um atributo constante, pelo que tem de ser inicializado no construtor.
[cotação: 1]
1.4 Assumindo que os restantes métodos da classe estão definidos, qual é o resultado da invocação do seguinte programa?
Apenas uma das opções está correcta.
int main()
{
Dicionário a("Português europeu");
a.insere("alquimia");
a.insere("banana");
a.insere("dia");
Dicionário b("Português americano");
b.transfereDe(a);
cout << a.
númeroDePalavras()
<< " "
<< b.númeroDePalavras()
<< endl;
}
V 3 3
F
0 3
F 3
0
F 0 0
[cotação: 0,5]
O atributo
língua_
da variávela
do tipoDicionário
é inicializado com "Português europeu
" e no atributo vectorpalavras
são inseridas três cadeias de caracteres: "alquimia
", "banana
" e "dia
". O atributolíngua_
da variávelb
do tipoDicionário
é inicializado com "Português americano
" e o atributopalavras
é um vector vazio. Em seguida, a variávelb
invoca a operaçãotransfereDe()
, com a variávela
como argumento. O conteúdo do vector membro dea
é inserido no vector membro deb
(ficando assim com três elementos), mas como o argumento foi passado por valor, as alterações realizadas dentro do método não se reflectem ema
. Assim, quando se invoca a operaçãonúmeroDePalavras()
para as variáveisa
eb
obtém-se em ambos os casos 3.
Questão 2
Considere o problema de gestão de stocks numa empresa. No stock da empresa dão entrada lotes, que se caracterizam por ter o nome do produto, a quantidade de unidades do produto nesse lote e o valor unitário do produto nesse lote. Quando um lote de um produto chega ao armazém da empresa é registado no inventário. Quando ocorrem saídas de produtos do armazém altera-se o inventário de acordo com a quantidade de produto que saiu do armazém. A ordem de saída dos produtos respeita a ordem de chegada. Ou seja, começa-se por retirar os produtos do primeiro lote desse produto que tiver dado entrada, continuando-se pelos lotes seguintes (do mesmo produto) até se ter a quantidade pretendida. O valor de uma saída é calculado somando as multiplicações das quantidade saídas de cada lote pelo valor unitário do produto nesse lote. O valor dos produtos em stock é calculado somando as multiplicações das quantidades de cada lote inventariado pelo valor unitário do produto nesse lote.
Pretende-se construir um sistema de gestão de stocks de uma empresa que disponha das seguintes funcionalidades:
2.1 Defina a classe C++ Lote
que
representa um lote de um dado produto. Um lote, como já foi referido, é
constituído pelo nome (cadeia de caracteres), quantidade (inteiro) e valor
unitário (valor de vírgula flutuante, i.e., double
) do produto. A classe C++ Lote
deve dispor de um construtor que recebe os dados necessários à construção de
um lote e das seguinte operações:
Indique a condição invariante de classe (CIC) e as pré condições de cada operação. Adicione a operação necessária para verificar a CIC.
Indique claramente quais dos métodos da classe não alteram a instância implícita.
Não é necessário nesta questão definir qualquer um dos métodos (funções ou procedimentos membro) da classe.
[cotação: 1]
2.2 Defina o construtor da classe Lote
e o método
que permite verificar a CIC.
[cotação: 0,5]
2.3 Defina as funções de inspecção do nome, da quantidade e
valor unitário do produto para a classe Lote
, bem como a
operação que exibe os dados do lote no ecrã e o modificador que
permite diminuir a quantidade de produto do lote.
Coloque instruções de asserção para verificar a condição invariante de classe e as pré-condições nos métodos definidos.
[cotação: 0,5]
2.4 Defina a classe C++ Inventário
que permite
registar os lotes que chegam ao armazém da empresa e as saídas de produto.
Esta classe deve dispor de operações para:
Todos os lotes inventariados têm de ter quantidade superior a zero. Como não devem existir
no inventário lotes com quantidade igual a zero (não fazem
sentido), a classe C++ Inventário
deve dispor ainda de uma
operação privada para realizar a purga dos lotes vazios, isto é, remover
todos os lotes cuja quantidade é zero.
Indique qual a condição invariante de classe e as pré-condições das operações. Adicione a operação necessária para verificar a CIC.
Indique claramente quais dos métodos da classe não alteram a instância implícita.Não é necessário nesta questão definir qualquer um dos métodos.
[cotação: 1,5]
2.5 Defina o método da classe C++ Inventário
que permite saber se dado produto está presente no inventário.
Coloque instruções de asserção para verificar as pré-condições e a condição invariante de classe no método definido.
[cotação: 1]
2.6 Defina o método da classe C++ Inventário
que devolve o valor dos produtos em stock.
Coloque instruções de asserção para verificar as pré-condições e a condição invariante de classe no método definido.
[cotação: 1]
2.7 Defina os métodos da classe C++ Inventário
para:
Coloque instruções de asserção para verificar as pré-condições e a condição invariante de classe nos métodos definidos.
[cotação: 1,5]
2.8 Escreva um programa que utilize as classes anteriores para simular a componente de gestão de stocks de uma empresa. O programa deve mostrar o menu:
no ecrã, permitindo assim ao utilizador escolher entre as operações possíveis. Quando a opção 0 for escolhida o programa terminará.
1 - Entrada de lote
2 - Saída de produto
3 - Valor dos produtos em stock4 - Mostra inventário
0 - Terminar
Se a opção 1 for escolhida, o programa deve perguntar qual o nome do produto, a quantidade e o valor unitário, e adicionar ao inventário o lote constituído por essa informação.
Se a opção 2 for escolhida, o programa deve perguntar qual o nome do produto e a quantidade que irá sair do armazém. Se o produto não existir em stock o programa deve avisar o utlizador. Se o produto não existir em quantidade suficiente o programa deve avisar o utilizador. Se não ocorrer nenhuma destas situações, o programa deve mostrar o valor da saída e realizá-la.
Se for escolhida a opção 3, deve ser exibido no ecrã o valor dos produtos em stock. Caso seja escolhida a opção 4, exibe-se o inventário.
Exemplo de execução:
1 - Entrada de lote
2 - Saída de produto
3 - Valor dos produtos em stock4 - Mostra inventário
0 - Terminar
Opção: 1
Nome do produto: batata
Quantidade: 100
Valor unitário: 0.7
1 - Entrada de lote
2 - Saída de produto
3 - Valor dos produtos em stock4 - Mostra inventário
0 - Terminar
Opção: 4
batata 100 0.7
1 - Entrada de lote
2 - Saída de produto
3 - Valor dos produtos em stock4 - Mostra inventário
0 - Terminar
Opção: 1
Nome do produto: cebola
Quantidade: 50
Valor unitário: 0.85
1 - Entrada de lote
2 - Saída de produto
3 - Valor dos produtos em stock4 - Mostra inventário
0 - Terminar
Opção: 1
Nome do produto: batata
Quantidade: 100
Valor unitário: 0.5
1 - Entrada de lote
2 - Saída de produto
3 - Valor dos produtos em stock4 - Mostra inventário
0 - Terminar
Opção: 4
batata 100 0.7
cebola 50 0.85
batata 100 0.5
1 - Entrada de lote
2 - Saída de produto
3 - Valor dos produtos em stock4 - Mostra inventário
0 - Terminar
Opção: 2
Nome do produto: banana
Quantidade: 20
O produto banana não existe em stock.
1 - Entrada de lote
2 - Saída de produto
3 - Valor dos produtos em stock4 - Mostra inventário
0 - Terminar
Opção: 2
Nome do produto: batata
Quantidade: 150
O valor da saída é 95.
1 - Entrada de lote
2 - Saída de produto
3 - Valor dos produtos em stock4 - Mostra inventário
0 - Terminar
Opção: 4
cebola 50 0.85
batata 50 0.5
1 - Entrada de lote
2 - Saída de produto
3 - Valor dos produtos em stock4 - Mostra inventário
0 - Terminar
Opção: 3
O valor dos produtos em stock é 67.5.
[cotação: 1]
Apresenta-se a solução completa. A negrito as partes requeridas no enunciado.
#include <iostream>
Representa um lote.
#include <iomanip>
#include <string>
#include <vector>
using namespace std;
/**
@invariant
nome_ <>
"" equantidade_ >=
0 evalor_unitario >=
0.*/
Constrói um lote.
class Lote {
public:
/**
@pre
nome <>
"",quantidade >=
0 evalor_unitario >=
0.@post
nome() = nome
,quantidade() = quantidade
e.
valor_unitario() = valor_unitario*/
Devolve o nome do produto do lote.
Lote(string const& nome, int const quantidade,
double const valor_unitario);
/**
@pre V.
@post
nome()
é o nome do produto do lote.*/
Devolve a quantidade de produto do lote.
string const& nome() const;
/**
@pre V.
@post
quantidade()
é a quantidade de produto do lote.*/
Devolve o valor unitário do produto do lote.
int quantidade() const;
/**
@pre V.
@post
valorUnitario()
é o valor unitário do produto do lote.*/
Diminui a quantidade de produto do lote em quantidade.
double valorUnitario() const;
/**
@pre
quantidade <= quantidade()
equantidade() =
q.@post
quantidade() =
q -quantidade
.*/
Mostra informação sobre o lote no ecrã.
void retira(int const quantidade);
/**
@pre V.
@post
¬cout
ou o ecrã contém o nome, a quantidade e o valor unitário do lote.*/
Devolve verdadeiro se o invariante se verificar.
void mostra() const;
private:
string nome_;
int quantidade_;
double valor_unitario;
/**
@pre V.
@post
cumpreInvariante =
(nome_ <>
"" equantidade_ >=
0 e0).
valor_unitario >=*/
bool cumpreInvariante() const;
};
Lote::Lote(string const& nome, int const quantidade,
double const valor_unitario)
: nome_(nome), quantidade_(quantidade),
valor_unitario(valor_unitario) {
}
string const& Lote::nome() const
{
assert(cumpreInvariante());
return nome_;
}
int Lote::quantidade() const
{
assert(cumpreInvariante());
return quantidade_;
}
double Lote::valorUnitario() const
{
assert(cumpreInvariante());
return valor_unitario;
}
void Lote::mostra() const
{
assert(cumpreInvariante());
cout << setw(40) << nome_ << ' '
<< setw(10) << quantidade_ << ' '
<< setw(20) << valor_unitario << endl;
}
void Lote::retira(int const quantidade)
{
assert(cumpreInvariante());
assert(quantidade <= quantidade_);
quantidade_ -= quantidade;
assert(cumpreInvariante());
}
Representa um inventário onde são registados lotes.
bool Lote::cumpreInvariante() const
{
return nome_ != "" and 0 <= quantidade_ and 0 <= valor_unitario;
}
/**
@invariant (Q j : 0
<=
j< lotes.size()
: 0 <lotes[
j].quantidade()
).*/
Indica se está inventariado o produto com nome
class Inventario {
public:
/**nome_do_produto
.
@pre V.
@post
contemProdutoComNome
=*this
contém pelo menos uma unidade do
produto com nome
nome_do_produto
.*/
Devolve a quantidade inventariada do produto com nome
bool contemProdutoComNome(string const& nome_do_produto) const;
/**nome_de_produto.
@pre V.
@post
quantidadeDe
= quantidade total de produto nos lotes cujo nome
de produto é
nome_do_produto
.*/
Devolve o valor da saída do armazém de quantidade do produto com nome
int quantidadeDe(string const& nome_do_produto) const;
/**nome_do_produto
.@pre 0 <=
quantidade
equantidade
<=quantidadeDe(nome_do_produto)
.@post
custoDaSaidaDe
= valor total da próxima saída dequantidade
produto
de nome
nome_do_produto
.
*/
Devolve o valor dos produtos inventariados.
double custoDeSaidaDe(string const& nome_do_produto, int const quantidade) const;
/**
@pre V.
@post
valor
= valor total dos produtos inventariados.*/
Adiciona o lote recebido como argumento no fim do inventario.
double valor() const;
/**
@pre
quantidadeDe(lote.nome()) =
q ecustoDeSaidaDe(lote.nome(),
q) =
c.@post
contemProdutoComNome
(lote.nome())
e+
quantidadeDe(lote.nome()) = qlote.quantidade()
eq
custoDeSaidaDe(lote.nome(),+
lote.quantidade()) =
c
+
lote.quantidade()
×
lote.valorUnitario()
.*/
Remove do inventário a quantidade quantidade do produto
void adiciona(Lote const& lote);
/**nome_do_produto
.@pre
contemProdutoComNome
(nome_do_produto)
e
0 <=
quantidade
equantidade
<=quantidadeDe(nome_do_produto)
eq e
quantidadeDe(nome_do_produto) =q
custoDeSaidaDe(nome_do_produto,) =
c1 ec2
custoDeSaidaDe(nome_do_produto, quantidade) =.
@post
quantidadeDe(nome_do_produto) =
q -quantidade
e
custoDeSaidaDe(nome_do_produto, quantidadeDe(nome_do_produto)) =
c1 - c2.*/
Mostra no ecrã informação sobre todos os lotes.
void remove(string const& nome_do_produto, int const quantidade);
/**
@pre V.
@post
¬canal
ou o ecrã contém o nome, a quantidade e o valor unitário de todos os lotes.*/
Remove do vector os lotes com quantidade igual a 0.
void mostra() const;
private:
vector<Lote> lotes;
/**
@pre V.
@post (Q j : 0
<=
j< lotes.size()
:lotes[j].quantidade() <>
0).*/
Devolve verdadeiro se o invariante se verificar.
void purgaLotesVazios();
/**
@pre V.
@post
cumpreInvariante =
(Q j : 0
<=
j< lotes.size()
:lotes[j].quantidade() >
0).*/
bool cumpreInvariante() const;
};
bool Inventario::contemProdutoComNome(string const& nome_do_produto) const
{
assert(cumpreInvariante());
for(vector<Lote>::size_type i = 0; i != lotes.size(); ++i)
if(lotes[i].nome() == nome_do_produto)
return true;
return false;
}
int Inventario::quantidadeDe(string const& nome_do_produto) const
{
assert(cumpreInvariante());
int quantidade = 0;
for(vector<Lote>::size_type i = 0; i != lotes.size(); ++i)
if(lotes[i].nome() == nome_do_produto)
quantidade += lotes[i].quantidade();
return quantidade;
}
double Inventario::custoDeSaidaDe(string const& nome_do_produto,
int const quantidade) const
{
assert(cumpreInvariante());
assert(0 <= quantidade and quantidade <= quantidadeDe(nome_do_produto));
double custo = 0.0;
int quantidade_actual = 0;
for(vector<Lote>::size_type i = 0;
i != lotes.size() and quantidade_actual != quantidade;
++i)
if(lotes[i].nome() == nome_do_produto) {
int unidades_a_acrescentar =
lotes[i].quantidade() < quantidade - quantidade_actual ?
lotes[i].quantidade() : quantidade - quantidade_actual;
quantidade_actual = unidades_a_acrescentar;
custo += unidades_a_acrescentar*lotes[i].valorUnitario();
}
return custo;
}
double Inventario::valor() const
{
assert(cumpreInvariante());
double total = 0.0;
for(vector<Lote>::size_type i = 0; i != lotes.size(); ++i)
total += lotes[i].quantidade() * lotes[i].valorUnitario();
return total;
}
void Inventario::adiciona(Lote const& lote)
{
assert(cumpreInvariante());
lotes.push_back(lote);
assert(cumpreInvariante());
}
void Inventario::remove(string const& nome_do_produto, int const quantidade)
{
assert(cumpreInvariante());
assert(0 <= quantidade and quantidade <= quantidadeDe(nome_do_produto));
int quantidade_por_remover = quantidade;
while(quantidade_por_remover != 0)
if(lotes[i].nome() == nome_do_produto) {
int quantidade_a_remover =
min(lotes[i].quantidade(), quantidade_por_remover);
quantidade_por_remover -= quantidade_a_remover;
lotes[i].retira(quantidade_a_remover);
}
purgaLotesVazios();
assert(cumpreInvariante());
}
void Inventario::mostra() const
{
assert(cumpreInvariante());
for(vector<Lote>::size_type i = 0; i != lotes.size(); ++i)
lotes[i].mostra();
}
void Inventario::purgaLotesVazios()
{
int j = 0;
for(vector<Lote>::size_type i = 0; i != lotes.size(); ++i)
if(lotes[i].quantidade() != 0)
lotes[j++] = lotes[i];
lotes.erase(lotes.begin() + j, lotes.end());
}
bool Inventario::cumpreInvariante() const
{
for(vector<Lote>::size_type i = 0; i != lotes.size(); ++i)
if(lotes[i].quantidade() <= 0)
return false;
return true;
}
int main()
{
Inventario inventario;
while(true) {
cout << endl
<< "1. Entrada de um lote" << endl
<< "2. Saída de produto" << endl
<< "3. Mostra valor dos produtos em stock" << endl
<< "4. Mostra inventário" << endl
<< endl
<< "0. Terminar" << endl
<< endl
<< "Opção: ";
int opcao;
cin >> opcao;
switch(opcao) {
case 0:
cout << "Até breve." << endl;
return 0;
case 1: {
cout << "Nome do produto: ";
string nome;
cin >> nome;
cout << "Quantidade: ";
int quantidade;
cin >> quantidade;
cout << "Preço unitário: ";
double preco;
cin >> preco;
inventario.adiciona(Lote(nome, quantidade, preco));
break;
}
case 2: {
cout << "Nome do produto: ";
string nome;
cin >> nome;
if(inventario.contemProdutoComNome(nome)) {
cout << "Quantidade: ";
int quantidade;
cin >> quantidade;
if(inventario.quantidadeDe(nome) >= quantidade) {
cout << "O custo da saída é "
<< inventario.custoDeSaidaDe(nome, quantidade) << endl;
inventario.remove(nome, quantidade);
} else
cout << "Não existem " << quantidade
<< " unidades disponíveis de " << nome << endl;
} else
cout << "Não exite o produto " << nome << " em stock." << endl;
break;
}
case 3:
cout << endl
<< "O valor dos produtos em stock é "
<< inventario.valor() << '.'
<< endl;
break;
case 4:
inventario.mostra();
break;
default:
cout << "Opção inválida!" << endl;
}
}
}
Questão 3
Com a entrada do euro em circulação, a necessidade de realizar conversões de valores entre unidades monetárias generalizou-se. O nosso objectivo é simplificar o trabalho ao grande número de pessoas que ainda necessitam de realizar conversões para melhor compreender o real valor dos bens e serviços.
Defina uma classe
Conversor
que permita converter valores, dada a taxa de conversão.
Deve definir a classe e os seguintes métodos:
Conversor::Conversor(double const taxa_de_conversão, int const
precisão = 2)
que
constrói um conversor com taxa de conversão taxa_de_conversão
e precisão precisão
.
vector
<double> Conversor::conversãoDe(vector<double>
const& valores) const
que
devolve a conversão do vector valores
.
void Conversor::mostraTabela(double const valor_inicial, double const
valor_final, double const incremento) const
que exibe no ecrã uma tabela de
conversão de valor_inicial
a valor_final
(inclusive) com
incrementos de incremento
. void Conversor::mudaPrecisãoPara(int const precisão)
que
permite alterar o valor da precisão. e a função
double arredondamentoDe(double const valor, int const precisão)
,
sabendo que double Conversor::conversãoDe(double const valor) const
definido
como
double Conversor::conversãoDe(double const valor) const
{
return arredondamentoDe(valor * taxa_de_conversão,
precisão_);
}
devolve a conversão do valor valor
.
de modo a que o seguinte código seja válido:
Conversor conversor(200.482);
Aparece 200.48
cout << conversor.conversaoDe(1) << endl; //
//
Note que .48 aparece porque a precisão é 2Aparece 401
conversor.estabelecePrecisão(0);
cout << conversor.conversaoDe(2) << endl; //
//
Note que não aparece parte decimal porque a precisão é 0
Caso seja necessário pode usar a função double pow(double base, int
expoente)
para calcular potências.
[cotação: 3,5]
#include <iostream>
Devolve o valor
#include <iomanip>
#include <cmath>
#include <vector>
using namespace std;
/**valor
recebido como argumento, arredondado com precisãoprecisao
.
@pre 0 <=
precisao
.@post
arredondamentoDe =
arredondamento devalor
com precisãoprecisao
.*/
Representa conversores entre unidades de medida.
double arredondamentoDe(double const valor, int const precisao)
{
if(valor < 0)
return ceil(valor * pow(10, precisao) - 0.5) / pow(10, precisao);
else
return floor(valor * pow(10, precisao) + 0.5) / pow(10, precisao);
}
/**
@invariant
taxa_de_conversao
<> 0 e 0 <=precisao_
.*/
Constrói um conversor.
class Conversor {
public:
/**
@pre
taxa_de_conversao <>
0 e 0 <=precisao
.@post
taxaDeConversao() = taxa_de_conversao
eprecisao() = precisao
.*/
Devolve a taxa de conversão.
Conversor(double const taxa_de_conversao, int const precisao = 2);
/**
@pre V.
@post
taxaDeConversao()
é a taxa de conversão do conversor.*/
Devolve a precisão do conversor.
double taxaDeConversao() const;
/**
@pre V.
é a precisão do conversor.
@post precisao()*/
Devolve a conversão do valor recebido como argumento.
int precisao() const;
/**
@pre V.
@post
conversaoDe = arredondamentoDe(valor
×taxaDeConversao(), precisao())
.*/
Devolve a conversão de todos os valores do vector recebido como argumento.
double conversaoDe(double const valor) const;
/**
@pre V.
@post
conversaoDe
.size
() =valores
.size
() e(Q j : 0 <= j <
valores
.size
() :conversaoDe
[j] =
arredondamentoDe(valores
[j] ×taxaDeConversao(), precisao())
)*/
Estabelece a precisão do arredondamento na conversão.
vector<double> conversaoDe(vector<double> const& valores) const;
/**
@pre 0 <=
precisao
.@post
precisao
() =precisao
.*/
Mostra no ecrã uma tabela de conversão.
void mudaPrecisaoPara(int const precisao);
/**@pre (
inicio
<=fim
e 0 <incremento
) ou (fim
<=inicio
eincremento
< 0) ou
(
inicio
=fim
eincremento
= 0).@post
¬canal
ou o ecrã contém uma tabela de conversão com início eminicio
, fim emfim
e
com incrementos deincremento
.*/
Devolve verdadeiro se o invariante se verificar.
void mostraTabela(double const inicio, double const fim, double const incremento) const;
private:
double const taxa_de_conversao;
int precisao_;
/**@pre V.
@post
cumpreInvariante =
(taxa_de_conversao <>
0 eprecisao_ >=
0).*/
bool cumpreInvariante() const;
};
Conversor::Conversor(double const taxa_de_conversao, int const precisao)
: taxa_de_conversao(taxa_de_conversao), precisao_(precisao)
{
assert(cumpreInvariante());
}
double Conversor::taxaDeConversao() const
{
assert(cumpreInvariante());
return taxa_de_conversao;
}
int Conversor::precisao() const
{
assert(cumpreInvariante());
return precisao_;
}
double Conversor::conversaoDe(double const valor) const
{
assert(cumpreInvariante());
return arredondamentoDe(valor * taxa_de_conversao, precisao_);
}
vector<double> Conversor::conversaoDe(vector<double> const& valores) const
{
assert(cumpreInvariante());
vector<double> valores_convertidos;
for(vector<double>::size_type i = 0; i != valores.size(); ++i)
valores_convertidos.push_back(conversaoDe(valores[i]));
return valores_convertidos;
}
void Conversor::mudaPrecisaoPara(int const precisao)
{
assert(cumpreInvariante());
assert(0 <= precisao);
precisao_ = precisao;
assert(cumpreInvariante());
}
void Conversor::mostraTabela(double const inicio, double const fim,
double const incremento) const
{
assert(cumpreInvariante());
assert(inicio <= fim and 0 < incremento or
fim <= inicio and incremento < 0 or
inicio == fim and incremento == 0);
if(incremento < 0)
for(double valor = inicio; fim <= valor; valor += incremento)
cout << setw(10) << valor << " <-> "
<< setw(10) << conversaoDe(valor) << endl;
else
for(double valor = inicio; valor <= fim; valor += incremento)
cout << setw(10) << valor << " <-> "
<< setw(10) << conversaoDe(valor) << endl;
}
bool Conversor::cumpreInvariante() const
{
return taxa_de_conversao != 0 and 0 <= precisao_;
}
Questão 4
Considere a função int índiceDoMáximoDe(vector<int> const& v) que devolve o índice do valor máximo que ocorre num vector:
int índiceDoPrimeiroMáximoDe(vector<int> const& v)
{
int índice_do_máximo = 0;
for(vector<int>::size_type i = 1; i != v.size(); ++i)
if(v[índice_do_máximo] < v[i])
índice_do_máximo = i;
return índice_do_máximo;
}
4.1 Indique a pré-condição (PC), a condição objectivo (CO), a condição invariante (CI) e a guarda (G) do ciclo necessário à construção desta função.
[cotação: 1]
PC: 1 <=
v
.size().
CO: 0 <=índiceDoPrimeiroMáximoDe
<v
.size() e
(Q j : 0 <= j <v
.size() :v
[j] <=v
[índiceDoPrimeiroMáximoDe
]) e
(Q j : 0 <= j <índiceDoPrimeiroMáximoDe
:v
[j] <v
[índiceDoPrimeiroMáximoDe
]).
CI: 0 <=índice_do_máximo
<i
e
(Q j : 0 <= j <i
:v
[j] <=v
[índice_do_máximo
]) e
(Q j : 0 <= j <índice_do_máximo
:v
[j] <v
[índice_do_máximo
]) e
0 <=i
<=v
.size().
G:i
<>v
.size().
4.2 Prove que o ciclo está correcto verificando que:
//
PC //
implica
CI.
//
G e CI //
implica
CI
//
CI e ¬G implica
CO.
Ver Secção 5.3.3 do Capítulo 5 as Folhas Teóricas.
[cotação: 1,5]
Questão 5
Explique resumida mas claramente os conceitos de abstracção e encapsulamento.
[cotação: 1]
R: Ver Secção 3.1 (Introdução à modularização) do Capítulo 3 das Folhas Teóricas.