Recibo do exame de 1ª época de Programação Orientada para Objectos (IGE e ETI), 2º semestre de 1999/2000, ISCTE:
Nome do aluno: _______________________________________________
Número do aluno:  ______________________
Assinatura do docente: ________________________________________

Identificação

Nome do aluno: _______________________________________________

Número do aluno:  ______________________

Turma: ____________

Exame de 1 ª época

Programação Orientada para Objectos

IGE e ETI

2º semestre de 1999/2000

ISCTE


Notas:

Questão 1
Assinale com V (Verdadeiro) as expressões que estão correctas e com F (Falso) as que estão incorrectas.

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>
using namespace std;

class A {
  public:
    A(int a, int b = 0)
        : a(a + b) {
    }
    int h() const { return a; }

  protected:
    int a;
};

class B : public A {
  public:
    B(int a) : A(2*a) { ba = new A(a); }
    virtual int h() const { return 2*a; }
    virtual ~B() {
        f();
        delete ba;
    }
    int g();

  private:
    A* ba;
    void f() const {
        cout << ba->h() << endl;
    }
};

int main()
{
    ...
}

Questão 1.1
Quais das seguintes instruções estão correctas?

__ A a(7, 0);
__ A* a = new a(3);
__ B* b = new B();

[1,5 valores]

Questão 1.2
Sendo a função main()
B* b = new B(1);
A* a = b;
cout << " " << b->h() << " " << a->h() << " ";
delete b;
qual o resultado produzido pelo programa (apenas uma das respostas está correcta)?  Atenção aos procedimentos virtuais!

__  4 2 1
__  4 4 1
__  4 2 2

[0,5 valores]

Questão 1.3
Quais das seguintes sequências de instruções estão correctas?

__ A a(5); a.a = 3;
__ B* b(1); cout << b->h();

[1 valor]

Questão 1.4
Assuma que as seguintes instruções são dadas dentro da função int B::g() (membro da classe B).  Quais delas estão correctas?

__ A* p = ba;
__ int& r = a;
__ int* pi = &a;
__ A** pp = &ba;

[2 valores]

Questão 2
Num centro de investigação linguística tenciona-se usar um programa de computador para classificar textos que se encontram disponíveis para estudo de fenómenos da Língua Portuguesa.

Pretende-se para isso desenvolver uma hierarquia de classes que represente os vários tipos de textos disponíveis: textos literários, científicos e jornalísticos.

No topo da hierarquia está a classe abstracta TextoEmProsa:

class TextoEmProsa {
  public:
    TextoEmProsa(std::string const& título, std::string const& autor,
          int const número_de_palavras, int const número_de_frases,
          int const número_de_parágrafos)
        : título_(título), autor_(autor),
          número_de_palavras(número_de_palavras),
          número_de_frases(número_de_frases),
          número_de_parágrafos(número_de_parágrafos) {
    }
    TextoEmProsa(std::istream& entrada);
    virtual ~TextoEmProsa() {}

    // Devolve o tipo do texto (literário, científico ou jornalístico):
    virtual string tipo() const = 0;

    // Facilidade de leitura do texto:
    virtual double legibilidade() const {
        return double(número_de_palavras)/número_de_frases;
    }

    // Funções de inspecção:
    std::string const& título() const {
        return título_;
    }
    std::string const& autor() const {
        return autor_;
    }
    int númeroDePalavras() const {
        return número_de_palavras;
    }
    int númeroDeFrases() const {
        return número_de_frases;
    }
    int númeroDeParágrafos() const {
        return número_de_parágrafos;
    }
    // Mostra no ecrã o que é comum a todos os TextoEmProsa:
    virtual void mostra() const;
 
 

    // Carrega do canal entrada o que é comum a todos os TextoEmProsa:
    virtual void carrega(std::istream& entrada);

    // Guarda no canal saida o que é comum a todos os TextoEmProsa:
    virtual void guarda(std::ostream& saida) const;

  private:
    std::string título_;
    std::string autor_;
    int número_de_palavras;
    int número_de_frases;
    int número_de_parágrafos;
};

Assuma que o construtor TextoEmProsa(std:::istream& entrada) e os procedimentos mostra(), carrega() e guarda() estão já definidos algures.
Questão 2.1
Defina completamente a classe TextoCientífico que é um texto em prosa e contém a seguinte informação: Esta classe deve dispor de funções inspectoras para a área científica, o número de equações e o título da publicação, e um procedimento modificador para a área científica (caso seja necessário reclassificar o texto).  Devem ainda existir as funções e os procedimentos comuns a todos os textos em prosa.  O tipo de um texto científico é "TextoCientífico".

O índice de legibilidade de um texto científico é dado pelo número médio de equações por parágrafo.

Defina todos os procedimentos e funções da classe TextoCientífico, excepto o construtor que recebe um canal de entrada (istream).

Defina também as classes TextoLiterário e TextoJornalístico, mas não especifique os seus membros, ou seja, não inclua nada entre {}.  Explicite apenas se derivam de alguma outra classe.  I.e., use o formato:

class B /* aqui deve especificar as heranças, se existirem. */ {
    // Aqui não ponha nada!
};
[1,5 valores]
Questão 2.2
Uma editora posteriormente disponibiliza novos textos, entre os quais se encontravam textos em verso, pelo que  é necessário alterar a hierarquia previamente definida.

Assim, deve ser introduzida uma nova classe abstracta Texto que representa qualquer tipo de texto.  Deve ser ainda criada uma nova classe concreta que represente os novos textos em verso, sabendo que tanto os textos em verso, como os textos em prosa são textos.

Os textos em verso contêm o título, o autor, o número de palavras e o número de estrofes, e dispõem das respectivas funções de inspecção.  O índice de legibilidade de um texto poético é 0 e o tipo é "TextoEmVerso".

Reestruture a hierarquia de classes de modo a acomodar estas alterações.  A classe texto deve ser uma generalização dos textos em prosa e poéticos.  Todas as classes desta hierarquia devem possuir um construtor a partir de um canal de entrada.  Defina todas as classes, mas não defina nenhum dos métodos.

Tal como na alínea anterior, não especifique os membros das classes TextoLiterário e TextoJornalístico.

[2 valores]

Questão 2.3
Durante a execução do programa é possível realizar as seguintes operações com a colecção de textos: Defina a classe ColecçãoDeTextos que contém uma lista de ponteiros para os textos que o compõem.  Esta classe deve dispor de funções e procedimentos que realizem as operações permitidas às colecções de texto (referidas acima). Deve ainda existir um destrutor, que será responsável pela destruição das instâncias de classes concretas derivadas da classe Texto para as quais o itens da lista apontam.

Para definir a lista pode usar qualquer das possibilidades referidas durante as aulas: list<Texto*>, ListaPonteiroTexto ou Lista<Texto*>.

Não é necessário implementar nenhum dos métodos nesta alínea.

[1 valor]

Questão 2.4
Defina o destrutor da classe ColecçãoDeTextos.

[1 valor]

Questão 2.5
Defina o procedimento membro da classe ColecçãoDeTextos que remove um texto da colecção, dado o seu título.  Não deve abortar o programa em nenhuma circunstância.  No caso de não existir nenhum texto com o título dado o procedimento não faz nada.

[1,5 valores]

Questão 2.6
Defina a função membro da classe ColecçãoDeTextos que calcula o índice médio de legibilidade da colecção.

[1 valor]

Questão 2.7
Defina o procedimento membro da classe ColecçãoDeTextos que lê textos a partir de um canal.  Admita que os textos lidos têm todos títulos diferentes.

Os dados lidos do canal têm o seguinte formato:

número_de_textos
tipo_do_primeiro_texto
... informação do primeiro texto
tipo_do_segundo_texto
... informação do segundo texto
...
tipo_do_último_texto
... informação do último texto
[1,5 valores]
Questão 2.8
Defina o procedimento membro da classe ColecçãoDeTextos que guarda uma colecção num canal (no formato da alínea anterior).

[1 valor]

Questão 3
Considere a seguinte estrutura
struct Elo {
    typedef int Item;

    Item item;
    Elo* anterior;
    Elo* seguinte;
};

usada para representar os elos de uma cadeia duplamente ligada com a particularidade de ser circular, i.e., o elo seguinte do último elo da cadeia é o primeiro elo da cadeia e o elo anterior do primeiro elo da cadeia é o último elo da cadeia.  A cadeia não tem guardas.

Considere que existe um procedimento

inline void troca(Elo*& a, Elo*& b) {
    Elo* aux = a;
    a = b;
    b = aux;
}
que troca dois ponteiros para Elo.

Defina um procedimento void inverte(Elo*& primeiro) que inverta a ordem dos elos de uma cadeia duplamente ligada e circular cujo primeiro elo é apontado pelo ponteiro primeiro.  Note que quando a cadeia está vazia o ponteiro para o primeiro elemento tem o valor 0.  Note também que em geral o primeiro elo da cadeia passa a ser o que antes era o último.

Faça desenhos da cadeia em várias situações!  Só assim resolverá com sucesso esta alínea!

[1,5 valores]

Questão 4
Considere a seguinte definição de uma pilha de inteiros:
class PilhaInt {
  public:
    typedef int Item;

    PilhaInt(int tamanho_inicial = tamanho_minimo);  // construtor da classe.
    PilhaInt(PilhaInt const& p);                     // construtor por cópia da classe.
    ~PilhaInt();                                     // destrutor da classe.

    PilhaInt& operator = (PilhaInt const& p);        // atribuição por cópia da classe.

    ...

    bool vazia() const;         // devolve true sse a pilha estiver vazia.
    bool cheia() const;         // devolve true sse a pilha estiver cheia.
    int altura() const;         // devolve o número de itens na pilha.

    ...

 private:
    static int const tamanho_minimo = 32; // tamanho mínimo da matriz (tem de ser > 0).

    mutable int tamanho;        // tamanho corrente da matriz.
    int quantos;                // número de itens actualmente na pilha.
    mutable Item* itens;        // matriz dinâmica dos itens.
};

Defina a função bool PilhaInt::cheia() const.  Uma pilha está cheia quando não havendo mais elementos disponíveis na matriz dinâmica, se tenta duplicar o tamanho desta matriz e tal não é possível por ter sido lançada uma excepção.

Observação: a excepção lançada pelo operador new em caso de falta de memória é bad_alloc.  Mas é preferível lidar com o problema para qualquer excepção.

Defina as funções e procedimentos (membros ou não) que achar necessários.

[2 valores]

Questão 5
Defina (distinguindo) ligação estática de ligação dinâmica.  Relacione esta distinção com o conceito de polimorfismo.

[1 valor]