Algoritmos e C++

 
 
Roteiro de aulas práticas
Parte IV - estruturas de dados, classes e objetos
Sumário:
  • Estruturas de dados
    • Definição de estrutura
    • Acesso a membros
    • Inicialização
    • Aninhamento e matriz
    • Estruturas e funções
    • Retorno de variável tipo estrutura
  • Classes e Objetos
  • Bibliografia
 

Estruturas de dados

Estruturas são agrupamentos de dados relacionados que podem ser de diferentes tipos básicos (int, float, double, char e void) sob uma única declaração. Os itens de dados das estruturas são denominados membros.
Os agrupamentos de dados mais importantes disponíveis em C++ são as estruturas com seus dados-membros e as classes, que caracterizam a programação orientada a objetos, com seus dados-membros e funções-membros.
Como a declaração das estruturas se assemelha à das classes, a compreensão daquelas ajuda sobremaneira no entendimento de classes e objetos.
 
 

Definição da estrutura

A estrutura é definida com a palavra-chave struct seguida de um nome identificador.
Entre chaves é especificado um ou mais itens de dados (tipo e membro) e, por último, as variáveis.

Formato da estrutura:    c++p4_img01

Exemplo de um programa que cria uma estrutura com descrição e preço, introduz e exibe seus conteúdos:
#include <iostream.h>
#include <string.h>
struct produto
{
    char descr[50];
    float preco;
} hd, cd;
void main()
{
    strcpy(hd.descr,"Hard disk Maxtor");
    hd.preco = 250.42;
    cout<<"Descricao do CD: ";
    cin.getline(cd.descr,50);
    cout<<"Preco do CD: ";
    cin>>cd.preco;
 
    cout<<"\nHD -\tDescricao: "<<hd.descr <<"\n\tPreco: "<<hd.preco<<endl;
    cout<<"\nCD -\tDescricao: "<<cd.descr <<"\n\tPreco: "<<cd.preco;
}

Outro modo de declarar as variáveis da estrutura é usando o nome-tipo da estrutura seguido das variáveis dentro da função:
#include <iostream.h>
#include <string.h>
struct produto
{
    char descr[50];
    float preco;
};     // ponto e vírgula após o fechar chaves
void main()
{
    produto hd, cd;     // tipo da estrutura e suas variáveis
    ...
}

A criação da estrutura apenas caracteriza a definição de um novo tipo de dado criado pelo usuário. Para sua utilização, deve-se declarar ao menos uma variável do tipo produto, neste caso.

À cada variável, hd e cd declaradas no exemplo, é reservado espaço contíguo de memória necessário para armazenar todos os membros da estrutura.

A definição da estrutura fora de qualquer função, como a que foi criada no programa acima, permite acesso a seus membros por todas as funções especificadas no programa. Por outro lado, a estrutura criada dentro da função restringe o acesso a esta função.
 
 

Acesso a membros da estrutura

Para acessar um membro da estrutura, deve-se informar os nomes da variável e do respectivo membro conectados por meio do operador ponto (.).

Exemplo de uma instrução de atribuição:    hd.preco = 250.42;
Este exemplo atribui o valor 250.42 ao membro preco da variável hd.
 
 

Inicialização de estruturas

As estruturas podem ser inicializadas na mesma instrução de sua definição e se parecem com a inicialização de vetores e matrizes.

Segue um exemplo:

#include <iostream.h>
struct contrato
{
    int matricula;
    char nome[20];
    float salario;
};
void main()
{
    contrato func = {123, "Ana Maria da Silva", 2500.00};
}
Os valores atribuídos à variável func devem seguir a ordem de acordo com a declaração dos membros na estrutura, separados por vírgulas e entre chaves.
 
 

Aninhamento e matriz de estruturas

O aninhamento de estruturas refere-se àquelas estruturas que participam como membros de outras estruturas.
No exemplo, a seguir, vê-se a estrutura data definida como membro da estrutura contrato.
Verifica-se também no mesmo exemplo uma matriz de 50 elementos declarada na variável func da estrutura contrato.
O exemplo objetiva cadastrar e listar elementos da variável func (funcionário) e exibir o valor total dos salários listados, segundo opção dada a escolher ao usuário.

#include <iostream.h>
#include <iomanip.h>
struct data         // estrutura do tipo data
{
    int dia, mes, ano;         // membros da estrutura
};
struct contrato         // estrutura do tipo contrato
{
    char nome[30];
    float salario;
    data nasc;         // membro da estrutura do tipo data
};
void incluir();         // protótipo da função incluir()
void listar();          // protótipo da função listar()
contrato func[50];         // declara uma matriz de estrutura
int i=0;
void main()
{
    int oper, verdade=1;
    while(verdade) {
        cout<<"1 para incluir";
        cout<<"\n2 para listar";
        cout<<"\n3 para encerrar : ";
        cin>>oper;

        if (oper==1) incluir();
        else
            if (oper==2) listar();
            else
                verdade=0;
        cout<<'\n';
    }
}
void incluir()
{
    cout<<"\nNome: "; cin>>func[i].nome;
    cout<<"Salario: "; cin>>func[i].salario;
    cout<<"Dia nasc.: "; cin>>func[i].nasc.dia;
    cout<<"Mes nasc.: "; cin>>func[i].nasc.mes;
    cout<<"Ano nasc.: "; cin>>func[i++].nasc.ano;
}
void listar()
{
    float totsal=0;
    cout<<"\nSalario"<<setw(13)<<"Data nasc."<<setw(12)<<"Nome";
    cout<<setprecision(2);                 // exibe duas casas decimais
    cout << setiosflags(ios::fixed);     // inibe a exibição em notação científica
    for(int j=0; j<i; j++)
    {
        cout<<'\n'<<setw(10)<<func[j].salario<<setw(6)
               <<func[j].nasc.dia<<setw(3)
               <<func[j].nasc.mes<<setw(3)
               <<func[j].nasc.ano<<setw(20)<<func[j].nome;
        totsal += func[j].salario;
    }
     cout<<"\nTotal salario:  "<<totsal<<endl;
}
As estruturas assim como a matriz e a variável índice (i) foram declaradas como componentes externos para permitir o acesso a eles pelas funções incluir() e listar().
 
 

Estruturas e funções

Estruturas também podem ser passadas como argumento de funções de modo semelhante ao procedimento realizado com quaisquer variáveis comuns.

Passagem por valor
A seguir, um exemplo de uma função que efetua um cálculo e exibe a média de alunos por sala, a partir de duas variáveis do tipo estrutura passadas por valor:
#include <iostream.h>
struct curso
{
    int sala;
    float aluno;
};
void media(curso n1, curso n2);
void main()
{
    curso c1, c2;
    cout<<"Curso 1";
    cout<<"\n\tQuant. de salas:  "; cin>>c1.sala;
    cout<<"\tNumero de alunos: "; cin>>c1.aluno;
    cout<<"\nCurso 2";
    cout<<"\n\tQuant. de salas:  "; cin>>c2.sala;
    cout<<"\tNumero de alunos: "; cin>>c2.aluno;
    media(c1, c2);     // variáveis tipo estrutura como argumento
}
void media(curso n1, curso n2)
{
    float med;
    med = (n1.aluno + n2.aluno) / (n1.sala + n2.sala);
    cout<<"\nMedia de alunos por sala: "<<med;
}

Passagem por referência
De modo análogo à operação de passagem de variáveis comuns, procede-se com as variáveis tipo estrutura na passagem destas como argumento por referência.
É bom lembrar que o método por referência economiza memória uma vez que o sistema não faz nenhuma cópia das variáveis para serem operadas pela função.
Para apresentar um exemplo desta técnica, foi modificado o programa do exemplo anterior para receber argumentos por referência:
#include <iostream.h>
struct curso
{
    int sala;
    float aluno;
};
void media(curso& n1, curso& n2);
void main()
{
    curso c1, c2;
    cout<<"Curso 1";
    cout<<"\n\tQuant. de salas:  "; cin>>c1.sala;
    cout<<"\tNumero de alunos: "; cin>>c1.aluno;
    cout<<"\nCurso 2";
    cout<<"\n\tQuant. de salas:  "; cin>>c2.sala;
    cout<<"\tNumero de alunos: "; cin>>c2.aluno;
    media(c1, c2);     // variáveis tipo estrutura como argumento
}
void media(curso& n1, curso& n2) 
{
    float med;
    med = (n1.aluno + n2.aluno) / (n1.sala + n2.sala);
    cout<<"\nMedia de alunos por sala: "<<med;
}
As variáveis n1 e n2 compartilham o mesmo espaço de memória ocupado pelas variáveis c1 e c2.
Observar que o operador & (operador de endereços) é escrito junto ao nome da estrutura que aparece no argumento da função média.
 
 

Retorno de variável tipo estrutura

A ilustração seguinte apresenta o mesmo exemplo modificado para que a função retorne uma variável tipo estrutura:
#include <iostream.h>
struct curso
{
    int sala;
    float aluno;
};
void media(curso& n1, curso& n2);
curso insere(void);
void main()
{
    curso c1, c2;
    cout<<"Curso 1";
    c1=insere();
    cout<<"Curso 2";
    c2=insere();
    media(c1, c2);
}
curso insere(void)
{
    curso sa;
    cout<<"\n\tQuant. de salas:  "; cin>>sa.sala;
    cout<<"\tNumero de alunos: "; cin>>sa.aluno;
    return (sa);
}
void media(curso& n1, curso& n2)
{
    float med;
    med = (n1.aluno + n2.aluno) / (n1.sala + n2.sala);
    cout<<"\nMedia de alunos por sala: "<<med;
}
Notar que a função insere( ) foi definida como uma função do tipo curso pois ela retorna uma variável do tipo especificado.
 
 

Classes e Objetos

Uma classe é um método lógico de organização de dados e funções numa mesma estrutura e é considerada como instrumento principal da programação orientada a objetos. A variável de uma classe é chamada objeto que fará uso dos dados e funções.

Classes
As classes são funcionalmente similares às estruturas, porém enquanto estas definem apenas dados, aquelas definem os chamados dados-membro e funções-membro
As funções-membro também conhecidas como métodos são responsáveis pelas operações realizadas sobre os dados-membro da classe.
Exemplo:
#include <iostream.h>
class area     // define a classe
{
private:     // dados-membro:
    float largura;
    float altura;
public:     // funções-membro:
    void obtemdados(float larg, float alt);            // protótipo da função
    float calcula()            // função inline
    { return(largura*altura);}
};
void area::obtemdados(float larg, float alt)
{
    largura=larg;
    altura=alt;
}
void main()
{
    area parede;     // declara o objeto
    parede.obtemdados(3.5, 5.2);
    float areapar = parede.calcula();
    cout<<"Area da parede: "<<areapar;
}
No exemplo é declarada a classe area que contém quatro membros: duas variáveis do tipo float e duas funções: obtemdados e calcula. A função obtemdados tem apenas seu protótipo definido dentro da declaração da classe, as operações são especificadas fora dela, ao passo que a função calcula tem seus comandos definidos dentro da classe.

Para definir funções fora da classe deve ser usado o operador de resolução de escopo (::) após o nome da classe. Ele especifica a classe a qual pertence à função-membro.
No exemplo tem-se:
void area :: obtemdados(float larg, float alt)
que significa que a função obtemdados é uma função-membro da classe area.

As funções-membros, também chamadas de métodos, definidas dentro da classe são criadas como inline por default, no entanto uma função-membro inline também pode ser definida fora da classe por meio da palavra reservada inline.

O exemplo traz duas seções private: e public: que especificam a visibilidade dos membros da classe. (Note-se que na codificação as palavras devem ser seguidas de dois pontos).

Na parte private, geralmente, são escritos os membros de dados, os quais só podem ser acessados por funções pertencentes à classe. Desse modo, diz-se que os dados estão escondidos ou encapsulados por não permitir que funções extra classe os acessem. A palavra reservada private por ser default não precisaria ser explicitada no programa, contudo sua colocação torna mais evidente essa circunstância.

Na seção public da classe, geralmente, são especificadas as funções ou métodos que atuam sobre os dados.

O acesso aos membros públicos é feito através do operador ponto de modo análogo ao acesso requerido aos membros de uma estrutura. A instrução
parede.obtemdados(3.5, 5.2 );
usa o operador ponto (.) para chamar a função obtemdados e atribuir valores aos dados membro.

Objetos
Um objeto é um tipo especial de variável que contêm dados e códigos e representa um elemento específico. Um objeto é uma instância ou uma ocorrência específica de uma classe. Ele geralmente possui vários atributos que definem suas características, e métodos que operam sobre esses atributos.
No exemplo anterior, parede é o nome do objeto do tipo classe que contém os atributos largura e altura e os métodos obtemdados e calcula.

A classe é o mecanismo que reúne objetos que podem ser descritos com os mesmos atributos e as mesmas operações. Ela agrupa dados e funções, é a peça fundamental da programação orientada a objeto.
No exemplo, a codificação:
area parede;
define como objeto o elemento parede pertencente a classe area, ou seja, declara uma instância da classe.
Os objetos se comunicam através de mensagem, isto é, de chamada a uma função-membro requisitando um serviço através da execução de uma operação. A instrução
parede.obtemdados(3.5, 5.2);
solicita ao objeto parede que receba os dados ou as medidas para o cálculo da área.
Uma classe permite declarar vários objetos diferentes.

Acrescentando o objeto tijolo à classe area, o programa fica como segue:
#include <iostream.h>
 
class area     // define a classe
{
private:     // dados-membro:
    float largura;
    float altura;
public:     // funções-membro:
    void obtemdados(float larg, float alt);        // protótipo da função
    float calcula()           // função inline
    { return(largura*altura);}
};
void area::obtemdados(float larg, float alt)
{
    largura=larg;
    altura=alt;
}
void main()
{
    area parede, tijolo;     // declara os objetos
 
    parede.obtemdados(3.5, 5.2);
    float areapar = parede.calcula();
    cout<<"Area da parede: "<<areapar;
 
    tijolo.obtemdados(0.12, 0.30);
    float areatij = tijolo.calcula();
    cout<<"\nArea do tijolo: "<<areatij;
 
    cout<<"\nQuant. de tijolos necessarios para construir a parede,";
    cout<<"\nconsiderando que 10% da area e' de argamassa: "
           <<(areapar/areatij*0.9)<<" tijolos."<<endl;
}
Na instrução que define o objeto foi incluído outro objeto de nome tijolo:
area parede, tijolo;
Por meio do operador ponto, o objeto tijolo também acessa os mesmos métodos do objeto parede para atribuir a seus dados-membro os devidos valores, como no caso da instrução:
tijolo.obtemdados(0.12, 0.30);
O objeto tijolo possui as mesmas características do objeto parede, ou seja, uma área definida pela largura e altura.
 
 

Bibliografia

  • ASCENCIO, Ana Fernanda Gomes, CAMPOS, Edilene Aparecida Veneruchi de. Fundamentos da programação de computadores : algoritmos, Pascal e C/C. São Paulo : Prentice Hall, 2002. xviii, 355p.
  • FORBELLONE, André Luiz Villar; EBERSPACHER, Henri Frederico. Lógica de programação : a construção de algoritmos e estruturas de dados. 2.ed. São Paulo : Makron Books, 2000. 197p.
  • JAMSA, Kris A. Aprendendo C. São Paulo : Makron Books do Brasil, 1999. 271p.
  • MIZRAHI, Victorine Viviane. Treinamento em linguagem C. Sao Paulo : Makron, 1994. v.
  • BERRY, John Thomas. Programando em C. Sao Paulo : Makron Books, 1991. xvi, 385p.
  • UCCI, Waldir; SOUSA, Reginaldo Luiz; KOTANI, Alice Mayumi, et al. . Lógica de programação : os primeiros passos. 8.ed. Sao Paulo : Erica, 1999. 339p.