Agnor's HQ

Aula 13 - Classes - Parte I

Conceitos-Chave:

- programação procedimental, estilo de programação baseado em passos/etapas, como se tratasse de um livro de receitas
- programação orientada a objectos, estilo de programação onde o programador cria objectos, abstraindo-se do código, baseando-se em exemplos da vida real. Cada objecto pode (e deve) interagir entre si.
- classe e objecto, um objecto pertence a uma determinada classe. No exemplo, Cadeira cadeira_do_escritorio;, Cadeira seria a classe e cadeira_do_escritorio o objecto.
- Acessibilidade, apontam para conjuntos de caracteres, não sendo preciso dimensionar o apontador

Paradigmas de programação

Até agora temos programado usando um estilo de programação procedimental, ou seja, um estilo de programação que utiliza várias funções (vários passos ou instruções) para serem executadas. Por exemplo:

1º - Pegar no telefone;
2º - Marcar o nº;
3º - Esperar por alguma actividade do telefone;
3.1 - Se alguém atender salta para o passo 4;
3.2 - Se o sinal estiver interrompido desligue o telefone, espere 1 minuto e volte ao passo 1;
3.3 - Se não atender desligue o telefone, espere 30 minutos e volte ao passo 1;
4 - Fale e tenha uma agradável conversa;
5 - Desligue o telefone;

Em C++ este código (recorrendo a funções e ao paradigma procedimental) poderia ficar assim:

ligarTelefone(telefone_de_casa);
marcarNumero(telefone_de_casa, numero);
int sinal = sinal_do_telefone();

while(sinal == 0)
{
	esperar(tempo_de_espera);
}

while (sinal != 1)
{
	case 2:
		//....
}

falar();
desligar_telefone(telefone_de_casa);
			

Um dos pontos mais fracos da linguagem C (a linguagem antecessora ao C++) foi o de não suportar a chamada Programação Orientada a Objectos (OOP - Object Oriented Programming).

A linguagem C++, para além de suportar o paradigma OOP e o procedimental, suporta outros dois (Abstract Data Type e Generic Programming). Isto é uma enorme vantagem, uma vez que poderemos escolher entre programar de 4 maneiras diferentes! Até agora tenho vos ensinado programação procedimental, mas a partir de agora é melhor habituarem-se à Programação Orientada a Objectos, uma vez que é o paradigma que "está na moda" (as linguagens da nova geração como Java e C# "obrigam" o programador a utilizá-la).

Depois desta "chuva" de termos técnicos vamos então à Programação Orientada a Objectos.

Programação Orientada a Objectos (OOP) - Introdução

Na OOP, em vez de o programa ser uma lista de instruções (passos) a seguir, este passa a ser um conjunto de objectos, capazes de interagir entre si, mandando, recebendo e processando mensagens. Com um exemplo da "vida real" verão que o conceito é muito simples e muito interessante.

Imaginemos um objecto, por exemplo, um ser humano (objecto não é nesse sentido).

Antes de mais, um ser humano é constituído por vários orgãos. Tem uma boca, um nariz, dois olhos, etc.

Um ser humano é um mamífero. Isso significa que partilha várias características com todos os mamíferos, por exemplo, possui coração, coluna vertebral, pêlo, além de possuir as mesmas funções básicas: acasalar, alimentar-se, dormir, etc.

Além disso, um ser humano tem várias funções, como a de falar, ler, escrever, etc.

Poderemos então construir o seguinte diagrama:

Diagrama UML

Nota:

O diagrama acima está desenhado seguindo a "linguagem" UML (Unified Modelling Language). Trata-se de uma "linguagem" para expôr a relação entre as classes de um programa e é fundamental quando estamos a planear o código para um projecto grande (um jogo, por exemplo) e quando estamos a trabalhar numa equipa com mais programadores.

Por agora, como os programas que iremos fazer serão muito simples, não é necessário estarmos a planeá-lo através de diagramas.

Talvez entre em mais pormenores sobre esta linguagem em futuras aulas.

Bem, agora que aprendemos o conceito da programação orientada a objectos vamos ver o seu uso num programa real.

Classes

Na lição nº 9 expliquei como se usavam estruturas (struct).

As classes são uma evolução das estruturas (só têm uma diferença significativa), em C usava-se estruturas, em C++, devido à introdução do paradigma OOP, usam-se classes.
Então porque é ensinei primeiro estruturas? Em primeiro lugar porque usar estruturas é um pouco mais fácil para novatos. Segundo, porque ainda há muitos programadores que utilizam classes e estruturas no mesmo programa (eu inclusivé), por isso já estão preparados para tudo.

Nota:

A verdade é que as estruturas nem deveriam existir em C++. Só existem para manter a compatibilidade com a linguagem C.

As classes definem-se através da palavra chave class e seguem praticamente as mesmas normas que as estruturas. Um exemplo de uma classe simples é:

class Ponto
{
  int x, y;
};	 

É muito parecido com uma estrutura, mas é diferente de:

struct Ponto
{
  int x, y;
};	 

Então onde está a diferença?

Acessibilidade

A diferença entre classes e estruturas está na sua acessibilidade. Numa classe (ou numa estrutura) os membros podem ser declarados como públicos ou privados.

Os membros privados (private) só podem ser acedidos pela própria classe. Os membros públicos (public) tanto podem ser acedidos pela classe como fora dela.

A acessibilidade predefinida de uma estrutura é pública. Assim, no exemplo acima, as variáveis x e y tanto podem ser manipulados dentro como fora da estrutura.
A acessibilidade predefinida de uma classe é privada. Assim, também no exemplo acima, as variáveis x e y podem ser manipuladas apenas dentro da classe.

Parece confuso? Um simples exemplo pode esclarecer as dúvidas:

class Ponto
{
public:

  int x, y; //membros publicos

private:

  int a, b; //membros privados
};	 

Que também pode ser definido por:

class Ponto
{
  int a, b; //membros privados

public:

  int x, y; //membros publicos
};	

Nota:

Em C++ ainda há outro tipo de acesso, chamado protegido (protected), mas não precisam de se preocupar com ele por agora.

Métodos

Métodos são como funções, que estão contidos dentro de uma classe. Por exemplo, imaginem uma classe Ponto (classe que trabalha com as coordenadas cartesianas, x e y, de um ponto):

class Ponto
{
public:
    void alterarX(int u_x); //altera o valor de x
    void alterarY(int u_y); //altera o valor de y
    void alterar(int u_x, int u_y); //altera o valor de x e de y

    int mostrarX(); //devolve o valor de x
    int mostrarY(); //devolve o valor de y

private:

    int x, y;   //coordenadas do ponto
};

Nota:

Dei o nome de u_x e u_y aos atributos das funções para não entrarem em conflito com as variáveis privadas x e y.

As funções acima (métodos) fazem parte da classe. Notem que apesar das variáveis x e y serem privadas podem ser acedidas pelos métodos da própria classe.
Notem também que apenas declaramos os métodos, ainda não os definimos. Para poder defini-los há duas maneiras. A primeira é defini-los na definição da classe:

class Ponto
{
public:
    void alterarX(int u_x) { x = u_x; }
    void alterarY(int u_y) { y = u_y; }
    void alterar(int u_x, int u_y) {
        x = u_x;
        y = u_y;
    }

    int mostrarX() { return x; }
    int mostrarY() { return y; }

private:

    int x, y;   //coordenadas do ponto
};

Esta maneira é bastante fácil, mas é desaconselhada para funções maiores. A segunda maneira é defini-los fora da definição da classe. No exemplo seguinte vou só definir fora da classe o método alterar().

class Ponto
{
public:
    void alterarX(int u_x) { x = u_x; }
    void alterarY(int u_y) { y = u_y; }
    void alterar(int u_x, int u_y);

    int mostrarX() { return x; }
    int mostrarY() { return y; }

private:

    int x, y;   //coordenadas do ponto
};

void Ponto::alterar(int u_x, int u_y) {
    x = u_x;
    y = u_y;
}

Como podem ver é semelhante a definir uma função normal, com uma única diferença: a inclusão do Ponto::. Esta instrução serve para informar o compilador que o método seguinte pertence à classe Ponto. O operador '::' é o operador resolução de alcance. Serve para dizermos ao compilador que queremos aceder à função (método) "alterar()", que está dentro da classe "Ponto": Ponto::alterar()

Classes vs Objectos

Neste ponto é algo importante conhecer a distinção entre classe e objecto. No exemplo abaixo:

Carro Seat;

Carro seria a classe e Seat seria o objecto. Se os compararmos a uma variável, uma classe seria o tipo de dados (int, char, etc.) e um objecto seria a variável em si.

Aceder aos membros de classes

Podemos aceder aos membros de um objecto da mesma forma que acedemos às estruturas. Por exemplo,

ponto.x = 3;
cout << ponto.getX();

Exemplo final e Questões de Acessibilidade

Para acabar esta parte, um programa de exemplo com a "matéria" toda.

#include <iostream>
using namespace std;

class Ponto
{
public:
    void alterarX(int u_x) { x = u_x; }
    void alterarY(int u_y) { y = u_y; }
    void alterar(int u_x, int u_y);

    int mostrarX() { return x; }
    int mostrarY() { return y; }

private:

    int x, y;   //coordenadas do ponto
};

void Ponto::alterar(int u_x, int u_y) {
    x = u_x;
    y = u_y;
}

int main()
{
    Ponto point;    //declaramos um objecto point da classe Ponto

    //como fazer point.x ou point.y daria erro (privado)....
    point.alterar(3, 2);

    //mostrar os pontos:
    cout << "X: " << point.mostrarX() << "\nY: " << point.mostrarY() << endl;

    point.alterarX(7);

    //mostrar os pontos:
    cout << "\nX: " << point.mostrarX() << "\nY: " << point.mostrarY() << endl;

    cin.get();
    return 0;
}

Exemplo 13.1 - Classe Ponto

Facilmente poderíamos adicionar mais métodos, como o de somar, de incrementar, etc..

Vocês devem estar a pensar no porquê de declararmos as variáveis privadas, pois seria muito mais simples fazer point.x do que point.mostrarX(). Poderão fazer das duas formas, mas é preferível declarar as varíaveis de forma privada e usar uma função para a alterar e outra para obter o seu valor. Isto porque, se no futuro quiserem expandir as funcionalidades da vossa classe, torna-se muito mais fácil. Imaginem uma classe mês. Fazer:

mes.dia = 50;

Seria um erro, obviamente, mas ao criarmos um método:

mes.alterarDia(50);

Poderiamos assegurar - dentro do método - que a variável seria menor que 31 (if (dia < 31)...). Assim não tínhamos que alterar código nenhum (não tinhamos de todos os mes.dia dentro da função main()), apenas algumas linhas dentro do método alterarDia().

Final da aula 13 de C++:

Próxima aula -> C++ 14 - Apontadores - Parte II

Fazer o download do código fonte dos exemplos da aula WinZip
Fazer o download da aula em PDF (Brevemente)

Ir para o topo da página

Aulas de C++

Anúncios