Universidad de Costa Rica
Escuela de Ciencias de la
Computación e Informática
Profesor Adolfo Di Mare
CI-1402
I Semestre 1998
[<=] [home] [<>] [\/] [=>]
CI-1402 Organización de Lenguajes de Programación

Examen Final [solución]

      Duración: tres horas. Lea bien el examen antes de hacerlo. El examen es a libro abierto. Cuenta el buen estilo, la redacción y la ortografía. Puede hacer el examen con lápiz. ¡No haga más de lo que se le pide! ¡Conteste la primera pregunta, y dos de las otras preguntas, en cualquier orden! Use su lenguaje predilecto en cada pregunta.

1) [50 pts] STL + Herencia + polimorfismo

template <class T> class vector {
public:
    T* start; // Rep

    vector(int n)  { start = new T[n]; }
    ~vector()      { delete[] start;   }

    typedef  T* iterator;
    iterator begin()      { return start;   }
    iterator end()        { return start+n; }
    T& operator[] (int i) { return T[i];    }
};
class TMesa : public TAqui {
    int _p;  // # patas
    int _a;  // altura
    //  ...
}; // TMesa



class TSilla : public TAqui {
    int _r;  // ¿Respaldar?
    //  ...
}; // TMesa



class TRefri : public TAqui {
    int _c;  // capacidad
    //  ...
}; // TRefri
enum TLugar = {Cuarto, Cocina, Baño};
class TAqui {
    TLugar _v;
public:
    TAqui()  { _v = Cuarto; }
    ~TAqui() {}
    void traslade(TLugar d) { _v = d; }
}; // TAqui

Figura 1

      Considere las declaraciones que se muestran en la figura de arriba. Recuerde que el Rep de los iteradores que se usan para recorrer un vector es un puntero que tiene, entre otras, las siguientes operaciones:

operator!= () // Comparación
operator++ () // Avance al siguiente
operator*  () // Derreferencia

      La forma de crear un vector "v[]" de (punteros a) objetos para luego trasladarlos al baño usando el iterador "i" es la siguiente:

vector <TAqui*> v(3); // 3 elementos

v[0] = new TMesa;     // & mesa
v[1] = new TSilla;    // & silla
v[2] = new TRefri;    // & refri

vector::iterator i;
for (i = v.begin(); i != v.end(); i++) {
    *(*i).traslade(Baño);
}
Figura 2

1.a) [25 pts] Reescriba las clases de la Figura 1 y el programa de la Figura 2, pero no use plantillas. En otras palabras, lo que usted debe hacer es instanciar las plantillas para que el código C++ que resulta no contenga ninguna instrucción parametrizable. No olvide traducir la plantilla de la clase vector<>.

1.b) [25 pts] Compile el programa de la Figura 2 junto con las clases de la Figura 1, pero en lugar de producir código objeto Intel x86, emita código Pascal o C (no C++). No use las facilidades de programmación por objetos de Pascal, ni el macro procesador de C. Recuerde que debe desarrollar en línea las operaciones del vector y del iterador, y que debe instanciar la plantilla del vector adecuadamente.

2) [25 pts] Constructores y destructores

      En C++ es inválido invocar a un constructor usando un puntero a un método. En Turbo Pascal hay que usar programación de bajo nivel para lograrlo, lo que hace al programa no portable (recuerde el programa InitDone.pas que está en el enunciado de una de las tareas programadas que usted resolvió). Por eso conviene encontrar una forma de hacer esa tarea sin recurrir a trucos de bajo nivel. Primero considere la especificación de la operación que se muestra a continuación:

PROCEDURE TObj.Clone(    { EXPORT }     { ADH }
  {?} VAR p : PObj       { Dónde dejar el duplicado }
);
{ RESULTADO
  Crea en "p^" un duplicado del valor del objeto "SELF".
  - Si p=NIL entonces el espacio para almacenar al
    nuevo valor será tomado de la memoria dinámica.
  - De otra manera el valor anterior de "p^" se pierde.
  - "SELF" siempre mantiene su valor anterior.
  - Luego de la copia, cuando el valor de "p^" cambia,
    el de "SELF" no cambiará, y viceversa, pues la copia
    es una copia profunda; no es superficial.
  - Si "p = @SELF", entonces su valor no cambia. }
Figura 5: TObj.Clone(p)

2.a) [10 pts] Implemente la operación TObj.Clone(p) en Pascal (no use C++), pero no use trucos de bajo nivel. Use las operaciones TObj.Init() y TObj.Copy() para realizar su trabajo.

2.b) [5 pts] Defina la clase abstracta TObj, que incluye la operación polimórfica (VIRTUAL) Otro() que permita crear polimórficamente un nuevo objeto (Stroustrup les llama a estas operaciones constructores virtuales [Str­98]). Especifique e implemente su duplicador virtual.

2.c) [8 pts] Explique por qué es necesario redefinir el constructor virtual Otro() en cada clase derivada de TObj. No estará de más que incluya un pequeño ejemplo.

2.d) [2 pts] ¿Ocurre lo mismo con Clone()?

3) [25 pts] Programación Perl

      Haga un programa que lea un grupo de archivos ASCII para obtener de ellos las direcciones electrónicas de las solicitudes que haga. Los archivos contienen colecciones de mensajes de correo electrónico como las que se muestran en la siguiente figura:

From cyberteq3@mafalda.teletel.com.ar  Wed May 20 07:51:15 1998
Return-Path: <cyberteq3@mafalda.teletel.com.ar>
Received: from teletel.com.ar (200.10.110.101)
    by mail02.rapidsite.net (8.8.5/8.8.5) with SMTP id JAA03974
    for <ci1402@ecci.ac.cr>; Wed, 20 May 1998 09:50:40 -0400 (EDT)
Received: from pc3 by teletel.com.ar with smtp
    (Smail3.1.29.1 #2) id m0yc3eF-000sC; Wed, 20 May 98 10:50 GMT
Message-Id: <m0yc3eF-000gcsC@teletel.com.ar>
Comments: Authenticated sender is <cyberteq3@mail.teletel.com.ar>
From: Juan Ramos <cyberteq3@smail.teletel.com.ar>
To: ci1402@ecci.ac.cr
Date: Wed, 20 May 1998 10:57:43 +0000
MIME-Version: 1.0
Content-type: text/plain; charset=US-ASCII
Content-transfer-encoding: 7BIT
Subject: Carta al estudiante I-Sem-1995
Priority: normal
X-mailer: Pegasus Mail for Win32 (v2.53/R1)
X-Loop-Detect: 1
Status: RO
X-Status:

Quiero información sobre el curso para un estudio personal.

Figura 3

      El renglón From: aparece siempre antes del renglón Subject:, y contiene la dirección de correo electrónico a extraer. En el renglón Subject: viene la indicación de la información a extraer. Para este ejemplo, al procesar el archivo su programa debe extraer los siguientes datos:
      Juan Ramos <cyberteq3@smail.teletel.com.ar>
      http://www.ecci.ac.cr/~ci1402/1995-1

      Cada archivo a procesar contiene muchos mensajes. Su programa debe dejar en la salida estándar todas las parejas de renglones que extraiga. Sin embargo, cuide de evitar procesar renglones que no contengan la línea de Subject:.

  Diane Wood Sponheim <dsponhei@luthersem.edu> 
  http://www.ecci.ac.cr/~ci1402/1995-1

  Vary Blanco <Vary@hotmail.com>
  http://www.ecci.ac.cr/~ci1402/1997-2

  Concepcion Larios <concep@caribe.net>
  http://www.ecci.ac.cr/~ci1402/1995-2

  Asparagus Jovenus <beavis@hp9000.cpd.uva.es>
  http://www.ecci.ac.cr/~ci1402/1996-1

  Andres Rivera <arivera@quercus.inbio.ac.cr>
  http://www.ecci.ac.cr/~ci1402/1998-1

  Carolina Uribe <mcuribe@reymoreno.net.co>
  http://www.ecci.ac.cr/~ci1402/1993-3
Figura 4

4) [25 pts] Constructores y destructores

      El lenguaje C++ estándar no permite que el programador invoque un constructor sin al mismo tiempo crear una nueva instancia de una variable. Para Pascal tampoco hay una forma portable de hacerlo.

4.a) [10 pts] Defina el tipo TClonabe, en su lenguaje preferido, que incluye un método polimórfico Invoca_Constructor(), que se encarga de invocar al constructor de un objeto sin requerir la creación de una nueva instancia. Luego implemente el método Invoca_Constructor() usando el siguiente algoritmo (que fue mencionado en clase):

  1. Primero hay que contar con una variable "desde" del tipo a construir.
  2. Hay que contar con "pClonable", la dirección de memoria sobre la que se invocará al constructor.
  3. Luego hay que hacer una copia bit por bit desde la variable "desde" ya construida.
  4. Por último, hay que inicializar los campos de la variable a construir "*pClonable".

      Recuerde que para lograr su objetivo debe implementar el constructor de TClonable usando una pareja de métodos diferentes [TClonable.Init() y TClonable.Real_Init()], de manera que pueda invocarlos por separado.

4.b) [5 pts] Diga qué debe hacer el programador cliente del tipo TClonabe para invocar el constructor de un objeto usando la maquinaria de Invoca_Constructor().

4.c) [5 pts] Explique por qué Invoca_Constructor() funciona.

4.d) [5 pts] De un ejemplo de una aplicación en la que conviene que el programador pueda invocar al constructor de la forma en que lo ha hecho al contestar esta pregunta.

5) [25 pts] Recursividad

PROCEDURE BajeSuba( primero, n : INTEGER );
{ Como ejercicio, determine qué despliega
  este programa, y porqué lo hace.        }
BEGIN
  IF (0 < n) AND (n <= 10) THEN BEGIN
    INC(primero); DEC(n);
    WriteLn('':10-n, 'Pre[', primero:1,',', n:1,']' );
    BajeSuba( primero, n );
    WriteLn('':10-n, 'Pos[', primero:1,',', n:1,']' );
  END;
END;
Figura 6: BajeSuba()

5.a) [0 pts] Escoga dos valores para los argumentos "primero" y "n" del procedimiento BajeSuba(), que muestren cómo se realiza la recursividad.

5.b) [10 pts] Muestre la ejecución del procedimiento BajeSuba() para la primera pareja de argumentos que usted ha escogido. No olvide mostrar el estado de la pila de ejecución del programa. Asegúrese de que haya al menos tres llamados recursivos activos en algún momento.

5.c) [10 pts] Muestre la ejecución del procedimiento BajeSuba() para la segunda pareja de argumentos.

5.d) [5 pts] Use los ejemplos anteriores para explicar qué es recursividad. Redacte su respuesta de manera que la pueda entender un estudiante que recién toma su primer curso de programación.


[Str­98] Stroustrup, Bjarne: The C++ Programming Language, 3rd edition, ISBN 0­201­88954­4; Addison-Wesley, 1998.
      http://www.research.att.com/~bs/papers.html

[mailto:] Adolfo Di Mare <adolfo@di-mare.com>.
Copyright © 1998
Derechos de autor reservados © 1998
[home] <> [/\]