Examen Final - 75.42. Taller de programación I

Cátedra: Veiga
Fecha: 2do Cuatrimestre 2006
Día: 12/12/2006
Tema: 1

Esta página está incompleta; podés ayudar completando el material.

Enunciado

  1. Describa y ejemplifique el uso de las siguientes instrucciones de precompilación: #DEFINED, #IF#ELSE#ENDIF.
  2. Declare una clase que encapsule un Thread (MiThread). Implemente el método Ejecutar con código default para el thread y el método Detener que se encargue de parar el thread.
  3. ¿Para qué sirve las funciones virtuales puras? Ejemplifique.
  4. Escriba una rutina gráfica capaz de dibujar un rombo centrado en pantalla.
  5. Escribir un programa ANSI C que, sin crear archivos intermedios, altere el archivo 'a.txt' reemplazando todas las secuencias '' por '*', excepto que se encuentre entre comillas. - Escriba el .H de una bilbioteca de funciones ANSI C para manejar una pila. - Escriba una aplicación ANSI Cpp que tome dos strings por consola e imprima el segundo string sin las ocurrencias del primero. - Declare una clase NumBinario para encapsular un número de 7 bits. Incluya al menos: Constructor default, Constructor con valor deinicialización y Constructor de Copia; Operador <, ==, =, int y « (impresión). Implemente el operator+. - Haciendo uso de algunas declaraciones de clases y sin usar punteros, ejemplifique el uso de funciones virtuales. - Implementar una clase denominada UNIVERSO que contenga una función estática que informe la cantidad de instancias existentes de esa clase. ===== Resolución ===== ==== Punto I ==== #DEFINED: Esta macro es de tipo “booleana” y retorna “true” o “false” dependiendo de cómo se evaluá la expresión lógica que recibe como parámetro. La respuesta será obtenida aplicando lógica booleana sobre los parámetros, evaluando cada término como true (si el parámetro fue previamente definido mediante la macro #DEFINE) o false (si nunca fue definido, o si fue des-definido mediante #UNDEF) #IF#ELSE#ENDIF: Esta macro equivale a las estructuras de control condicionales de cualquier lenguaje de programación. Sólo la primera parte de la misma recibe parámetros (que será una expresión que retorne un valor booleano). En caso de que dicha expresión sea verdadera, se incluirá en el código a compilar todo auqello que se encuentre entre el final de la expresión y el comienzo del #ELSE (puede no requerirse un else, con lo que se incluirá hasta el comienzo del #ENDIF). En caso de que la expresión sea falsa, se incluirá lo que se encuentre entre el fin del #ELSE y el comienzo del #ENDIF (en caso de no existir sentencia else, directamente no se incluirá nada de lo que exista entre la expresión evaluada y el end). <code cpp> #DEFINE TESTING #IF DEFINED(TESTING) std::cout « “Just testing, not inserting in DB” « std::endl; #ELSE std::cout « “Do something to insert some value in DB” « std::endl; #ENDIF </code> De esta forma, con solo comentar la linea #DEFINE TESTING, uno puede cambiar el código compilado, para, por ejemplo hacer testing, debugging, etc. Otra utilidad es la compilación condicional para diferentes plataformas. Referencia NOTA: No todos los preprocesadores implementan el parseo de MACROS de la misma manera ==== Punto II ==== <code cpp> #include <iostream> Class MiThread { private: Mutex debeSeguirMutex; bool debeSegir; static void s_hacer(void* instancia); void hacer() { while (seguir()) { std::cout « “Hago algo” « std::endl; } } void setDebeSeguir(bool b); bool seguir(); public: MiThread(); ~MiThread(); /* Lanza el thread */ void ejecutar() { pthread_create(&thread, NULL, s_hacer, this); } /* Pide al thread que finalice sus tareas */ void detener() { /* Corta el loop */ setDebeSeguir(false); /* Hace que el Thread que lo llamó espere a que se finalice */ join(); } /* Duerme al thread que lo llama por secs segundos */ static void sleep(unsigned int secs); /* Espera a que el thread termine realmente */ void join(); }; void MiThread::s_hacer(void* instancia) { 1)
1) MiThread)instancia)→hacer(); } </code> ==== Punto III ==== Las funciones virtuales puras son aquellas que:
  • Son virtuales
  • No proveen implementación
Este tipo de funciones (en Cpp) se utilizan para denotar que una determinada clase es abstracta. Esto significa que no podrán existir instancias que sean directamente de la clase (en general es una decisión de diseño cuándo una clase debe ser o no abstracta). Toda clase que herede de una que sea abstracta (y deba ser concreta) debe implementar todos los métodos virtuales puros de sus antecesoras.
#include <iostream>
 
class SomeAbstractClass {
public:
	virtual void doSomething() = 0; /*El "=0" la marca como virtual pura*/
};
 
class SomeConcreteClass: public SomeAbstractClass {
public
	void doSomething() { std::cout << "I'm doing it!" << std::endl; }
};
Si SomeConcreteClass no implementase doSomething, tendríamos un error de compilación al intentar crear una instancia de esa clase (ya que sería abstracta). ==== Punto IV ====
/**
* Author: Mariano Szklanny 
**/
static GdkPoint* points = 0;
 
static gboolean onDraw(GtkWidget* sender, GdkEvent* eventArgs, gpointer data)
{
	if (points == 0)
	{
		points = (GdkPoint*)malloc(4 * sizeof(GdkPoint));
		points[0].x = sender->allocation.width / 2;
		points[0].y = 0;
		points[1].x = sender->allocation.width;
		points[1].y = sender->allocation.height / 2;
		points[2].x = sender->allocation.width / 2;
		points[2].y = sender->allocation.height;
		points[3].x = 0;
		points[3].y = sender->allocation.height / 2;
	}
 
	gdk_draw_polygon (sender->window,
                sender->style->fg_gc[GTK_WIDGET_STATE (sender)],
                FALSE, points, 4);
 
	return TRUE;
}
 
int main(int argc, char* argv[])
{
	GtkWidget* window;
	GtkWidget* drawingArea;
 
	gtk_init(&argc, &argv);
 
	window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
	g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);
	gtk_window_set_title(GTK_WINDOW(window), "Drawing");
 
	drawingArea = gtk_drawing_area_new();
	g_signal_connect(G_OBJECT(drawingArea), "expose_event", G_CALLBACK(onDraw), NULL);
 
	gtk_container_add(GTK_CONTAINER(window), drawingArea);
	gtk_widget_show(drawingArea);
	gtk_widget_show(window);
 
	gtk_main();
	free(points);
	return 0;
}
==== Punto V ====
void replace(FILE* file, long int foundPos)
{
    char c;
    fseek(file, foundPos, SEEK_SET);
 
    fputc('*', file);
    fgetc(file);
 
    while ((c = fgetc(file)) != EOF)
    {
        fseek(file, -2*sizeof(char), SEEK_CUR);
        fputc(c, file);
        fgetc(file);
    }
 
    fflush(file);
}
 
void process(FILE* file)
{
    char c;
    long int foundPos;
 
    while ((c = fgetc(file)) != EOF)
    {
        if ((c == '/') && ((c = fgetc(file)) == '/'))
        {
            foundPos = ftell(file) - 2;
            if (fgetc(file) == '"')
            {
                fseek(file, -4*sizeof(char), SEEK_CUR);
                if (fgetc(file) == '"')
                {
                    fseek(file, foundPos + 3, SEEK_SET);
                    continue;
                }
            }
            replace(file, foundPos);
            fseek(file, foundPos + 3, SEEK_SET);
        }
    }
}
 
int main(int argc, char* argv[])
{
    FILE* file;
 
    file = fopen("file.txt", "r+");
    if (file == 0 || feof(file) || ferror(file)) return 1;
 
    process(file);
 
    fclose(file);
    return 0;
}
==== Punto VI ====
#ifndef STACK_H_
#define STACK_H_
 
typedef struct Node {
    struct Node* next;
    void* element;
} Node;
 
typedef struct {
    Node* top;
} Stack;
 
/* Crea la estructura */
void create(Stack* stack);
/* Destruye la estructura */
void destroy(Stack* stack);
/* Agrega un elemento */
void push(Stack* stack, void* element);
/* Quita el último elemento agregado a la estructura */
void* pop(Stack* stack);
/* Retorna el último elemento agregado a la estructura */
void* top(Stack* stack);
/* Retorna 0 si la estructura está vacía. En caso contrario retorna un número distinto de 0 */
int is_empty(Stack* stack);
 
#endif
Se presenta una declaración de un tipo de dato Stack que tendrá una implementación con nodos simplemente enlazados. ==== Punto VII ====
#include <iostream>
using namespace std;
 
string process(const string& first, const string& second) {
	string result = first;
	string::size_type loc = result.find(second);
 
	while (loc != string::npos) {
		result.erase(loc,second.size());
		loc = result.find(second,loc);
	}
 
	return result;
}
 
int main(int argc, char **argv) {
	string first;
	string second;
 
	cout << "Ingrese el primer string" << endl;
	getline(cin,first);
	cout << "Ingrese el segundo string" << endl;
	getline(cin,second);
 
	cout << "Se procesaran:\n1. " << first << "\n2." << second << endl;
	cout << process(first,second);
	return 0;
}
==== Punto VIII ====
#ifndef NUMBINARIO_H_
#define NUMBINARIO_H_
#include <ostream>
 
class NumBinario
{
private:
	bool signo;
	bool numero[7];
	static NumBinario intToNumBin(int n);
 
public:
	NumBinario();
	NumBinario(int n);
	NumBinario(const NumBinario& n);
	virtual ~NumBinario();
	bool operator<(const NumBinario& n);
	bool operator==(const NumBinario& n);
	NumBinario operator=(const NumBinario& n);
 
	NumBinario operator+(const NumBinario& n) {
		int a = (int)*this;
		int b = (int)(NumBinario)n;
		int c = a+b;
		return intToNumBin(c);
	}
 
	operator int();
	friend std::ostream& operator << (std::ostream& os, NumBinario& n);
};
 
#endif
La implementación mostrada tiene la ventaja de no meterse a trabajar con números binarios (posible fuente de errores) durante el exámen. Se suponen implementados los métodos operator int() y un conversor de ints a numeros binarios. A nivel diseño tampoco es una mala idea, ya que queda completamente encapsulado el manejo de binarios y permite trabjar en el resto de los métodos de manera transparente.

Mejoras son bienvenidas

==== Punto IX ====

#include <iostream>
 
class A {
public:
	virtual ~A() {}
	virtual void doSomething() { std::cout << "I'm A" << std::endl; }
};
 
class B: public A {
public:
	virtual ~B() {}
	virtual void doSomething() { std::cout << "I'm B" << std::endl; }
};
 
void testVirtual(const A& instance) {
	instance.doSomething();
}
 
int main(int argc, char* argv[]) {
	A myA;
	B myB;
 
	testVirtual(myA); /* Muestra "I'm A" */
	testVirtual(myB); /* Muestra "I'm B" */
 
	return 0;
}
Esto sucede así, porque se está mandando una referencia a una instancia a la función testVirtual. En runtime se tiene información sobre la clase a la que efectivamente pertenece cada objeto que llega ahí y se hace Late Binding correctamente (Observar que si testVirtual recibiera no una referencia, sino un objeto, dicha información se pierde, y siempre se llamaría al método de la clase definida como parámetro - esto se conoce como Object Slicing). ==== Punto X ====
class Universo {
private:
	static int contador;
 
public:
	Universo() {contador++;}
	~Universo() {contador--;}
	static int cantidadInstancias();
};
 
int Universo::contador = 0;
 
int Universo::cantidadInstancias() { return contador; }
===== Discusión =====

Si ves algo que te parece incorrecto en la resolución y no te animás a cambiarlo, dejá tu comentario acá.

materias/75/42/final_002_20061212_1.txt · Última modificación: 2008/02/11 17:23 por gsoriano
 
Excepto donde se indique lo contrario, el contenido de esta wiki se autoriza bajo la siguiente licencia: CC Attribution-Noncommercial-Share Alike 3.0 Unported


Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki