Introdução aos Objectos/Objectos em C: Tipos de Dados Abstractos

From Wiki**3

< Introdução aos Objectos
Revision as of 12:49, 13 September 2011 by Root (talk | contribs) (Interface do conceito "Animal")

Os exercícios seguintes ilustram a definição de tipos de dados abstractos e de suas instâncias. Estas instâncias são semelhantes aos objectos suportados por linguagens como o C++ ou o Java, mas, como estão implementados em C, algumas das operações têm de ser definidas explicitamente pelo programador.

Os exemplos tocam também no aspecto da reutilização de código: em linguagens OO, é algo que surge "naturalmente". Nestes exemplos, é necessário mais trabalho. Os exemplos são implementados em C++ no final (apenas para uma comparação mais directa com C: deixa-se como exercício a implementação em Java ou em outras linguagens de programação).

Animal simples

A tarefa é a modelação e implementação em C (ficheiros .h e .c) de uma estrutura de dados que represente uma versão simples do conceito “animal”.

Um animal tem como características o nome (_name), a idade (_age) e o peso (_weight).

Devem ser ainda implementadas as funções newAnimal e destroyAnimal. A função newAnimal reserva memória suficiente para representar um animal e permite inicializar os seus campos (através dos argumentos da função). Por simplicidade, assume-se que o campo _name tem comprimento fixo máximo de 16 caracteres (incluindo o terminador). A função destroyAnimal liberta os recursos associados ao animal.

Outras funções a implementar:

  • função de comparação – equalsAnimal –, por forma a considerar que dois animais são iguais se as suas características forem iguais
  • funções de acesso às variáveis de um animal: getAnimalName, getAnimalAge, getAnimalWeight (dado um animal, retornam um dos seus campos)
  • função printAnimal que, quando aplicada a um animal, apresenta os seus dados (use printf para apresentar cada campo do animal)
  • programa – main – que ilustra a utilização das funções anteriores

Interface do conceito "Animal"

Ficheiro Animal.h: <c>

  1. ifndef __ANIMAL_H__
  2. define __ANIMAL_H__

// this typedef is used to hide the concept's implementation details typedef struct animal *Animal;

Animal newAnimal(const char *name, int age, double weight); void destroyAnimal(Animal animal);

int equalsAnimal(Animal animal1, Animal animal2); const char *getAnimalName(Animal animal); int getAnimalAge(Animal animal); double getAnimalWeight(Animal animal); void printAnimal(Animal animal);

  1. endif

</c>

Implementação do conceito "Animal"

Ficheiro Animal.c: <c>

  1. include <string.h>
  2. include <stdlib.h>
  3. include <stdio.h>
  4. include "Animal.h"

struct animal {

 char   _name[16];
 int    _age;
 double _weight;

};

Animal newAnimal(const char *name, int age, double weight) {

 Animal animal = (Animal)malloc(sizeof(struct animal));
 if (animal != NULL) {
   strcpy(animal->_name, name);
   animal->_age = age;
   animal->_weight = weight;
 }
 return animal;

}

void destroyAnimal(Animal animal) {

 if (animal) {
   free(animal);
   animal = NULL;
 }

}

const char *getAnimalName (Animal animal) { return animal->_name; } int getAnimalAge (Animal animal) { return animal->_age; } double getAnimalWeight(Animal animal) { return animal->_weight; }

/* note that we require animal1 and animal2 to be valid animals: any of

  them being NULL pointers will result in a false comparison. */

int equalsAnimal(Animal animal1, Animal animal2) {

 if (animal1 == NULL || animal2 == NULL) return 0;
 return !strcmp(getAnimalName(animal1), getAnimalName(animal2)) &&
     getAnimalAge(animal1) == getAnimalAge(animal2) &&
     getAnimalWeight(animal1) == getAnimalWeight(animal2);

}

void printAnimal(Animal animal) {

 printf("== Animal ==\n");
 printf("Name:   %s\n", getAnimalName(animal));
 printf("Age:    %d\n", getAnimalAge(animal));
 printf("Weight: %g\n", getAnimalWeight(animal));

} </c>

Programa exemplo

Ficheiro main.c: <c>

  1. include <stdio.h>
  2. include "Animal.h"

int main() {

 Animal a1 = newAnimal("Tareco", 12, 3.4);
 Animal a2 = newAnimal("Piloto", 1, 12.3);
 printAnimal(a1);
 printAnimal(a2);
 printf("a1==a1? %s\n", equalsAnimal(a1, a1) ? "yes" : "no");
 printf("a1==a2? %s\n", equalsAnimal(a1, a2) ? "yes" : "no");
 return 0;

} </c>

Gato simples

A tarefa é a modelação e implementação em C (ficheiros .h e .c) de uma estrutura de dados que represente uma versão simples do conceito “gato”.

Um gato tem como características o nome (_name), a idade (_age), o peso (_weight), o volume do ronronar (_purrLevel) e o grau de suavidade do pêlo (_fluffiness).

Devem ser ainda implementadas as funções newCat e destroyCat. A função newCat reserva memória suficiente para representar um gato e permite inicializar os seus campos (através dos argumentos da função). Por simplicidade, assuma que o campo _name tem comprimento fixo máximo de 16 caracteres (incluindo o terminador). A função destroyCat liberta os recursos associados ao gato.

Outras funções a implementar:

  • função de comparação – equalsCat –, por forma a considerar que dois gatos são iguais se as suas características forem iguais
  • funções de acesso às variáveis de um gato: getCatName, getCatAge, getCatWeight, getCatPurrLevel, getCatFluffiness (dado um gato, retornam um dos seus campos)
  • função printCat que, quando aplicada a um gato, apresenta os seus dados (use printf para apresentar cada campo do gato)
  • programa – main – que ilustra a utilização das funções anteriores

<c> //TODO </c>

Gato menos simples

Como se pode observar acima, existe alguma repetição na definição de animal e de gato. Como o conceito de gato contém alguma informação do conceito de animal, seria conveniente a sua reutilização.

A tarefa é a modelação e implementação em C (ficheiros .h e .c) de uma estrutura de dados que represente uma versão do conceito “gato”, mas considerando-o como uma animal caracterizado pelo volume do ronronar (_purrLevel) e pelo grau de suavidade do pêlo (_fluffiness).

Tal como anteriormente, devem ser ainda implementadas as funções newCat e destroyCat. A função newCat reserva memória suficiente para representar um gato e permite inicializar os seus campos (através dos argumentos da função). Por simplicidade, assuma que o campo _name tem comprimento fixo máximo de 16 caracteres (incluindo o terminador). A função destroyCat liberta os recursos associados ao gato.

Note-se que o facto de o gato ser um animal não altera a necessidade de implementação das funções associadas ao gato.

Assim, as funções a implementar são:

  • função de comparação – equalsCat –, por forma a considerar que dois gatos são iguais se as suas características forem iguais
  • funções de acesso às variáveis internas de um gato: getCatName, getCatAge, getCatWeight, getCatPurrLevel, getCatFluffiness (dado um gato, retornam um dos seus campos). Note-se que algumas destas características são fornecidas pelo conceito “animal”
  • função printCat que, quando aplicada a um gato, apresenta os seus dados (use printf para apresentar cada campo do gato)
  • programa – main – que ilustra a utilização das funções anteriores

<c> //TODO </c>

Discussão

Implementação em C++