Programação Orientada para Objectos
IGE e ETI
2º semestre de 1999/2000
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.
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:
#include <iostream>
#include <cassert>using namespace std;
class Vector {
public:
typedef int Valor;Vector(int tamanho);
virtual ~Vector() { ... }int tamanho() const { return tamanho_; }
virtual Valor const& operator [] (int i) const = 0;
virtual Valor& operator [] (int i) = 0;protected:
virtual Valor& acede(int i) { return dados[i]; }private:
int tamanho_;
Valor* dados;
};inline Vector::Valor const& Vector::operator [] (int i) const {
return dados[i];
}Vector::Vector(int tamanho) : tamanho_(tamanho), dados(new Valor[tamanho]) {
assert(tamanho >= 0);
for(int i = 0; i != tamanho; ++i)
dados[i] = Valor();
}class VectorVerificado : public Vector {
public:
VectorVerificado(int tamanho) : Vector(tamanho) {}
virtual Valor const& operator [] (int i) const {
assert(0 <= i && i < tamanho());
return Vector::operator [] (i);
}
virtual Valor& operator [] (int i) {
assert(0 <= i && i < tamanho());
return acede(i);
}
};int main() {
...
}
F free(dados);
Esta versão só seria válida se a matriz dinâmica tivesse sido reservada com o velho malloc() do C.F delete[tamanho] dados;
Não é permitido indicar a dimensão da matriz no operador delete[]. A razão é simples: o sistema sabe essa dimensão (é usado um pequeno truque para guardar essa dimensão um pouco antes do início da matriz, num local invisível ao utilizador).F delete dados;
Como é uma matriz dinâmica (construída com o operador new[]), é necessário usar o operador delete[] para a destruir.F delete dados[];
É uma boa tentativa, mas a versão correcta sintacticamente é delete[] dados.[2 valores]
VectorVerificado* vv = new VectorVerificado(3);qual o resultado produzido pelo programa quando executado (apenas uma das respostas está correcta)?
Vector* v = vv;
vv[0] = 1;
vv[1] = 2;
vv[2] = 3;
cout << v[3];
delete v;
F Com sorte
o programa aborta e com azar escreve lixo no ecrã.
V O programa
aborta por uma das asserções falhar.
F O programa
escreve 3 no ecrã.
Como a função operator [] é virtual, é usada ligação dinâmica, ou seja, a versão da função executada é da classe VectorVerificado, cuja asserção falhará.[0,5 valores]
F Vector* v; v = new Vector(4);
A classe Vector é abstracta (tem duas funções puramente virtuais), pelo que não pode ser instanciada.F Vector* v; v = new VectorVerificado(3); cout << v->acede(1);
As duas primeiras instruções estão correctas. A terceira não está, pois tenta invocar uma função membro protegida. Aos membros protegidos de uma classe só podem aceder os membros da própria classe ou de classes derivadas.[1 valor]
class A {Suponha que a classe Vector começa com:
public:
A(int v) : valor(v) {}
friend ostream& operator << (ostream&, A const&);
private:
int valor = 1;
};inline ostream& operator << (ostream& saída, A const& a) {
return saída << a.valor;
}
class Vector {Que sucede quando se tenta compilar e executar o seguinte programa?
public:
typedef A Valor;
int main() {F Surge no ecrã 1.
VectorVerificado v(3);
cout << v[0] << endl;
}
O primeiro erro deve-se à obrigação de a inicialização das variáveis membro de instância ter de ser feita forçosamente nos construtores da classe. O segundo deve-se a que a classe A não tem construtor por omissão, necessário não só para construir cada um dos seus elementos, como porque o construtor por omissão é invocado explicitamente do lado direito da atribuição controlada pelo ciclo no corpo do construtor.[1,5 valores]
A classe deve ser preparada para poder ser derivada sem problemas.
A classe deve fornecer funções de inspecção para o nome, sexo, pai, mãe e filhos da pessoa.
Deve também fornecer um procedimento membro void mostra() const que escreve no ecrã o nome e sexo da pessoa.
Finalmente, deve fornecer as seguintes funções de verificação de grau de parentesco:
bool éDescendenteDe(Pessoa const* ascendente) const;Deve possuir um construtor que serve não apenas para inicializar o nome e sexo de uma nova pessoa, mas também para indicar quem são os seus pais (afinal, construir uma pessoa é concebê-la). Os parâmetros usados para indicar os pais da nova pessoa devem ter valor por omissão 0. A utilização de 0 no valor dos ponteiros para um qualquer dos pais significa que ele não é conhecido ou relevante para o problema em causa.
bool éAscendenteDe(Pessoa const* descendente) const;
bool éParenteDe(Pessoa const* pessoa) const;
Assuma definido o tipo enumerado Sexo:
enum Sexo {masculino, feminino};Tenha o cuidado de indicar claramente os métodos que não alteram a instância implícita.
Nesta alínea não é necessário definir nenhum dos métodos (funções ou procedimentos membro) da classe.
[1 valor]
O construtor serve não apenas para inicializar o nome e sexo de uma nova pessoa, mas também para indicar quem são os seus pais. Os parâmetros usados para indicar os pais da nova pessoa devem ter valor por omissão 0. A utilização de 0 no valor dos ponteiros para um qualquer dos pais significa que ele não é conhecido ou relevante para o problema em causa. Por cada pai especificado (não 0), deve ser verificado o respectivo sexo. O programa aborta se os sexos estiverem errados.
É muito importante que o construtor da nova pessoa registe essa mesma pessoa como filha de cada um dos pais especificados!
[1 valor]
Defina também a função bool éAscendenteDe(Pessoa const* descendente) const. Recorde-se que A é ascendente de B se B for descendente de A. Recorra a essa informação para escrever esta função à custa de uma simples chamada da função anterior.
Tenha cuidado porque as pessoas em causa podem não ter algum (ou nenhum) dos pais especificados. Nesse caso considere que a pessoa foi concebida por partenogénese ou "geração espontânea" :-)
[2 valores]
class Coisa {Defina totalmente uma classe Prenda para representar prendas. Uma prenda é uma coisa. Além do nome, as prendas têm um valor pecuniário e um valor simbólico (em unidade indefinidas, mas representadas por double). Além disso, as prendas têm associada uma pessoa que as ofereceu (ponteiro para a classe Pessoa). A classe, para além do construtor (que inicializa o nome, dador e valores de uma nova prenda), deve possuir inspectores para os dois valores e um procedimento mostra() que, para além de mostrar o nome da prenda, indique os seus dois valores da prenda e o nome da pessoa que a deu.
public:
Coisa(std::string const& nome)
: nome_(nome) {
}
virtual ~Coisa() {}
std::string const& nome() const;
return nome_;
}
virtual void mostra() const {
std::cout << nome() << std::endl;
}
private:
std::string nome_;
};
Tenha o cuidado de indicar claramente os métodos que não alteram a instância implícita.
[1 valor]
A classe Festa representa um jantar-festa. Cada festa tem um conjunto de participantes, que podem ser divididos em anfitriões e convidados. Cada festa tem também um nome (e.g., "Anos do Manel"), um número de convidados objectivo (e.g., 20) e um custo (em unidade indefinidas, mas representadas por double). Quando uma festa é construída, ainda não tem quaisquer anfitriões ou convidados.
Deve ser possível realizar as seguintes operações com uma festa:
A classe Festa deve guardar as listas de:
A classe abstracta Participante representa um participante na festa. Um participante é uma pessoa. Além disso, cada participante deve saber a festa em que participa (ponteiro para a festa) e se está ou não sentado à mesa. Deve ser possível realizar as seguintes operações com um participante:
Quando se constrói um anfitrião, este introduz-se imediatamente (e automaticamente) na festa, invocando no seu construtor o método da festa que introduz um anfitrião.
Um convidado é um tipo específico de participante na festa. Os convidados, para além daquilo que qualquer participante guarda, guardam um ponteiro para uma prenda a entregar na festa. Essa prenda é construída (comprada...) quando o convidado é construído. Quando se ordena a um convidado que se sente, este só o faz se todos os anfitriãos da festa estiverem já sentados. Deve ser possível realizar as seguintes operações adicionais com um convidado:
Tenha o cuidado de indicar claramente os métodos que não alteram a instância implícita em todas as classes.
Nesta alínea não é necessário definir nenhum dos métodos (funções ou procedimentos membro) da classe.
[3 valores]
[1,5 valores]
Apresenta-se a solução completa com todos os métodos definidos e dividida em módulos físicos. A negrito a parte correspondente às respostas ao enunciado:
coisa.H
#ifndef COISA_Hprenda.H
#define COISA_H#include <string>
#include <iostream>// Classe Coisa:
class Coisa {
public:
Coisa(std::string const& nome);
virtual ~Coisa() {}
std::string const& nome() const;
virtual void mostra() const;private:
std::string nome_;
};inline Coisa::Coisa(std::string const& nome)
: nome_(nome) {
}inline std::string const& Coisa::nome() const {
return nome_;
}inline void Coisa::mostra() const {
std::cout << nome() << std::endl;
}#endif // COISA_H
#ifndef PRENDA_Hpessoa.H
#define PRENDA_H#include <string>
#include <iostream>#include "coisa.H"
// Classe Prenda:
class Prenda : public Coisa {
public:
Prenda(std::string const& nome, Pessoa const* dador,
double valor_sentimental, double valor_pecuniario);
double valorSentimental() const;
double valorPecuniario() const;
void mostra() const;private:
Pessoa const* dador;
double valor_sentimental;
double valor_pecuniario;
};inline Prenda::Prenda(std::string const& nome, Pessoa const* dador,
double valor_sentimental,
double valor_pecuniario)
: Coisa(nome), dador(dador),
valor_sentimental(valor_sentimental),
valor_pecuniario(valor_pecuniario) {
assert(valor_sentimental >= 0 && valor_pecuniario >= 0);
}inline double Prenda::valorSentimental() const {
return valor_sentimental;
}inline double Prenda::valorPecuniario() const {
return valor_pecuniario;
}inline void Prenda::mostra() const {
Coisa::mostra();
std::cout << "Valor sentimental: " << valorSentimental() << std::endl
<< "Valor pecuniario: " << valorPecuniario() << std::endl
<< "Oferecida por: " << dador->nome() << std::endl;
}#endif // PRENDA
#ifndef PESSOA_Hpessoa.C
#define PESSOA_H#include <iostream>
#include <list>
#include <string>enum Sexo {feminino, masculino};
class Pessoa {
public:
Pessoa(std::string const& nome, Sexo sexo,
Pessoa* pai = 0, Pessoa* mae = 0);
virtual ~Pessoa() {}std::string const& nome() const;
Sexo sexo() const;
Pessoa const* pai() const;
Pessoa const* mae() const;
std::list<Pessoa const*> const& filhos() const;virtual void mostra() const;
void mostraDescendencia() const;
void mostraAscendencia() const;bool eDescendenteDe(Pessoa const* ascendente) const;
bool eAscendenteDe(Pessoa const* descendente) const;
bool eParenteDe(Pessoa const* outra) const;private:
std::string nome_;
Sexo sexo_;
Pessoa const* const pai_;
Pessoa const* const mae_;
std::list<Pessoa const*> filhos_;
};inline Pessoa::Pessoa(std::string const& nome, Sexo sexo,
Pessoa* pai, Pessoa* mae)
: nome_(nome), sexo_(sexo), pai_(pai), mae_(mae) {
assert((pai == 0 || pai_->sexo() == masculino) &&
(mae == 0 || mae_->sexo() == feminino));
if(pai != 0)
pai->filhos_.push_back(this);
if(mae != 0)
mae->filhos_.push_back(this);
}inline std::string const& Pessoa::nome() const {
return nome_;
}inline Sexo Pessoa::sexo() const {
return sexo_;
}inline Pessoa const* Pessoa::pai() const {
return pai_;
}inline Pessoa const* Pessoa::mae() const {
return mae_;
}inline std::list<Pessoa const*> const& Pessoa::filhos() const {
return filhos_;
}inline void Pessoa::mostra() const {
cout << nome_ << " (" << (sexo_ == masculino? "homem" : "mulher")
<< ')' << endl;
}#endif // PESSOA_H
#include "pessoa.H"festa.Husing namespace std;
void Pessoa::mostraDescendencia() const {
for(list<Pessoa*>::const_iterator i = filhos_.begin();
i != filhos_.end(); ++i) {
(*i)->mostra();
(*i)->mostraDescendencia();
}
}void Pessoa::mostraAscendencia() const {
if(pai_ != 0) {
pai_->mostra();
pai_->mostraAscendencia();
}
if(mae_ != 0) {
mae_->mostra();
mae_->mostraAscendencia();
}
}bool Pessoa::eDescendenteDe(Pessoa const* ascendente) const {
if(pai_ != 0 &&
(pai_ == ascendente || pai_->eDescendenteDe(ascendente)))
return true;
if(mae_ != 0 &&
(mae_ == ascendente || mae_->eDescendenteDe(ascendente)))
return true;
return false;
}bool Pessoa::eAscendenteDe(Pessoa const* descendente) const {
return descendente->eDescenteDe(this)
}bool Pessoa::eParenteDe(Pessoa const* outra) const {
if(this == outra || this->eAscendenteDe(outra))
return true;
if(pai_ != 0 && pai_->eParenteDe(outra))
return true;
if(mae_ != 0 && mae_->eParenteDe(outra))
return true;
return false;
}
#ifndef FESTA_Hfesta.C
#define FESTA_H#include <string>
#include <list>#include "pessoa.H"
#include "prenda.H"// Classe Festa:
class Festa {
public:
// A solução com classes embutidas não era importante.
class Participante;
class Anfitriao;
class Convidado;Festa(std::string const& nome, int convidados, double custo);
~Festa();std::string nome() const;
bool convidadosChegaram() const;
bool anfitrioesSentados() const;
double valor() const;
void mostra() const;void novoAnfitriao(Anfitriao* anfitriao);
void recebe(Convidado* convidado);
void senta();
private:
std::list<Participante*> participantes;
std::list<Anfitriao*> anfitrioes;
std::list<Convidado*> convidados;
std::list<Prenda*> prendas;
std::string nome_;
int numero_de_convidados_a_chegar;
double custo;
};class Festa::Participante : public Pessoa {
public:
Participante(Festa* festa, std::string const& nome, Sexo sexo,
Pessoa* pai = 0, Pessoa* mae = 0);
virtual ~Participante() {}Festa const* festa() const;
Festa* festa();
bool sentado() const;virtual void senta() = 0;
private:
Festa* festa_;
bool sentado_;
};class Festa::Anfitriao : public Festa::Participante {
public:
Anfitriao(Festa* festa, std::string const& nome, Sexo sexo,
Pessoa* pai = 0, Pessoa* mae = 0);
~Anfitriao();virtual void mostra() const;
virtual void senta();
void guarda(Prenda* prenda);private:
std::list<Prenda*> prendas;
};class Festa::Convidado : public Festa::Participante {
public:
Convidado(Festa* festa, std::string const& nome, Sexo sexo,
Pessoa* pai = 0, Pessoa* mae = 0);
~Convidado();virtual void mostra() const;
bool temPrenda() const;Prenda* oferece();
virtual void senta();private:
Prenda* prenda;
};inline Festa::Festa(std::string const& nome, int convidados, double custo)
: nome_(nome), numero_de_convidados_a_chegar(convidados), custo(custo) {
assert(convidados >= 0);
}inline std::string Festa::nome() const {
return nome_;
}inline bool Festa::convidadosChegaram() const {
return numero_de_convidados_a_chegar == 0;
}inline void Festa::novoAnfitriao(Anfitriao* anfitriao) {
assert(anfitriao != 0);
anfitrioes.push_back(anfitriao);
participantes.push_back(anfitriao);
}inline Festa::Participante::Participante(Festa* festa,
std::string const& nome, Sexo sexo,
Pessoa* pai, Pessoa* mae)
: Pessoa(nome, sexo, pai, mae), festa_(festa), sentado_(false) {
assert(festa != 0);
}inline Festa const* Festa::Participante::festa() const {
return festa_;
}inline Festa* Festa::Participante::festa() {
return festa_;
}inline bool Festa::Participante::sentado() const {
return sentado_;
}inline void Festa::Participante::senta() {
sentado_ = true;
}inline Festa::Anfitriao::Anfitriao(Festa* festa,
std::string const& nome, Sexo sexo,
Pessoa* pai, Pessoa* mae)
: Participante(festa, nome, sexo, pai, mae) {
festa->novoAnfitriao(this);
}inline void Festa::Anfitriao::guarda(Prenda* prenda) {
assert(prenda != 0);
prendas.push_back(prenda);
}inline Festa::Convidado::Convidado(Festa* festa,
std::string const& nome, Sexo sexo,
Pessoa* pai, Pessoa* mae)
: Participante(festa, nome, sexo, pai, mae), prenda(prenda) {
prenda = new Prenda("Treta", this, rand() % 100, rand() % 100);
festa->recebe(this);
}inline Festa::Convidado::~Convidado() {
delete prenda;
}inline bool Festa::Convidado::temPrenda() const {
return prenda != 0;
}inline Prenda* Festa::Convidado::oferece() {
Prenda* p = prenda;
prenda = 0;
return p;
}#endif // FESTA
#include "festa.H"teste_festa.C#include <iostream>
using namespace std;
Festa::~Festa() {
if(anfitrioes.empty())
for(list<Prenda*>::iterator i = prendas.begin();
i != prendas.end(); ++i)
delete *i;
else {
list<Anfitriao*>::iterator ia = anfitrioes.begin();
for(list<Prenda*>::iterator ip = prendas.begin();
ip != prendas.end(); ++ip) {
(*ia)->guarda(*ip);
if(++ia == anfitrioes.end())
ia = anfitrioes.begin();
}
}
}bool Festa::anfitrioesSentados() const {
for(list<Anfitriao*>::const_iterator i = anfitrioes.begin();
i != anfitrioes.end(); ++i)
if(!(*i)->sentado())
return false;
return true;
}double Festa::valor() const {
double proveito = 0.0;
for(list<Prenda*>::const_iterator i = prendas.begin();
i != prendas.end(); ++i)
proveito += (*i)->valorPecuniario();
return proveito - custo;
}void Festa::recebe(Convidado* convidado) {
assert(convidado != 0);
if(numero_de_convidados_a_chegar != 0 && convidado->temPrenda()) {
prendas.push_back(convidado->oferece());
convidados.push_back(convidado);
participantes.push_back(convidado);
--numero_de_convidados_a_chegar;
}
}void Festa::senta() {
if(convidadosChegaram()) {
for(list<Anfitriao*>::iterator i = anfitrioes.begin();
i != anfitrioes.end(); ++i)
(*i)->senta();
for(list<Convidado*>::iterator i = convidados.begin();
i != convidados.end(); ++i)
(*i)->senta();
}
}void Festa::mostra() const {
cout << "Festa: " << nome() << endl
<< "Anfitriões: " << endl;
for(list<Anfitriao*>::const_iterator i = anfitrioes.begin();
i != anfitrioes.end(); ++i)
(*i)->mostra();
cout << "Convidados: " << endl;
for(list<Convidado*>::const_iterator i = convidados.begin();
i != convidados.end(); ++i)
(*i)->mostra();
if(numero_de_convidados_a_chegar != 0)
cout << "Ainda faltam " << numero_de_convidados_a_chegar
<< " convidados." << endl;
cout << "Prendas: " << endl;
for(list<Prenda*>::const_iterator i = prendas.begin();
i != prendas.end(); ++i)
(*i)->mostra();
cout << "Valor: " << valor() << endl;
}Festa::Anfitriao::~Anfitriao() {
for(list<Prenda*>::iterator i = prendas.begin();
i != prendas.end(); ++i)
delete *i;
}void Festa::Anfitriao::senta() {
if(festa()->convidadosChegaram())
Participante::senta();
else
cout << '[' << nome()
<< "] não me posso sentar porque faltam convidados."
<< endl;
}void Festa::Anfitriao::mostra() const {
Pessoa::mostra();
cout << "Prendas:" << endl;
for(list<Prenda*>::const_iterator i = prendas.begin();
i != prendas.end(); ++i)
(*i)->mostra();
}void Festa::Convidado::senta() {
if(festa()->anfitrioesSentados())
Participante::senta();
else
cout << '[' << nome()
<< "] não me posso sentar porque os "
<< "anfitriões estão em pé."
<< endl;
}void Festa::Convidado::mostra() const {
Pessoa::mostra();
if(prenda != 0) {
cout << "Prenda a dar:" << endl;
prenda->mostra();
}
}
#include "festa.H"using namespace std;
int main()
{
list<Festa::Anfitriao*> anfitrioes;
list<Festa::Convidado*> convidados;Festa* festa = new Festa("Anos do Zé", 5, 2000);
convidados.push_back(new Festa::Convidado(festa, "Ana", feminino));
convidados.push_back(new Festa::Convidado(festa, "Américo", masculino));
anfitrioes.push_back(new Festa::Anfitriao(festa, "Zé", masculino));
anfitrioes.push_back(new Festa::Anfitriao(festa, "Maria", feminino));
festa->senta();
anfitrioes.front()->senta();
convidados.front()->senta();
convidados.push_back(new Festa::Convidado(festa, "Anabela", feminino));
convidados.push_back(new Festa::Convidado(festa, "António", masculino));
convidados.push_back(new Festa::Convidado(festa, "Amaral", masculino));festa->mostra();
festa->senta();if(festa->valor() > 0)
cout << "Festa valeu a pena :-)" << endl;
else
cout << "Festa não valeu a pena :-(" << endl;delete festa;
for(list<Festa::Anfitriao*>::const_iterator i = anfitrioes.begin();
i != anfitrioes.end(); ++i)
(*i)->mostra();for(list<Festa::Anfitriao*>::const_iterator i = anfitrioes.begin();
i != anfitrioes.end(); ++i)
delete *i;for(list<Festa::Convidado*>::const_iterator i = convidados.begin();
i != convidados.end(); ++i)
delete *i;
}
struct Elo {usada para representar os elos de uma cadeia simplesmente ligada com a particularidade de ser circular, i.e., o elo seguinte do último elo da cadeia é o primeiro elo da cadeia. A cadeia não tem guardas.
typedef int Item;Item item;
Elo* seguinte;
Elo(Item const& item, Elo* seguinte = 0) : item(item), seguinte(seguinte) {
}
};
Defina um procedimento void inverte(Elo*& último) que inverta a ordem dos elos de uma cadeia simplesmente ligada, circular e sem guardas cujo último elo é apontado pelo ponteiro último. Note que quando a cadeia está vazia o ponteiro para o último elemento tem o valor 0. Note também que em geral o último elo da cadeia passa a ser o que antes era o primeiro.
Faça diagramas da cadeia em várias situações! Só assim resolverá com sucesso esta alínea!
Apresenta-se uma solução completa incluindo programa de teste. A negrito as partes pedidas no exercício:[2 valores]#include <iostream>
using namespace std;
struct Elo {
typedef int Item;Item item;
Elo* seguinte;
Elo(Item const& item, Elo* seguinte = 0) : item(item), seguinte(seguinte) {
}
};void poeInicio(Elo*& ultimo, Elo::Item const& item) {
if(ultimo == 0) {
ultimo = new Elo(item);
ultimo->seguinte = ultimo;
} else
ultimo->seguinte = new Elo(item, ultimo->seguinte);
}void inverte(Elo*& ultimo) {
if(ultimo != 0) {
Elo* anterior = ultimo;
Elo* e = ultimo->seguinte;
while(e != ultimo) {
Elo* seguinte = e->seguinte;
e->seguinte = anterior;
anterior = e;
e = seguinte;
}
ultimo = ultimo->seguinte;
e->seguinte = anterior;
}
}void mostra(Elo const* ultimo) {
cout << '(';
if(ultimo != 0) {
for(Elo const* e = ultimo->seguinte; e != ultimo; e = e->seguinte)
cout << e->item << ", ";
cout << ultimo->item;
}
cout << ')' << endl;
}int main() {
Elo* ultimo = 0;
mostra(ultimo);
inverte(ultimo);
mostra(ultimo);
inverte(ultimo);poeInicio(ultimo, 1);
mostra(ultimo);
inverte(ultimo);
mostra(ultimo);
inverte(ultimo);poeInicio(ultimo, 2);
mostra(ultimo);
inverte(ultimo);
mostra(ultimo);
inverte(ultimo);poeInicio(ultimo, 3);
mostra(ultimo);
inverte(ultimo);
mostra(ultimo);
inverte(ultimo);poeInicio(ultimo, 4);
mostra(ultimo);
inverte(ultimo);
mostra(ultimo);
inverte(ultimo);poeInicio(ultimo, 5);
mostra(ultimo);
inverte(ultimo);
mostra(ultimo);
inverte(ultimo);poeInicio(ultimo, 6);
mostra(ultimo);
inverte(ultimo);
mostra(ultimo);
inverte(ultimo);
}
#include <iostream>[2 valores]using namespace std;
// Procedimento que descarta todos os caracteres lidos do teclado até ao primeiro
// fim-de-linha encontrado:
void ignora() {
char c;
while(cin.get(c) && c != '\n')
;
}class Vector {
public:
Vector() : x_(0.0), y_(0.0), z_(0.0) {}
Vector(double x, double y, double z) : x_(x), y_(y), z_(z) {}double x() const { return x_; }
double y() const { return y_; }
double z() const { return z_; }Vector& operator += (Vector const& v) {
x_ += v.x_; y_ += v.y_; z_ += v.z_;
return *this;
}class ErroAoCarregar {};
// Carrega as coordenadas do vector a partir do canal entrada. Em caso de
// erro lança a excepção ErroAoCarregar e mantém o valor original do vector
// intacto!
void carrega(istream& entrada);// Lê do teclado as coordenadas. Se tudo correr bem devolve true. Se a
// leitura falhar devolve false e mantém o valor original do vector intacto!
bool le();// Lê do teclado as coordenadas, depois de as pedir. Em caso de erro
// avisa o utilizador e pede para ele introduzir de novo ignorando toda a
// linha. Só termina depois de lidas com sucesso as três coordenadas.
void leInteractivo();private:
double x_, y_, z_;
};Vector operator + (Vector a, Vector const& b) {
return a += b;
}void Vector::carrega(istream& entrada) {
double x, y;
if(!(entrada >> x >> y >> z_))
throw ErroAoCarregar();
x_ = x;
y_ = y;
}bool Vector::le() {
double x, y;
if(!(cin >> x >> y >> z_))
return false;
x_ = x;
y_ = y;
return true;
}void Vector::leInteractivo() {
while(true) {
cout << "Introduza três coordenadas: ";
if(cin >> x_ >> y_ >> z_)
return;
cout << "Coordenadas inválidas!" << endl;
// Limpar condição de erro:
cin.clear();
// Ignorar caracteres até ao fim da linha:
ignora();
}
}
O que distingue um método normal de um nétodo virtual é que para um método normal não podem ser fornecidas especializações enquanto para um método virtual podem. I.e., se numa classe derivada se redefinir o método, no primeiro caso oculta-se simplesmente o método de igual assinatura da classe base e no segundo sobrepõe-se-lhe uma especialização. O método normal será invocado usando ligação estática enquanto o método virtual será invocado usando ligação dinâmica. Ou seja, o método a invocar através de um ponteiro ou referência será no primeiro caso determinado pelo tipo do ponteiro ou referência e no segundo pelo tipo do objecto apontado ou referenciado.[1 valor]Um método abstracto é um método virtual que não necessita ser definido. Tem como consequência tornar a classe abstracta (i.e., que não se pode instanciar). Outra consequência é obrigar as classe derivadas que se queiram concretas a fornecerem uma definição para esse método.