CG 5 Oo C++ PDF

Fazer download em pdf ou txt
Fazer download em pdf ou txt
Você está na página 1de 20

Universidade Federal de Santa Maria

Departamento de Eletrnica e Computao


Prof. Cesar Tadeu Pozzer
[email protected]
30/07/2009

Introduo a Programao Orientada Objetos


na Linguagem C++

1 Introduo
A programao orientada a objetos surgiu com o principal objetivo de unir os dados e funes em um nico
elemento: o objeto. Esta metodologia traz uma srie de vantagens sobre linguagens de programao procedural,
como o C:

Reusabilidade: as classes que compem um sistema podem ser aproveitadas em outros sistemas, sem
qualquer alterao, pois dados e funes esto contidos dentro da classe. Caso haja necessidade, pode-se
criar novas classes baseadas em outras j existentes, herdando as caractersticas da classe pai.
(Modularizao)
Encapsulamento: proteo dos dados contra alteraes indevidas. O encapsulamento mantm
escondidos dados e mtodos do objeto. Pode-se explicitamente declarar o grau de visibilidade de
atributos e mtodos.
Produtividade: A partir do momento que temos a disposio uma coleo de classes devidamente
testadas e com um funcionamento a prova de erros, para criar novos sistemas basta usar estas classes,
sem nenhuma necessidade de reescrever e adaptar cdigo. Isto d, sem sombra de dvida, maior rapidez
e, conseqentemente, produtividade no desenvolvimento de sistemas.

A Linguagem C++ uma extenso da linguagem C que incorpora recursos de Orientao a Objetos. A
linguagem C++ herdou todas as caractersticas de C, e adiciona recursos de programao orientada a objetos.
Sempre que possvel ser feita uma analogia entre C e C++. OBS: todos os arquivos de um projeto C++
devem ter a extensao .cpp.

2 Classe
Uma classe um tipo definido pelo usurio, semelhante a uma estrutura, com o adicional que funes tambm
podem ser inseridas. Estas funes (mtodos) vo agir sobre os dados (atributos) da classe. O seguinte exemplo
mostra um exemplo hipottico de um fragmento de cdigo em C e seu equivalente em C++.

C C++
typedef struct{ class Ponto {
int x, y: public:
}Ponto; int x, y;
void set(int a, int b)
void set(Ponto *p, int x, int y) {
{ x = a;
p->x = x; y = b;
p->y = y; }
} }; //no esqueca o ;

Toda classe deve ter um construtor, que um mtodo com o mesmo nome da classe, sem valor de retorno. Ele
chamado quanto um objeto inicializado e nele so definidos, pelo programador, os atributos que devem ser
inicializados. Uma classe pode ter vrios construtores, com diferentes argumentos (sobrecarga). As classes
tambm podem ter um destrutor, que um mtodo sem parmetros e sem retorno chamado quando o objeto
desalocado. O destrutor no pode ser chamado explicitamente e tem somente como funo fornecer ao
compilador o cdigo a ser executado quando o objeto destrudo.

1
#include <stdio.h>
class Ponto
{
public:
int x, y;
Ponto(void) //mtodo construtor
{
x = y = 0;
}
~Ponto(void) //Destrutor. Chamado quando o objeto liberado
{
//no faz nada neste caso
}
};

int main (void)


{
Ponto p1; //chama o construtor default imediatamente
Ponto p2(); //chama o construtor imediatamente
Ponto *pp; //no chama o construtor pois pp ponteiro
pp = new Ponto(); //chama o construtor para pp
printf("%d %d ", p1.x, pp->x);
return 0;
}

2 Objeto
Um objeto uma instncia da classe, da mesma forma como uma varivel de estrutura em C. Por meio dele
que os mtodos e variveis da classe, ou superclasses, podem ser acessados. Os objetos podem ser alocados de
forma esttica ou dinmica, com o seguinte exemplo.

C C++
Ponto p; //varivel Ponto p; //objeto
Ponto *p = (Ponto*) malloc(sizeof(Ponto)); Ponto *p = new Ponto();

3 Mtodo
Mtodos so funes associadas a uma classe, e so chamadas pelos objetos pertencentes a classe ou por outros
mtodos da classe. No seguinte exemplo, para fazer a inicializao do Ponto p, em C deve-se chamar a funo
inicia passando-se a referncia de qual varivel ser inicializada. Em C++, o objeto p chama seu mtodo prprio
inicia(int, int) que faz sua inicializao. Este exemplo tambm mostra como feita a inicializao no caso de
ponteiros.

C C++
Ponto p; Ponto p;
inicia(&p, 10, 20); p.inicia(10, 20);
Ponto p2(3,3);
Ponto *p =(Ponto*)malloc(sizeof(Ponto)); Ponto *p = new Ponto();
inicia(p, 19, 20); p->inicia(10, 20);

4 Sobrecarga de funes
Ocorre quanto uma classe possui mais de um mtodo com o mesmo nome, porm com diferentes tipos de
argumentos ou nmero de argumentos.

2
class Ponto{ Ponto(Ponto p)
private: {
int x,y; x = p.x;
public: y = p.y;
Ponto(float x1, float y1) }
{ Ponto()
x = (int)x1; {
y = (int)y1; x = 0;
} y = 0;
Ponto(int x1, int y1) }
{ };
x = x1;
y = y1;
}

5 Proteo de Dados e Funes


Uma das caractersticas da programao orientada a Objetos o encapsulamento. O C++ oferece 3 nveis
(modificadores) de proteo de mtodos e atributos:

public: mtodos e atributos podem ser acessados de qualquer parte do programa;


private: (valor default) Apenas mtodos da classe podem acessar. Tentativas de chamadas de mtodos
private fora da classe resultam em erro de compilao;
protected: Apenas mtodos da classe e derivados (herdados) tem acesso.

No prximo exemplo so ilustrados os vrios tipos de permisso de acesso a mtodos e atributos de classe. O
construtor deve ser sempre public.

class Ponto
{
// x e y s podem ser usadas por mtodos da classe e derivadas
protected:
int x, y;
//mtodo que s pode ser chamado por mtodos da classe Ponto2D
private:
bool podeMover(int x1, int y1)
{
if( (x+x1) < 100 && (y+y1)<100)
return 1;
return 0;
}
//mtodos pblicos
public: int main (void)
Ponto(int x1, int y1) {
{ Ponto p1(0, 0);
x = x1; y = y1; p1.podeMover(1,1);
} p1.imprime();
void move(int x1, int y1) p1.move(1,1);
{ p1.imprime();
if( podeMover(x1, y1) ) return 0;
{ }
x+=x1; y+=y1;
}
} no permitido. Erro
void imprime() de Compilao
{
printf("\nx= %d, y= %d", x, y);
}
};

6 Herana
o mecanismo que permite uma classe herdar todo o comportamento e atributos de outra classe. A classe que
herda chamada de subclasse e a que fornece chamada de superclasse. No construtor da subclasse pode-se
3
passar parmetros para o construtor da classe pai, como no seguinte exemplo. Neste exemplo, se na definio da
classe Cavalo no fosse chamado o construtor da classe Animal, geraria um erro de compilao pois no existe
um construtor default sem nenhum parmetro.

#include <stdio.h>

class Animal{
int idade;
public: //qualquer um pode chamar estes mtodos
Animal(int i) int main (void)
{ {
idade = i; Cavalo cavalo(10, 30);
} Animal animal(20);
void respira(void) cavalo.respira();
{ cavalo.corre();
printf("\nRespirando..."); animal.respira();
} return 0;
}; }

//Classe Cavalo herda os mtodos da classe Animal


class Cavalo : public Animal{
int velocidade;
public:
Cavalo(int i, int v): Animal(i) {
velocidade = v;
}
void corre(void)
{
printf("\nCorrendo a %d Km/h", velocidade);
}
};

7 Funes virtuais
Funes de uma classe podem ser redefinidas em classes derivadas. Isto chamado de overriden de funes. O
uso da palavra reservada virtual frente do mtodo informa ao compilador que podem existir novas definies
deste mtodo em classe derivadas. Quando uma funo virtual chamada, verificada a verso do objeto que a
chamou para que seja chamada a funo correspondente. No seguinte exemplo, a funo Desenha da classe
Figura, definida apenas nas classes derivadas.

#include <stdio.h>
class Figura{
public:
Figura()
{
}
//este mtodo virtual definido nas classes derivadas
virtual void Desenha()
{
printf("\nEu sou uma figura ");
}
//virtual float Area() = 0; //mtodo virtual puro
};
class FigRetangular: public Figura{
public:
4
FigRetangular() : Figura()
{
}
void Desenha()
{
printf("\nEu sou uma figura Retangular");
}
};
class FigOval: public Figura{
public:
FigOval() : Figura()
{
}
void Desenha();
};
// ***** Implementao do mtodo Desenha de FigOval ******
void FigOval::Desenha()
{
printf("\nEu sou uma figura oval");
}
int main()
{
Figura *f1, *f2;
f1 = new FigOval(); // inicializado com o tipo FigOval */
f2 = new FigRetangular(); // inicializado com o tipo FigRetangular
f1->Desenha(); //chama o mtodo da classe FigOval
f2->Desenha(); //chama o mtodo da classe FigRetangular
return 0;
}

Neste exemplo, o mtodo Desenha() de Figura virtual, ou seja, classes derivadas podem reimplementar este
mtodo. Por sua vez, o mtodo comentado virtual Area() = 0; est defindo como sendo virtual puro.
Neste caso todas as classes imediatamente derivadas de Figura devem obrigatoriamente implementar este
mtodo, que pode ser virtual mas no virtual puro.

Funes virtuais um recurso muito poderoso da linguagem C. Considere um outro exemplo, como no caso de
um jogo onde existem diversos tipos de personagens, como soldados, fuzileiros e tanques. Todos os personagens
podem realizar as mesmas funes como correr, atirar, fugir, procurar energia, perseguir o inimigo e morrer.

Inicialmente vamos considerar a implementao deste jogo sem usar funes virtuais e sem os demais recursos
da linguagem C++. Supondo que um time controlado pelo computador (adversrio) possui vrias unidades de
vrios tipos. Para controlar estas unidades, na implementao pode-se criar listas dinmicas para cada tipo de
personagem. Assim, vai ter uma lista com todos os soldados, outra com os fuzileiros e outra com os tanques.
Quando o jogo est sendo executado, cada unidade deve realizar suas aes, como se deslocar, perseguir o
inimigo e atirar. Para isso, o seguinte algoritmo poderia ser utilizado.

for(int i=0; i < numSoldados; i++)


{
processaSoldado(soldado[i]);
}
for(int i=0; i < numFuzileiros; i++)
{
processaFuzileiro(fuzileiro[i]);
}
for(int i=0; i < numTanques; i++)
{
processaTanque(tanque[i]);
}

Esta mesma estrutura pode ser utilizada em diversos locais do jogo, com por exemplo para a) avaliar o nvel de
vida de cada uma das unidades para descobrir se existe alguma que necessite de reparo, b) para avaliar
mensagens recebidas, ou c) para fazer a renderizao grfica das unidades. Para isso, uma estratgia um pouco

5
melhor seria usar uma lista (vetor) heterognea, onde cada elemento da lista (vetor) armazena um ponteiro void e
um inteiro indicando o tipo de informao armazenada.

#define N 100
typedef struct no
{
int tipoUnidade; //pode ser SOLDADO, FUZILEIRO ou TANQUE.
void *unidade;
}No;
No unidade[N];
for(int i=0; i<N; i++)
{
switch(unidade[i].tipoUnidade)
{
case SOLDADO:
processaSoldado((Soldado*)unidade[i].unidade);
break;
case FUZILEIRO:
....
}
}

Utilizando-se os recursos da linguagem C++, este problema seria resolvido da seguinte forma:

for(i=0; i<numUnidades; i++)


{
unidade[i].processa();
}

Alm do fato de ser um cdigo muito mais compacto, tambm apresenta uma outra vantagem de maior
importncia ainda. Considere que em um determinado momento, seja necessrio incluir mais um tipo de unidade
no jogo: o avio. Para os dois primeiros casos, deve-se alterar o cdigo pela adio de mais um for() e mais um
case, respectivamente, em todos os locais do programa onde os personagens so processados. Para o ltimo caso,
nada precisa ser alterado. Basta criar uma nova classe avio, tambm derivada da classe UnidadeMovel.

8 Estruturao de um programa C++


Programas escritos em C++ so compostos por arquivos .cpp e arquivos .h. Nos arquivos .h encontram-se a
definio das classes, atributos e mtodos, porm tambm permitida a colocao de cdigo. Os arquivos .cpp
possuem as implementaes dos mtodos descritos nos arquivos .h. Para o exemplo da Seo 7, poderiam ser
gerados 4 arquivos: dois de prottipos e dois de implementao.

Arquivo Ponto.h - Definio da classe Ponto

#ifndef __PONTO_H__
#define __PONTO_H__
#include <iostream>
class Ponto
{
int x, y;
public:
Ponto();
Ponto(const Ponto &p); //copy constructor
Ponto(int x1, int y1);
void imprime();
};
#endif

6
Arquivo Ponto.cpp - Implementao da classe Ponto

#include <stdio.h>
#include "Ponto.h" Define o escopo
Ponto::Ponto()
{
x = y = 0;
}
Ponto::Ponto(int x1, int y1)
{
x = x1; y = y1;

}
Ponto::Ponto(const Ponto &p)
{
x = p.x;
y = p.y;
}
void Ponto::imprime()
{
printf("\n Dados do ponto: (x=%d, y=%d) ", x, y);
}

Arquivo Circ.h - Definio da classe Circ

#ifndef __CIRC_H__
#define __CIRC_H__
#include "Ponto.h"

class Circ : public Ponto


{
int raio;
public:
Circ(Ponto p, int r);
void imprime();
};
#endif

Arquivo Circ.cpp - Implementao da classe Circ

#include <stdio.h>

#include "Circ.h"
Circ::Circ(Ponto p, int r): Ponto(p)
{
raio = r;
}
void Circ::imprime()
{
printf("\nRaio do circulo: %d", raio);
Ponto::imprime();
}

main.cpp deve incluir os arquivos Ponto.h e Circ.h

#include "Ponto.h"
#include "Circ.h"
void main (void)
{

7
Ponto p1(10, 40);
Circ c1(p1, 40);
p1.imprime();
c1.imprime();
}

9 Exemplo Comparativo entre C e C++


#include <stdio.h> #include <stdio.h>
typedef struct{ class Ponto{
int x,y; private:
}Ponto; int x,y;
void setPonto(Ponto *p, int x, int y) public:
{ Ponto(int x1, int y1)
p->x = x; {
p->y = y; x = x1;
} y = y1;
void imprimePonto(Ponto p) }
{ void imprime()
printf("\n\nDados do ponto: "); {
printf("x= %d, y= %d", p.x, p.y); printf("\n\nDados do ponto: ");
} printf("x=%d,y=%d", x,y);
}
};

typedef struct { class Circ: public Ponto{


Ponto p; int raio;
int raio; public:
}Circ; Circ(int x, int y, int r):Ponto(x,y)
void setCirculo(Circ *c, Ponto p, int r) {
{ raio = r;
c->p = p; }
c->raio = r; void imprime()
} {
void imprimeCirculo(Circ c) printf("\nDados do circulo:");
{ printf("%d", raio);
printf("\n\nDados do Circulo: "); Ponto::imprime();
printf("x=%d,y=%d", c.p.x, c.p.y); }
printf(" Raio=%d", c.raio); };
}

void main (void) int main (void)


{ {
Ponto p1; Ponto p1(10, 40);
Circ c1; Circ c1(1, 2, 40);
setPonto (&p1, 10, 20); p1.imprime();
setCirculo (&c1, p1, 40); c1.imprime();
imprimePonto(p1); return 0;
imprimeCirculo(c1); }
}

8
10 Namespace (Por Vitor Conrado, Cesar Pozzer)
Namespace um espao ou uma regio, dentro de um programa, onde um nome (uma varivel, uma funo, uma
classe, etc..) considerado vlido. Bjarne Stroustrup [4] (o criador da linguagem C++) diz em seu livro que
namesapce um mecanismo para expressar agrupamentos lgicos.

Este conceito apareceu porque as primeiras linguagens de programao (como o caso do BASIC) s tinham as
chamadas Global Variables, isto , uma varivel que estaria presente durante todo o programa - mesmo dentro
das funes. Isto tornava a manuteno de programas grandes uma tarefa muito difcil. Para resolver o problema
as novas linguagens de programao criaram o conceito de namespace. A linguagem C++ permite que o prprio
programador crie o seu namespace em qualquer parte do programa. Isso muito bom para quem cria bibliotecas
e quer manter os nomes das suas funes nicas, quando integradas com bibliotecas de outros programadores.

O uso de namespace aconselhado para programas que tenham um grande nmero de bibliotecas, pois facilita a
organizao e a identificao do escopo de cada funo/varivel/classe. interessante tambm, j que permite
que existam funes com mesmo nome em namespaces diferentes, que tambm uma das vantagens do uso de
classes.

#include <iostream>
int main(){
std::cout<<"Ola Mundo !!! "<<std::endl;
return 0;
}

cout (que faz o papel da funo printf do C) est no escopo std, por isso foi necessria a utilizao do
operador de escopo :: para sua utilizao. O mesmo programa poderia ser escrito assim:

#include <iostream>
using namespace std;
int main(){
cout<<"Ola Mundo !!! "<<endl;
return 0;
}

Neste segundo exemplo a linha using namespace std; indica ao compilador que est sendo utilizado o
escopo std, desta forma no mais necessrio utilizar o operador de escopo. Este mesmo exemplo ainda poderia
ser escrito da seguinte forma:

#include <iostream>
using std::cout;
using std::endl;
int main(){
cout<<"Ola Mundo !!! "<<endl;
return 0;
}

Neste terceiro exemplo indicado que sero usados cout e endl do escopo std, as demais
funes/variveis/classes do escopo std devero ser utilizadas usando o operador de escopo std::.

OBS: no existe diferena quanto ao tamanho do programa final com a utilizao de using namespace std;
ou using std::cout; using std::endl; ..., (dvida encontrada em fruns de discusso).

Criando Namespace

A sintaxe para a criao de namespace :

namespace Nome{
[Classes]

9
[Funes]
[Variveis]
...
}

Exemplo Arquivo de Interface Teste.h:

namespace Teste2
{
void func2();
}

namespace Teste
{
class MinhaClasse
{
int valor;
public:
MinhaClasse();
void func();
};

void func();
int a;
}

Exemplo Arquivo de Implementao Teste.cpp

#include <iostream>
#include "teste.h"

using namespace std;

// aqui poderia usar tambm


// using namespace Teste; e
// using namespace Teste2;

void Teste2::func2(){
cout<<"Funcao 2, dentro do namespace Teste2"<<endl;
}

//construtor de MinhaClasse, definida no namespace Teste.


//O escopo da classe ainda deve ser incluido
Teste::MinhaClasse::MinhaClasse()
{
this->valor = 10;
cout<<"Construtor da classe Classe"<<endl;
}

void Teste::Classe::func()
{
cout<<"Valor: "<<valor<<endl;
}

Exemplo Arquivo main.cpp

// main.cpp
#include <stdio.h>
#include "teste.h"

10
using namespace std;
using namespace Teste;
using Teste2::func2;
// ou using namespace Teste2;

int main()
{
Classe c;
printf("Ola Mundo");
func2();
c.func();
}

O uso de namespaces permite que sejam criadas funes com mesmo nome em escopos diferentes, porm ainda
existe o problema de existirem namespaces com nomes iguais quando se utiliza bibliotecas de terceiros. Por isso
aconselhado que se utilize nomes pouco comuns ou grandes para namespaces. Para facilitar a utilizao desses
namespaces pode ser criado um alias, da seguinte forma:

namespace Exemplo_de_Namespace{
...
}
namespace EN = Exemplo_de_Namespace;

EN::func();

11 Sobrecarga de Operadores
Da mesma forma como mtodos, pode-se tambm fazer a sobrecarga de operadores, o que permite a realizao
de operaes sobre tipos de dados no bsicos sem a necessidade de chamadas de funes especficas.
A seguinte tabela ilustra a lista de todos os operadores que podem ser sobrecarregados.

+ - * / = < > += -= *= /= << >> <<= >>= == !=


<= >= ++ -- % & ^ ! | ~ &= ^= |= && || %= []
() new delete

A definio de sobrecarga feita pela definio de mtodos de uma classe cujo nome operator seguido pelo
operador que se deseja sobrecarregar. O seguinte exemplo ilustra a definio da classe Vector3, para
manipulao de vetores.

class Vector3
{
public:
float x, y, z;
Vector3(float vx, float vy, float vz)
{
x = vx; y = vy; z = vz;
}
Vector3(const Vector3& u)
{
x = u.x; y = u.y; z = u.z;
}

void operator+= (const Vector3& v)


{
x += v.x; y += v.y; z += v.z;
}

11
//produto vetorial entre dois vetores
Vector3 operator ^ (Vector3& v)
{
Vector3 aux( y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x );
return( aux );
}

Vector3 operator + (const Vector3& v)


{
Vector3 aux( x + v.x, y + v.y, z + v.z );
return( aux );
}

void imprime( ) const


{
printf("%f %f %f", x, y, z);
}
};

Neste exemplo pode-se observar o surgimento de dois operadores: const e &. O operador const usado para
assegurar que o parmetro passado para a funo no poder ser alterado. O operador & indica que o parmetro
ser passado por referncia, porm todas as operaes sobre ele e em sua chamada so como se fosse uma
varivel passada por valor. O operador const ao lado da declarao da funo indica que a funo no poder
alterar nenhum membro da classe.

Com a definio destes operadores, pode-se facilmente somar, incrementar e calcular o produto vetorial de dois
vetores, como no seguinte exemplo.

Vector3 v1(1,1,1), v2(2,2,2), v3(1,1,1);


v1 += v2;
v1.imprime();
v3 = v1^v2;
v3.imprime();

A implementao de uma API para fornecer suporte a manipulao de vetores, em C++, de vital importncia
para acelerar o desenvolvimento de um jogo ou aplicativo grfico. Toda API deve operar sobre uma estrutura
que define como o vetor est alocado.

O nome da estrutura varia segundo o gosto de cada programador. comum encontrar definies como Vector,
Vector3, Vector3D, dentre outras. Neste documento, adotado o nome Vector3. O elenco de operaes
implementadas pode ser muito amplo, podendo contemplar a soma de vetores, multiplicao, rotao, ngulos,
produtos escalares, dentre outros. Cabe como exerccio a criao desta API.

12 Mtodos Inline
Funes inline so comuns em C++, tanto em funes globais como em mtodos de classes. Estas funes tm
como objetivo tornar o cdigo mais eficiente. Elas so tratadas pelo compilador quase como uma macro: a
chamada da funo substituda pelo corpo da funo. Para funes pequenas, isto extremamente eficiente, j
que evita gerao de cdigo para a chamada e o retorno da funo.

Este tipo de otimizao normalmente s utilizado em funes pequenas, pois funes inline grandes podem
aumentar muito o tamanho do cdigo gerado. Do ponto de vista de quem chama a funo, no faz nenhuma
diferena se a funo inline ou no.

Nem todas as funes declaradas inline so expandidas como tal. Se o compilador julgar que a funo muito
grande ou complexa, ela tratada como uma funo normal. No caso de o programador especificar uma funo
como inline e o compilador decidir que ela ser uma funo normal, ser sinalizada uma warning. O critrio de
quando expandir ou no funes inline no definido pela linguagem C++, e pode variar de compilador para

12
compilador. Para a declarao de funes inline foi criada mais uma palavra reservada, inline. Esta deve
preceder a declarao de uma funo inline:

inline double quadrado(double x)


{
return x * x;
}

Alguns detalhes devem ser levados em considerao durante a utilizao de funes inline. O que o compilador
faz quando se depara com uma chamada de funo inline? O corpo da funo deve ser expandido no lugar da
chamada. Isto significa que o corpo da funo deve estar disponvel para o compilador antes da chamada. Um
mdulo C++ composto por dois arquivos, o arquivo com as declaraes exportadas (.h) e outro com as
implementaes (.c ou .cpp). Tipicamente, uma funo exportada por um mdulo tem o seu prottipo no .h e sua
implementao no .cpp. Isso porque um mdulo no precisa conhecer a implementao de uma funo para us-
la. Mas isso s verdade para funes no inline. Por causa disso, funes inline exportadas precisam ser
implementadas no .h e no mais no .cpp.

13 Templates
A sobrecarga de funes permite a declarao de mtodos com mesmo nome e diferentes tipos de parmetros.
Porm, para cada tipo de parmetro, um novo mtodo deve ser definido. Uma soluo para este problema o uso
de Templates, que permitem criar funes genricas que admitem qualquer tipo de parmetro para argumentos e
retorno. O seguinte exemplo ilustra a sintaxe para definio de uma funo template que retorna o maior valor
entre dois nmeros de mesmo tipo.

template <class GenericType>


GenericType getMax (GenericType a, GenericType b)
{
return ( a>b ? a:b );
}

A funo getMax pode ser chamada com qualquer tipo de parmetro, que ser substitudo por GenericType em
tempo de execuo. No seguinte exemplo a funo getMax chamada com parmetros inteiros e long.

template <class T> int main ()


T GetMax (T a, T b) {
{ i nt i=5, j=6, k;
T result; long l=10, m=5, n;
result = (a>b)? a : b; k = GetMax<int>(i, j);
return result; n = GetMax<long>(l, m);
} k = GetMax (i, j);
n = GetMax (l, m);
return 0;
}

A definio do tipo de parmetro <int>, <long> opcional pois o compilador detecta automaticamente o tipo e
o converte. Caso os parmetros forem de tipos diferentes, deve-se definir o Template com dois tipos genricos

template <class T, class U>


T GetMin (T a, U b)
{
return (a<b?a:b);
}

Templates tambm podem ser definidos para comportar classes, que podem conter mtodos com parmetros
genricos, como no seguinte exemplo:

13
#include <stdio.h>

template <class T>


class Ponto
{
T x, y;
public:
Ponto (T xx, T yy)
{
x = xx;
y = yy;
}
T getX()
{
return x;
}
T getY()
{
return y;
}
};

A definio de um objeto do tipo par chamado Ponto, para armazenar dois valores inteiros, tem a seguinte
sintaxe:

int main()
{
Ponto<int> p1(2115, 360);
Ponto<float> p2(1.66, 0.1);
int i = p1.getX();
printf("%d", i);
return 0;
}

14 STL - Standard Template Library


STL um conjunto de tipos abstratos de dados e funes projetados para manipularem diferentes tipos de dados
de forma transparente. As operaes sobre os dados so realizadas por mtodos que tambm aceitam tipos de
dados genricos. Como o prprio nome diz, STL faz uso de templates, j definidos, para implementao de
diversos algoritmos que manipulam dados de forma eficiente, como por exemplo vetores, dinmicos, listas,
pilhas, etc. No STL tambm foi adicionado um tipo String, que facilita as operaes de manipulao de
caracteres quando comparado a biblioteca string.h da linguagem C. Alm disso, tambm existem funes de
busca, ordenao, dentre outros.

Nesta seo sero abordadas 3 estruturas seqenciais: vetor, fila dupla (Deque Double End Queue) e lista. A
escolha de uso dada em funo das operaes que se deseja realizar sobre dos dados. A seguinte tabela mostra
o tempo gasto para diferentes operaes sobre cada um dos tipos de representao.

Tabela 1: Tempo de execuo de diferentes operaes [10]


Operao Vector Deque Lista
Acessar o primeiro elemento Constante Constante Constante
Access ltimo elemento Constante Constante Constante
Accessar elementos randmicos Constante Constante Linear
Add/Delete no incio Linear Constante Constante
Add/Delete no final Constante Constante Constante
Add/Delete randomicamente Linear Linear Constante

Ao se usar STL, deve-se ter em mente o conceito de namespace, que permite agrupar classes, objetos e funes e
associ-los a um nome, o que facilita a quebra de escopos globais em subescopos menores. Para acessar as
variveis a e b do seguinte exemplo, deve-se indicar o escopo associado usando-se o operador ::.
14
namespace teste
{
int a, b;
}

int main()
{
teste::a = 8;
printf("%d", teste::a);
return 0;
}

Em STL, todas as classes, objetos e funes so definidos com o namespace std. Pode-se usar o operador de
escopo a cada uso da STL ou indicar o namespace corrente, da seguinte forma:

using namespace std;

Para fazer o percorrimento de todos os elementos da estrutura so usados Iterators. Eles podem ser vistos como
ponteiros para posies especficas da estrutura. Nas prximas sees so apresentados vrios exemplos do uso
de namespace e iterators para 3 tipos de containers STL.

14.1 Vector

O tipo vector similar a um array, com a diferena que possui tamanho dinmico. As principais funes
definidas so:

begin() Retorna um iterator para o incio do vetor


end() Retorna um iterator para o final do vetor
push_back() Adiciona elemento no final do vetor
pop_back() Destri elemento no final do vetor
Size() Nmero de elementos do vetor
[] Operador de acesso randmico

Exemplo sem namespace global Exemplo com namespace global


#include <stdio.h> #include <stdio.h>
#include <stdio.h> #include <stdio.h>
#include <vector> #include <vector>

int main(void) using namespace std;


{
int val; int main(void)
std::vector<int> v; {
std::vector<int>::iterator iter; int val;
vector<int> v;
printf("Digite alguns inteiros: "); vector<int>::iterator iter;
do{
scanf("%d", &val); printf("Digite valores: ");
v.push_back(val); do{
}while(val!=-1); scanf("%d", &val);
v.push_back(val);
for( iter=v.begin(); iter != v.end(); iter++ ) }while(val!=-1);
printf("%d ", *iter);
return 0;
//acesso com o operador randomico }
for( int i=0; i<v.size(); i++)
printf("%d ", v[i] );
return 0;
}

15
14.2 Deque

Uma Deque muito similar a um vetor, com a caracterstica de apresentar rpida insero e remoo de
elementos no incio e no final. Possui funes de acesso iguais ao Vector, e duas adicionais:

push_front( ) Adiciona elemento no incio da Deque


pop_front( ) Destroi elemento no incio da Deque

Para usar este template, deve-se adicionar a diretiva #include <deque>.

14.3 List

O tipo List, como mostrado na Tabela 1, deve ser usado preferencialmente quando existem muitas inseres e
remoes de dados em posies intermedirias. Em todas as demais operaes, por no possuir o operador [],
tem um alto custo computacional. O tipo List faz uso de uma implementao com listas duplamente encadeadas,
o que necessita grande consumo de memria. Os principais mtodos so semelhantes ao Deque.

#include <stdlib.h> int main( void )


#include <list> {
//lista de ponteiros para Vector
using namespace std; list<Vector*> lista;
list<Vector*>::iterator iter;
class Vector
{ for(int i=0; i<3; i++)
int x, y; {
public: lista.push_front( new Vector(i, i) );
}
Vector(){ }
//insere elemento em posicao intermediaria
Vector(const int mx, const int my) iter = lista.begin();
{ iter++;
x = mx; lista.insert( iter, new Vector(20,20) );
y = my;
} for(iter = lista.begin();
void imprime() iter!=lista.end(); iter++)
{ {
printf("\n\nDados do ponto: "); Vector *v1 = *iter;
printf("x=%d, y=%d", x, y); v1->imprime();
} }
}; return 0;
}

15 Incluso Cruzada de Arquivos


Em algumas situaes, necessrio que duas classes se auto-referenciem. Como exemplo, suponha que existam
as classes Ator e Comportamento. A classe Ator tem uma instncia da classe Comportamento e a classe
comportamento faz uso de argumentos do tipo Ator. O Seguinte trecho de cdigo no funciona para este caso.

Ator.h Comportamento.h
#ifndef __ACTOR_H__ #ifndef __COMPORT_H__
#define __ACTOR_H __ #define __COMPORT_H __

#include "Vector.h" #include "Vector.h"


#include "Comportamento.h" #include "Ator.h"

class Ator class Comportamento


{ {
Vector pos, dir; int tipo;
Comportamento *c; public:
public: Comportamento(Ator *a, int tipo);
...

16
Ator(char *name, int id); };
...
};
#endif #endif
Ator.cpp Comportamento.cpp
#include "Ator.h" #include "Comportamento.h"
... ...

Para solucionar este problema, deve-se na interface da classe comportamento no incluir o arquivo Ator.h, mas
sim apenas declarar a existncia da classe Ator. No arquivo Comportamento.cpp deve-se adicionar a incluso do
arquivo Ator.h.

Ator.h Comportamento.h
#ifndef __ACTOR_H__ #ifndef __COMPORT_H__
#define __ACTOR_H __ #define __COMPORT_H __

#include "Vector.h" #include "Vector.h"


#include "Comportamento.h"
class Ator; //define a classe Ator
class Ator
{ class Comportamento
public: {
Vector pos, dir; int tipo;
Comportamento *c; public:
Comportamento(Ator *a, int tipo);
Ator(char *name, int id); ...
... };
};
#endif #endif
Ator.cpp Comportamento.cpp
#include "Ator.h" #include "Comportamento.h"
... #include "Ator.h" //inclui a classe Ator
...

16 Diagramas de Classe UML


A linguagem UML (Unified Modeling Language) uma ferramenta muito utilizada na modelagem Orientada a
Objetos. O diagrama mais comum desta linguagem o Diagrama de Classes, utilizado para descrever os
relacionamentos entre as classes que compem a aplicao. Nesta seo feita uma abordagem introdutria
sobre os principais recursos do diagrama de classes. Para definir uma classe, utiliza-se um retngulo que pode ser
dividido em 3 regies: nome da classe, atributos e operaes.
Nome Classe Carro
Atributos -Velocidade: vetor
+Direo: vetor
Operaes #Posio
+setPos(amount)
+setDir()
+setVel()
+getPos():vector

Para este exemplo, a classe chamada Carro, tem 3 atributos (Velocidade, Direo e Posio) e 4 mtodos. O
atributo Velocidade private (-), Direo public (+) e Posio protected (#). Todos os mtodos so public e o
mtodo getPos() retorna um vector.

Pode-se definir o relacionamento entre classes por meio de Associao, Herana ou Dependncia. No
relacionamento de Associao, utiliza-se uma linha slida para descrever o relacionamento. No seguinte
exemplo, o carro de corrida dirigido por at um piloto e o piloto dirige no mximo 1 carro de corrida. Cada
carro de corrida pode ter vrios patrocinadores, mas cada patrocinador pode ter exatamente 1 carro de corrida (o
parmetro 1 pode ser omitido neste caso). Cada carro de corrida pode ter um nmero qualquer de espectadores.
Neste caso, o carro de corrida no sabe quais so os seus espectadores (devido linha direcionada).

17
Para a definio de herana, utiliza-se uma seta direcionada apontando na direo do pai da classe, como
mostrado no seguinte exemplo.

Espectador Patrocinador

0..*

* 1
0..1 Dirigido por >
CarroCorrida Piloto
< Dirige 0..1

Carro

CarroCorrida CarroLazer

O ltimo exemplo de relacionamento por dependncia. Este ocorre quando, por exemplo, um mtodo de uma
classe recebe como parmetro uma instncia de uma outra classe. Utiliza-se uma linha pontilhada direcionada.
CarroCorrida Vector
<<posio>>
+setPos(vector)

17 Estrutura de um programa Grfico em C++ com OpenGL


Ao se analisar um cdigo fonte (supostamente para compreender como ele funciona), inicialmente abre-se o
arquivo main.cpp, para ento comear a analisar classes mais gerais para depois, se necessrio, olhar as classes
mais especficas. Deste modo, para facilitar a compreenso do cdigo, as classes de mais alto nvel devem ser
simples, com pouco cdigo e com poucas funes matemticas. Em um jogo, por exemplo, podem existir classes
Carro, Cenario, Manager, IA, Vector, Fisica, Math, etc.

Considere um programa em OpenGL, ou implementado por meio da Canvas2D, que implemente um veculo
controlado pelo usurio por meio do teclado. Para garantir uma funo main() compacta, todos os cdigos de
tratamento de eventos de mouse/teclado devem ser repassados para classes especializadas, como no seguinte
exemplo:

void keyboardFunc(unsigned char key, int x, int y)


{
case seta_frente:
carro->move(1);
case seta_left:
...
}

No se deve na funo keyboardFunc(), por exemplo, determinar a nova posio do carro. Os clculos de
posio e direo envolvem conceitos matemticos que devem estar encapsulados dentro da classe Carro ou
classes herdadas ou associadas.

Como uma aplicao grfica executa continuamente, pela chamada da funo render(), caso for pressionada
uma tecla para mover o carro para frente, deve-se evitar de incrementar a posio do carro na chamada move().
18
Deve-se indicar na classe Carro que a tecla foi pressionada e cada vez que a render() do carro for chamada,
deve-se ento incrementar a posio do veculo. Isso tambm reduz a utilizao de variveis globais.

A funo render() da main() deve mais uma vez ser compacta e deve apenas invocar os mtodos
render() dos objetos que compem a aplicao.

void render()
{
camera->render();
carro->render();
cenario->render();
text->render()
...
}

Obviamente que para se obter um cdigo bem estruturado deve-se investir um tempo na especificao das
classes e hierarquias.

Apesar da interface do OpenGL ser em linguagem C, pode-se encapsul-lo em uma classe C++, como no
seguinte exemplo.

Arquivo myGL.h
class myGL
{
public:
myGL(int argc, char* argv[]);
private:
//estes metodos devem ser estaticos
static void callbackDisplay();
static void callbackKeyboard(unsigned char key, int x, int y);

void render();
};

Arquivo myGL.cpp
#include <GL/glut.h>
#include <stdio.h>
#include "myGL.h"

myGL *_this; //guarda referencia para o objeto para ser usado em mtodos estticos

myGL::myGL(int argc, char* argv[])


{
_this = this;
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);
glutCreateWindow ("GLUT");

glutDisplayFunc(this->callbackDisplay);
glutKeyboardFunc(myGL::callbackKeyboard);

glutMainLoop();
}

void myGL::callbackDisplay()
{
_this->render();
}

void myGL::callbackKeyboard(unsigned char key, int x, int y)


{
printf("\nTecla pressionada: %d" , key);

19
}

void myGL::render()
{
//cdigo de desenho
}

Desta forma, a funo main() de uma aplicao grfica em OpenGL pode ser escrita da seguinte forma:
int main (int argc, char* argv[])
{
new myGL();
}

18 Exerccios
1.Definir uma hierarquia de classes para a especificao de:
a. Um veculo;
b. Quadro de funcionrios de uma empresa;
c. Jogo composto por um cenrio, personagens de vrios tipos, aes e troca de mensagens entre personagens;
2. Implemente um editor de figuras geomtricas utilizando STL e funes virtuais. Implemente o mesmo editor
na linguagem C para analisar vantagens da linguagem C++.
3. Implemente a classe Vector2 que disponibiliza operaes sobre vetores 2D.
4. Implemente a classe Vector3 que disponibiliza operaes sobre vetores 3D.

19 Referncias Bibliogrficas
[1] Souli, J. CPP Tutorial. Disponvel em: http://www.cplusplus.com/doc/tutorial/
[2] Ottewell, P. STL Tutorial. Disponvel em: http://www.yrl.co.uk/~phil/stl/stl.html
[3] Borges, R., Clinio, A. L. Programao Orientada a Objetos com C++. Tutorial
[4] Stroustrup, B. The C++ Programming Language. Addison-Wesley Professional, 3 edition, 911 p., 2000.
[5] Buckland, M. Programming Game AI by Example. Wordware publishing Inc, 2005.
[6] Nathan Myers. Artigos C++ no Mundo Real. Disponvel em:
http://www.arnaut.eti.br/op/CPPAR002.htm
[7] Resources Network, Namespaces. Disponvel em:
http://www.cplusplus.com/doc/tutorial/namespaces.html
[8] BUENO, A. D., Apostila de Programao Orientada a Objeto em C++. Disponvel em:
http://www.apostilando.com/download.php?cod=283&categoria=C%20e%20C++
[9] The Standard Template Library Tutorial. Disponvel em:
http://www.infosys.tuwien.ac.at/Research/Component/tutorial/prwmain.htm
[10] Phil Ottewell's STL Tutorial. Disponvel em: http://www.pottsoft.com/home/stl/stl.htmlx
[11] Bjarne Stroustrup's homepage. Disponvel em http://www.research.att.com/~bs/homepage.html

20

Você também pode gostar