Buscar

Apostila_C++

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 3, do total de 144 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 6, do total de 144 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 9, do total de 144 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Prévia do material em texto

1 
 
 
 2 
Capítulo I – Introdução a Linguagem C++ ____________________________________ 3

1. ESTRUTURA BÁSICA DE UM PROGRAMA EM C++ __________________________ 3

1.1 - Primeiro Programa______________________________________________________________ 3

1.2 - Variáveis _____________________________________________________________________ 4

1.2.1 - Constantes ________________________________________________________________ 4

1.3 - Operadores____________________________________________________________________ 5

1.4 - Comentários___________________________________________________________________ 6

1.5 - Fluxo de Controle ______________________________________________________________ 7

1.5.1 - Comando if () {} _______________________________________________________ 7

1.5.2 - Comando for( ; ; ) {} _________________________________________________ 8

1.5.3 - Comando while() {} e do { } while();______________________________ 11

1.5.4 - Comando break e continue ______________________________________________ 14

1.6 - Funções _____________________________________________________________________ 15

1.6.1 – Referência _______________________________________________________________ 17

2 - VETORES E MATRIZES__________________________________________________ 19

2.1 - Vetores______________________________________________________________________ 19

2.1.1 - Declaração _______________________________________________________________ 19

2.1.2 – Exemplo: Método de Ordenação______________________________________________ 20

2.2 - Matrizes _____________________________________________________________________ 21

3 - PONTEIROS ____________________________________________________________ 22

3.1 - Introdução ___________________________________________________________________ 22

3.2 – Principais Aplicações de Ponteiros________________________________________________ 22

3.3 – Armazenando o Endereço das Variáveis ___________________________________________ 22

3.4 – Acessando o conteúdo de um endereço ____________________________________________ 23

3.5 – Ponteiros com Vetores _________________________________________________________ 24

3.6 – Alocação de Vetores Dinamicamente______________________________________________ 25

3.7 – Alocação de Matrizes Dinamicamente _____________________________________________ 26

4 – OBJETOS E CLASSES ___________________________________________________ 27

4.1 – Membros da Classe____________________________________________________________ 27

4.2 – Construtores _________________________________________________________________ 28

4.3 – Controle de Acesso aos Campos e Funções _________________________________________ 30

4.3.1 - Seção Pública_____________________________________________________________ 30

4.3.2 - Seção Privada_____________________________________________________________ 30

Exemplo 1: ____________________________________________________________________ 30

Exemplo 2: ____________________________________________________________________ 30

4.3 – Funções Membros_____________________________________________________________ 31

4.3.1 - Introdução _______________________________________________________________ 31

4.3.2 – Acesso as variáveis da classe ________________________________________________ 31

4.3.4 – Exemplo de uma Classe Vetor _______________________________________________ 35

 
 3 
Capítulo I – Introdução a Linguagem C++ 
 
C++ é uma linguagem de programação orientada a objeto desenvolvida por Bjarne 
Stroustrup. 
1. ESTRUTURA BÁSICA DE UM PROGRAMA EM C++ 
 
Em C++ os programas são escritos utilizando-se classes. Inicialmente vamos aprender os 
comandos básicos do C++ e na seção 3 discutiremos o funcionamento das classes e a 
orientação a objeto. 
1.1 - Primeiro Programa 
 
Como primeiro exemplo, consideremos o programa modelo do software Eclipse: 
 
Hello.cpp 
//==================================================================== 
// Name : Hello.cpp 
// Author : 
// Version : 
// Copyright : Your copyright notice 
// Description : Hello World in C++, Ansi-style 
//==================================================================== 
 
#include <iostream> 
using namespace std; 
 
int main() { 
 cout << "Hello World!!!" << endl; // prints Hello World!!! 
 return 0; 
} 
 
 
Os programas em C++ sempre iniciam pela função main() (o termo função será 
explicado depois), Seguindo o nome da função seguem as chaves {} que delimitam o 
início e o fim da função. 
Neste exemplo o cout e return são os dois únicos comandos da função main(). O 
comando cout imprime mensagens na tela padrão e como será visto mais tarde, também 
imprime o conteúdo de variáveis. Observe que após todo comando dentro de uma função 
segue um ponto e vírgula ( ; ). O comando return indica o fim da função e neste 
exemplo que o valor 0 é retornado como resultado da execução da função main. 
Os caracteres em branco são invisíveis para o compilador. Assim o programa acima 
também poderia ser (O cometário precisa ser retirado para que funcione): 
 
#include <iostream> 
using namespace std; 
int main() { cout << "Hello World!!!" << endl; return 0; } 
 
 4 
1.2 - Variáveis 
 
O programa a seguir exibe como é feita a declaração de algumas variáveis e sua utilização. 
 
Variáveis.cpp 
#include <iostream> 
using namespace std; 
 
int main() { 
 
 int n = 1; 
 float a = 2.3e10f; 
 double b = 34.5e200; 
 
 cout << "n = " << n << " a = " << a << " b = " << b << endl; 
} 
 
As primeiras linhas declaram as variáveis e os tipos: 
 
int n; 
Tipo da variável Nome da variável 
 
 Em seguda atribuimos o valor 1 para a variável: 
 
n = 1; 
 
O C++ tem diferentes tipos de variáveis. Os tipos básicos são: 
 
boolean 1-bit (TRUE ou FALSE) 
char 8-bit inteiro(signed) (-128 a 127) 
short 16-bit inteiro(signed) (–32.768 a 32.767) 
int 64-bit inteiro(signed)(-2.147.483.648 a 2.147.483 .647) 
float 32-bit floating-point (10e-38 a 10e38) 
double 64-bit floating point (10e-308 a 10e308) 
unsigned Retira o sinal e portanto troca a variação de valores, 
por exemplo: unsigned char varia de 0 a 255 
1.2.1 - Constantes 
 
Uma constante é um valor constante que é definido no programa de forma que não será 
alterado durante toda a execução. Para declararmos uma constante utilizamos o prefixo 
const, como no exemplo: 
 
Variaveis.cpp 
#include <iostream> 
int main() { 
 const int a = 1; 
 etc… 
} 
 5 
 
1.3 - Operadores 
 
Os operadores aritméticos sobre as variáveis são os seguintes: 
 
+ Soma 
- Subtração 
* Multiplicação 
/ Divisão 
% Resto da divisão 
 
A operação de incremento de uma unidade tem também um formato reduzido, ou seja, o 
comando: 
 
 i = i + 1; 
 
é freqüentemente representado por: 
 
 i++; 
 
Da mesma forma i = i-1; pode ser escrito como i--; 
 
Como exemplo dos operadores, o programa abaixo calcula as raízes reais de um polinômio 
de segundo grau: 
 
Raizes.cpp 
#include <iostream> 
#include <cmath> 
 
int main() { 
 
 double a, b, c; 
 double x1, x2; 
 
 a = 1; 
 b = -5; 
 c = 6; 
 x1 = (-b + sqrt(b * b - 4* a * c)) / (2 * a); 
 x2 = (-b - sqrt(b * b - 4* a * c)) / (2 * a); 
 
 std::cout << "x1 = " << x1 << " x2 = " << x2; 
} 
 6 
 
 
1.4 - Comentários 
 
É possível introduzir comentários dentro de um programa em C++. Há dois nos formatos 
básicos: 
 
Formato 1: 
/* Comentario pode prosseguir por varias 
 linhas e so termina ao encontar a marca de fim de 
 comentario */ 
 
 
Format 2: 
// Comentario somente até o final da linha 
 
 
Observe o exemplo abaixo: 
 
 
#include <iostream> 
#include <cmath> 
 
int main() { 
 
 /* Soluções reais da equação a*x*x + b*x + c = 0 */ 
 
 double x1, x2; 
 
 const double a = 1; // Valores arbitrarios para a, b e c 
 const double b = -5; 
 const double c = 6; 
 
 x1 = (-b + sqrt(b * b - 4* a * c)) / (2 * a); 
 x2 = (-b - sqrt(b * b - 4* a * c)) / (2 * a); 
 
 std::cout << "x1 = " << x1 << " x2 = " << x2; 
} 
 
 
 
 71.5 - Fluxo de Controle 
 
O comando principal de decisão é o if() { }. Os três formatos mais utilizados de laços 
são: 
 
for( ; ;) { } 
while() {} 
do { } while(); 
1.5.1 - Comando if () {} 
 
Através deste comando o fluxo do programa pode ser desviado para executar ou não um 
conjunto de comandos. Considere o exemplo abaixo: 
ParImpar.cpp 
#include <iostream> 
using namespace std; 
 
/** Testa se um numero e par ou impar */ 
int main() { 
 
 int i, n; 
 
 cout << "Ëntre com um numero inteiro: "; 
 cin >> n; // Entre com n 
 
 i = n % 2; 
 
 if (i == 0) { 
 cout << n << " e um numero par\n"; 
 } else { 
 cout << n << " e um numero impar\n"; 
 } 
} 
 
Neste exemplo a variável i armazena o resto da divisão de n por 2. Caso seja zero, então o 
programa passa a execução do comando cout << n << " e um numero par\n". Se a 
condição falha, o comando else indica que o programa deve executar o comando cout 
<< n << " e um numero impar\n". Observe que o else é um comando opcional. 
Caso você não o inclua, o programa segue para o próximo comando após o if. 
Os testes utilizam os seguintes operadores relacionais: 
< Menor 
> Maior 
<= Menor ou igual 
>= Maior ou igual 
== Igual 
!= Diferente 
 
&& e 
! negação 
|| ou 
 8 
 
1.5.2 - Comando for( ; ; ) {} 
 
O for é um comando apropriado quando queremos executar um conjunto de operações um 
número fixo de vezes, como no exemplo da seqüência de fibonacci: 
 
 
 
Fibonacci.cpp 
 
#include <iostream> 
#include <cmath> 
using namespace std; 
 
/** Gera a sequencia de Fibonacci */ 
 
const int MAX = 10; 
int main() { 
 int n; 
 int lo = 1; 
 int hi = 1; 
 cout << "1: 1 \n"; 
 for (n = 2; n <= MAX; n++) { 
 cout << n << ": " << hi << endl; 
 hi = lo + hi; 
 lo = hi - lo; 
 } 
 
} 
 
O resultado será: 
 1: 1 
 2: 1 
 3: 2 
 4: 3 
 5: 5 
 6: 8 
 7: 13 
 8: 21 
 9: 34 
 10: 55 
 9 
 
O comando for é composto de três argumentos: 
for( n=0 ; n<= 10 ; n++ ) 
 Expressão de inicialização Expressão de teste Incremento 
 
Expressão de inicialização 
Inicializa a variável do laço. A inicialização é feita uma única vez quando o laço inicia. 
 
Expressão de teste 
Esta expressão testa (a cada vez que o conjunto de comandos no interior do for finaliza), se 
o laço deve ser encerrado. Enquanto a expressão for verdadeira o laço é repetido. Para 
realizar teste utilizamos os operadores relacionais. 
 
Expressão de incremento 
A cada repetição do laço, o terceiro argumento (n++) incrementa a variável n. 
 
Exemplo: Métodos numéricos de integração (ponto a esquerda) 
 
Como aplicação do comando for o exemplo abaixo ilustra a implementação do método do 
ponto a esquerda. Podemos utilizar os métodos de integração para obter uma aproximação 
para a expansão decimal de . Se calcularmos: 
obteremos aproximações para . 
 
PontoEsquerda.cpp 
#include <iostream> 
#include <cmath> 
using namespace std; 
 
/* Integracao Numerica: Ponto a Esquerda */ 
 
int main() { 
 
 int i; 
 int n; 
 double x, dx; 
 double a, b; 
 double soma; 
 
 cout.precision(20); 
 
 a = -1; // Extremo inferior do intervalo 
 b = 1; // Extremo superior do intervalo 
 n = 1000; // Numero de particoes 
 
 soma = 0.0; 
 dx = (b - a) / n; 
 10 
 x = a; 
 for (i = 0; i < n; i++) { 
 soma = soma + 2* sqrt(1 - x * x) * dx; 
 x = x + dx; 
 } 
 cout << "\n Integral = " << soma ; 
 cout << "\n Pi = " << M_PI; 
 cout << "\n Erro = " << (soma - M_PI); 
} 
 
 
Exemplo: Métodos numéricos de integração (Monte Carlo) 
 
Neste método utilizamos um sorteio de pontos em uma certa região. O quociente do 
número de pontos que são sorteados no interior pelo número total de pontos é uma 
estimativa para a integral. 
 
MonteCarlo.cpp 
#include <iostream> 
#include <cstdlib> 
using namespace std; 
 
/* Integracao Numerica: Monte Carlo */ 
 
int main() { 
 
 double x, y, f; 
 int cont = 0; 
 const int points = 500000; 
 
 srand(1); 
 cout.precision(20); 
 
 for (int i = 0; i < points; i++) { 
 x = (double)rand()/ RAND_MAX; 
 y = (double)rand()/ RAND_MAX; 
 if ((x * x + y * y - 1) < 0) 
 cont++; 
 } 
 f = 4.0 * cont / points; 
 cout << "Pi = " << f << endl; 
} 
 
Exemplo: Métodos numéricos de integração (Método de Simpson) 
 
O método de Simpson refina o método do trapézio [Malta,Pesco,Lopes, Cálculo a uma 
variável – Vol II]. 
#include<iostream> 
#include<cmath> 
using namespace std; 
 
#define PI 3.14159265358979323846264338327950288419716939937510 
 
 11 
int main() { 
 int n; 
 double x, dx; 
 double a, b; 
 double soma; 
 cout.precision(20); 
 
 a = -1; // Extremo inferior do intervalo 
 b = 1; // Extremo superior do intervalo 
 n = 100000; // Numero de particoes 
 soma = 0.0; 
 dx = (b - a) / n; 
 x = a; 
 soma = 2 * sqrt(1 - a * a); 
 for (int i = 1; i < n; i++) { 
 x = x + dx; 
 if (i % 2 == 0) 
 soma = soma + 2 * 2*sqrt(1 - x * x); 
 else 
 soma = soma + 4 * 2*sqrt(1 - x * x); 
 } 
 soma = 2 * sqrt(1 - b * b); 
 soma = soma * dx / 3; 
 cout << "\n Integral = " << soma; 
 cout << "\n Pi = " << PI; 
 cout << "\n Erro = " << (soma - PI); 
} 
1.5.3 - Comando while() {} e do { } while(); 
 
Este segundo tipo de laço é adequado para situações onde não sabemos ao certo quantas 
vezes o laço deve ser repetido. 
 
Existem dois formatos: 
 
while (“condição”) { 
... 
comandos 
... 
} 
 
 Inicia testando se a condição é verdadeira, e em caso afirmativo, os comando dentro while 
são executados e ao final, a condição é novamente testada. Enquanto a condição 
permanecer verdadeira, os comandos no interior do while são repetidos. Observe que se a 
condição for falsa a primeira vez, em nenhum momento os comandos dentro do laço serão 
executados. 
 
do { 
... 
comandos 
... 
 12 
} while (“condição”); 
 
 Inicia executando os comandos e ao final, testa a condição. Se verdadeira, então os 
comandos são novamente executados. Enquanto a condição permanecer verdadeira, os 
comandos são repetidos. Observe que os comandos são executados no mínimo uma vez, 
mesmo que a condição seja falsa na primeira vez, sendo esta a diferença para o formato 
anterior while() {}. 
 
Os exemplos a seguir ilustram aplicações de ambos os casos: 
 
Exemplo: Método de Newton 
 
O programa abaixo determina as soluções da equação 
 
 
utilizando o método de Newton, ou seja, dada uma condição inicial e um erro máximo, a 
seqüência abaixo pode convergir para uma das soluções: 
 
#include <iostream> 
#include <cmath> 
using namespace std; 
 
/* Metodo de Newton */ 
int main() { 
 double xn, xn_1; 
 double erro; 
 
 xn = 2; // Condicao inicial 
 erro = 1e-10; // Erro maximo 
 cout.precision(20); 
 
 do { 
 xn_1 = xn; 
 xn = xn_1 - (xn_1 * xn_1 - 2) / (2 * xn_1); 
 cout << "Solucao parcial = " << xn << endl; 
 } while (fabs(xn - xn_1) > erro); 
 
 cout << "Solucao obtida = " << xn << endl; 
 cout << "Raiz 2 = " << M_SQRT2 << endl; 
} 
 
 
 13 
Exemplo: Método da Bisseção 
 
O programa abaixo determina as soluções da equação: 
 
 
 
Para isso utilizaremos o método da bisseção. No método da bisseção procuramos uma 
solução contida em certo intervalo [a,b] dado. A solução existe desde que a função seja 
contínua, e o sinal da função troque de um extremo para outro (ou seja 
f(a) * f(b) < 0). 
 
Bissecao.cpp 
#include <iostream> 
#include <cmath> 
using namespace std; 
 
int main() { 
 double a,b,c; 
 double fa,fb,fc; 
 const double erro = 0.0000001; 
 
 cout.precision(20); 
 cout << "Entre com o extremo a: "; 
 cin >> a; 
 cout << "Entre com o extremo b: "; 
 cin >> b; 
 
 fa = a*a - 2; 
 fb = b*b - 2; 
 
 if ((fa * fb) > 0) { 
 cout << "Intervalo inicial nao garante existencia de 
solucao ! \n"; 
 return 0; 
 } 
 
 while(fabs(a-b) > erro) { 
 c = (a+b)/2.0; 
 fc = c*c - 2.0; 
 
 if (fa * fc < 0) { 
 b = c; 
 } 
 else { 
 if (fb * fc < 0) 
 a = c; 
 else 
 break; 
 } 
 cout << "Solucao parcial = " << c << endl; 
 } 
 cout << "Solucao obtida = " << c << endl; 
 cout << "Raiz 2 = " << M_SQRT2 <<endl; 
} 
 14 
 
1.5.4 - Comando break e continue 
 
Estes dois comando servem para auxiliar na interrupção do laço, cumprindo diferentes 
tarefas: 
 
- O comando break; interrompe o laço (Qualquer dos formatos apresentados) e o 
programa continua no primeiro comando após o laço. Exemplo: 
 
Exemplobreak.cpp 
 
#include <iostream> 
using namespace std; 
 
int main() { 
 
 int n = 0; 
 
 while (n < 10) { 
 cout << "n = " << n << endl; 
 if (n > 3) 
 break; 
 n++; 
 } 
 cout << "Fim do programa \n"; 
} 
 
 
O resultado deste programa será: 
 
n = 0 
n = 1 
n = 2 
n = 3 
n = 4 
Fim do programa 
 
- O comando continue; transfere a execução do programa para o teste do laço, que 
pode ou não prosseguir, conforme a condição seja verdadeira ou falsa. 
 
 15 
1.6 - Funções 
 
As funções cumprem como primeiro papel evitar repetições desnecessárias de código. Nos 
exemplos anteriores foi necessário calcular o valor y = x*x-2 em diversas partes do 
programa. Se desejássemos trocar a função, seria necessário alterar várias partes do código. 
Para evitar isso, podemos utilizar uma função como no exemplo abaixo: 
Bissecao.cpp 
#include <iostream> 
#include <cmath> 
using namespace std; 
 
float f(float x) 
{ 
 float y; 
 y = x*x-2; 
 return(y); 
} 
 
int main() { 
 double a,b,c; 
 double fa,fb,fc; 
 const double erro = 0.0000001; 
 
 cout.precision(20); 
 cout << "Entre com o extremo a: "; 
 cin >> a; 
 cout << "Entre com o extremo b: "; 
 cin >> b; 
 
 fa = f(a); 
 fb = f(b); 
 
 if ((fa * fb) > 0) { 
 cout << "Intervalo inicial nao garante existencia de 
solucao ! \n"; 
 return 0; 
 } 
 while(fabs(a-b) > erro) { 
 c = (a+b)/2.0; 
 fc = f(c); 
 
 if (fa * fc < 0) 
 b = c; 
 else { 
 if (fb * fc < 0) 
 a = c; 
 else 
 break; 
 } 
 cout << "Solucao parcial = " << c << endl; 
 } 
 cout << "Solucao obtida = " << c << endl; 
 cout << "Raiz 2 = " << M_SQRT2 << endl; 
} 
 16 
 
Vamos examinar alguns detalhes da função introduzida: 
 
float f (float 
x) 
Define o tipo 
que será 
retornado 
Nome 
da 
função 
Parâmetro de 
entrada 
{ 
 float y; 
 
 y = x * x - 2; 
 
return(y); 
Valor a ser 
retornado 
 
} 
Uma observação importante é que as variáveis dentro da função não são conhecidas fora da 
função e vice-versa. Considere o seguinte programa: 
 
Funcao.cpp 
#include <iostream> 
using namespace std; 
 
int teste(int k) 
{ 
 k = k + 20; 
 cout << "Dentro da funcao k = " << k << endl; 
 return(k); 
} 
 
int main() 
{ 
 int i,j; 
 
 i = 1; 
 cout << "Fora da funcao i = " << i << endl; 
 j = teste(i); 
 cout << "Fora da funcao i = " << i << endl; 
 cout << "Fora da funcao j = " << j << endl; 
} 
 
 
O resultado será: 
Fora da funcao i = 1 
Dentro da funcao k = 21 
Fora da funcao i = 1 
Fora da funcao j = 21 
 
 17 
 
Observe que o valor da variável i não tem seu conteúdo alterado pela função. Isto ocorre 
porque quando uma função é chamada durante o programa, o parâmetro de entrada 
(variável i) tem seu conteúdo copiado para uma nova variável declarada na função 
(variável k). Observe que a variável i e j não são conhecidas dentro da função teste(). 
 
1.6.1 – Referência 
 
Muitas vezes gostaríamos que os argumentos de entrada da função pudessem ter seus 
valores alterados quando a função finalizasse. Para isso utilizamos uma referência para o 
parâmetro de entrada como ilustra o exemplo abaixo: 
 
Referencia.cpp 
#include <iostream> 
using namespace std; 
 
int teste(int& k) 
{ 
 k = k + 20; 
 cout << "Dentro da funcao k = " << k << endl; 
 return(k); 
} 
 
int main() 
{ 
 int i,j; 
 
 i = 1; 
 cout << "Fora da funcao i = " << i << endl; 
 j = teste(i); 
 cout << "Fora da funcao i = " << i << endl; 
 cout << "Fora da funcao j = " << j << endl; 
} 
 
O resultado será: 
Fora da funcao i = 1 
Dentro da funcao k = 21 
Fora da funcao i = 21 
Fora da funcao j = 21 
 
Quando o parâmetro da função é declarado com o símbolo & antes do nome da variável, 
então qualquer alteração no corpo da função do parâmetro de entrada, acessa o argumento 
de entrada utilizado na chamada da função. Nesse caso o parâmetro de entrada é uma 
referência. 
 
 
 
 
 18 
Exemplo: Vamos construir uma função cujo objetivo é permutar os valores de duas 
variáveis dadas. Não seria possível permutar os dois valores através de uma função como 
abaixo: 
Nao_Permuta.cpp 
/* Este programa NÃO consegue permutar os valores */ 
 
#include <iostream> 
 
void troca(float x, float y) 
{ 
 float auxiliar; 
 
 auxiliar = x; 
 x = y; 
 y = auxiliar; 
} 
 
int main() 
{ 
 float x = 1.2f; 
 float y = 56.89f; 
 
 troca(x,y); 
 std::cout << "x = " << x << " e y = " << y << std::endl; 
} 
 
O resultado deste programa seria: 
x = 1.2 e y = 56.89 
Como visto anteriormente, utilizando referências podemos obter o efeito desejado: 
Permuta.cpp 
/* Este programa consegue permutar os valores */ 
 
#include <iostream> 
 
void troca(float& x, float& y) 
{ 
 float auxiliar; 
 
 auxiliar = x; 
 x = y; 
 y = auxiliar; 
} 
 
int main() 
{ 
 float x = 1.2f; 
 float y = 56.89f; 
 
 troca(x,y); 
 std::cout << "x = " << x << " e y = " << y << std::endl; 
} 
 
 
O uso comum de argumentos do tipo referência ocorre em funções que devem retornar mais 
de um valor. No exemplo acima, a função retornou dois valores. 
 19 
2 - VETORES E MATRIZES 
2.1 - Vetores 
 
Quando você deseja representar uma coleção de dados semelhantes, pode ser muito 
inconveniente utilizar um nome de variável diferente para cada dado. 
Para ilustrar vamos considerar o seguinte exemplo: Montar um programa que armazena as 
notas de 5 alunos e calcula a média obtida pela turma. As notas serão armazenadas em uma 
variável do tipo float, porém ao invés de criarmos 5 variáveis, utilizamos uma variável do 
tipo vetor, definida como abaixo: 
 
 float notas[5]; 
 
Exemplo: 
 
Notas.cpp 
#include <iostream> 
using namespace std; 
 
int main() { 
 int i; 
 float media; 
 float soma; 
 float notas[5]; 
 
 for (i = 0; i < 5; i++) { 
 cout << " Aluno [" << (i+1) << "]:" ; 
 cin >> notas[i]; 
 } 
 
 soma = 0; 
 for (i = 0; i < 5; i++) 
 soma = soma + notas[i]; 
 
 media = soma / 5; 
 cout << " A media final é: " << media; 
} 
2.1.1 - Declaração 
 
Um vetor é uma coleção de variáveis de certo tipo, alocadas seqüencialmente na memória. 
Para C++ um declaração de variável vetor do tipo: 
 
 int n[5]; 
 
reserva o espaço de 5 variáveis do tipo inteira, onde cada variável pode ser referenciada 
conforme abaixo: 
 
 
 20 
n[0] n[1] n[2] n[3] n[4] 
 
IMPORTANTE: Observe que a declaração anterior cria cinco variáveis, porém o primeiro 
elemento é n[0]. A declaração de vetor inicia com o índice 0 e finaliza no índice 4. Se 
você quer atribuir um valor a um dos componentes do vetor basta referenciá-lo: 
 
 n[3] = 29; 
 
resultando em: 
 
 29 
 n[0] n[1] n[2] n[3] n[4] 
 
Assim como é possível atribuir valores a uma variável na mesma linha da declaração, o 
mesmo pode ser feito para vetores. Observe o exemplo abaixo: 
 
 int n[5] = {23, 3, -7, 288, 14}; 
2.1.2 – Exemplo: Método de Ordenação 
 
Como exemplo vamos apresentar um programa que ordena uma seqüência de 10 números 
reais. 
Ordenação.cpp 
 
/* Metodo da Bolha (ordenacao de um vetor) */ 
 
#include <iostream> 
using namespace std; 
 
 
int main() { 
 int i; 
 int flag; 
 float swap; 
 float x[10]; 
 const int n = 10; 
 
 
 /* Entrada de Dados */ 
 cout << "Entre com os numeros para ordenacao \n"; 
 for (i = 0; i < n; i++) { 
 cout << "\n numero[" << i << "] = "; 
 cin >> x[i]; 
 } 
 
 /* Ordena a sequencia de numeros */ 
 flag = 1; 
 while (flag == 1) { 
 flag = 0; 
 for (i = 0; i < (n - 1); i++) { 
 if (x[i] > x[i + 1]) { 
 swap = x[i]; 
 21 
 x[i] = x[i + 1]; 
 x[i + 1] = swap; 
 flag = 1; 
 } 
 } 
 } 
 
 /* Imprime a sequencia de numeros ordenada */ 
 cout << "\n Sequencia ordenada : " << endl; 
 for (i = 0; i < n; i++) 
 cout << x[i] << endl; 
} 
2.2 - Matrizes 
Para representar uma matriz3x4 (3 linha e 4 colunas) de números reais utilizamos a 
seguinte declaração: 
 
 float A[3][4]; 
 
Assim fica reservado um espaço de memória conforme a figura abaixo: 
 
A[0][0] A[0][1] A[0][2] A[0][3] 
A[1][0] A[1][1] A[1][2] A[1][3] 
A[2][0] A[2][1] A[2][2] A[2][3] 
 
Exemplo: Produto de uma matriz por um vetor 
 
Vamos montar um programa que multiplica um vetor por uma matriz. 
/* * * * * * * * * * * * * * * * * * * * * * */ 
/* Multiplicacao de um vetor por uma matriz */ 
#include <iostream> 
using namespace std; 
 
int main() { 
 int i, j; 
 float A[3][3] = { { 1.0, 1.5, 2.1 }, 
 { 3.4, 2.2, 9.1 }, 
 {-1.2, -3.4, 0.9 }}; 
 float v[3] = { 2.0, 1.0, 0.5 }; 
 float p[3]; 
 
 for (i = 0; i < 3; i++) { 
 p[i] = 0; 
 for (j = 0; j < 3; j++) 
 p[i] += A[i][j] * v[j]; 
 } 
 for (i = 0; i < 3; i++) { 
 cout << "\n["; 
 for (j = 0; j < 3; j++) 
 cout << A[i][j] << " "; 
 cout << " ] [ " << v[i] << "]"; 
 } 
 for (i = 0; i < 3; i++) 
 22 
 cout << "\n p["<< i << "] = " << p[i]; 
} 
3 - PONTEIROS 
 
3.1 - Introdução 
 
Um ponteiro é uma variável que contém o endereço de memória de outra variável. Todas as 
variáveis são alocadas em algum espaço de memória do computador. O ponteiro fornece 
um mecanismo para obter e armazenar este endereço de memória. Considere o exemplo: 
 
Ponteiro01.cpp 
#include <iostream> 
using namespace std; 
 
int main() 
{ 
 int i; 
 
 cout << "Endereco de i = " << &i << endl; 
} 
 
O endereço da variável é obtido utilizando-se o operador unário & na frente da variável. 
Assim &i fornece o endereço da variável i. 
 
3.2 – Principais Aplicações de Ponteiros 
 
Algumas situações em que os ponteiros são úteis: 
1. Para passar vetores e matrizes de forma mais conveniente como argumentos de funções. 
2. Para manipular vetores e matrizes de forma mais eficiente. 
3. Para manipular estruturas de dados mais complexas, tais como listas e árvores. 
4. Na utilização de alocação de memória dinâmica. 
3.3 – Armazenando o Endereço das Variáveis 
 
Para armazenar o endereço de uma variável (por exemplo &i) em outra variável, é 
necessário criar um tipo especial de variável denominada apontador. Exemplo: 
 
Ponteiro02.cpp 
#include <iostream> 
 
int main() 
{ 
 int i ; 
 int *pi; 
 
 pi = &i; 
 23 
 std::cout << "Endereco de i = " << &i << " ou " << pi; 
} 
 
A variável pi é uma variável do tipo ponteiro para inteiro (ou seja, ela recebe o endereço 
de uma variável do tipo inteiro). Para informar que esta variável é do tipo apontador 
colocamos um asterisco (*) na frente da variável no momento da sua declaração: 
 
int * pi; 
Tipo de 
ponteiro 
Indica 
pontei
ro 
Nome 
da 
variáv
el 
 
3.4 – Acessando o conteúdo de um endereço 
 
Considere o exemplo anterior em que pi = &i. Além do endereço de i, (já armazenado em 
pi) podemos também acessar o conteúdo armazenado no endereço de memória. Isto 
equivale a obter o valor da variável i. Observe o exemplo: 
 
Ponteiro03.cpp 
 
#include <iostream> 
using namespace std; 
 
int main() 
{ 
 int i, j; 
 int *pi; 
 
 pi = &i; 
 
 i = 25; 
 j = *pi + 8; /* equivalente a j = i + 8 */ 
 
 cout << "Endereco de i = " << pi << endl; 
 cout << "j = " << j << endl; 
} 
 
O operador unário * trata seu operando como um endereço e acessa este endereço para 
buscar o conteúdo da variável. Observe que o * tem dupla função: 
1. Em uma declaração de variável, indica que a variável é do tipo ponteiro. 
2. Durante uma atribuição, acessa o conteúdo do endereço armazenado pela variável 
ponteiro. 
 
No nosso exemplo, para alterar o valor da variável i, temos duas alternativas (totalmente 
equivalentes) : 
 i = 5; 
*pi = 5; 
 
 24 
 
 
3.5 – Ponteiros com Vetores 
 
Na linguagem C++, o relacionamento de ponteiros com vetores e matrizes é tão direto que 
daqui para frente sempre trataremos vetores e matrizes utilizando ponteiros. Qualquer 
operação que possa ser feita com índices de um vetor pode ser feita através de ponteiros. 
Vamos acompanhar através do exemplo de ordenação: 
/* Metodo da Bolha (ordenacao de um vetor) */ 
 
#include <iostream> 
using namespace std; 
 
void troca(float& x, float& y) 
{ 
 float auxiliar; 
 
 auxiliar = x; 
 x = y; 
 y = auxiliar; 
} 
 
void ordena(float *v,int elementos) 
{ 
 // Ordena a sequencia de numeros 
 int flag = 1; 
 
 while (flag == 1) { 
 flag = 0; 
 for (int i = 0; i < (elementos - 1); i++) { 
 if (v[i] > v[i + 1]) { 
 troca(v[i],v[i+1]); 
 flag = 1; 
 } 
 } 
 } 
} 
 
int main() { 
 float x[10]; 
 const int n = 10; 
 
 // Entrada de Dados 
 cout << "Entre com os numeros para ordenacao \n"; 
 for (int i = 0; i < n; i++) { 
 cout << "\n numero[" << i << "] = "; 
 cin >> x[i]; 
 } 
 
 ordena(x,n); 
 
 // Imprime a sequencia de numeros ordenada 
 cout << "\n Sequencia ordenada : " << endl; 
 25 
 for (int i = 0; i < n; i++) 
 cout << x[i] << endl; 
} 
 
 
Observe que quando chamamos a função ordena(x,n), utilizamos como argumento a 
variável x, sem referência a nenhum índice em particular do vetor. A função ordena é 
declarada como: 
 
void ordena(float *v, int elementos) 
 
Como o programa sabe que estamos nos referenciando a um vetor e não a uma simples 
variável ? Na verdade v é uma variável ponteiro para um float. Ela recebe o endereço do 
primeiro elemento do vetor. Assim é equivalente a chamar a função ordena como: 
ordena(&x[0],n); 
Como os vetores são alocados sequencialmente na memória do computador, então a 
referência x[5], acessa o sexto conteúdo em sequência na memória. Quando o nome de 
um vetor é passado para uma função, o que é passado é o endereço do início do vetor. 
3.6 – Alocação de Vetores Dinamicamente 
Uma das restrições do nosso programa de ordenação é que o usuário não pode definir a 
princípio quantos elementos ele pretende ordenar. Isto ocorre porque precisamos informar 
na declaração do vetor qual será a sua dimensão. Vamos retirar essa restrição. Para isso 
utilizaremos um novo comando: new[]. Vamos utilizar um exemplo: 
 
#include <iostream> 
using namespace std; 
 
void main() 
{ 
 int i,n; 
 float *v; 
 
 cout << "Entre com a dimensao do vetor desejada = " << endl; 
 cin >> n; 
 
 v = new float[n]; 
 
 cout << "Entre com o vetor = " << endl; 
 for(i=0;i<n;i++) 
 cin >> v[i]; 
 for(i=0;i<n;i++) 
 cout << "v[" << i << "]= " << v[i] << endl;; 
 
 delete[] v; 
} 
Para efetuar a alocação dinâmica observe as etapas do programa: 
 
1. O vetor que será alocado foi declarado como um ponteiro: float *v; 
2. O comando new float[n] reserva n espaços de memória, cada um do tamanho de um 
float. 
 26 
3. A função new retorna o endereço do primeiro elemento do vetor. 
4. A função delete[] libera o espaço de memória reservado para o vetor. 
3.7 – Alocação de Matrizes Dinamicamente 
 
Para alocar matrizes observe o exemplo: 
 
#include <iostream> 
using namespace std; 
 
void main() 
{ 
 int i,j,n,m; 
 float **A; 
 
 cout << "Entre com a dimensão da matriz desejada: \n n = "; 
 cin >> n; 
 cout << " m = "; 
 cin >> m; 
 
 A = new float*[n]; 
 A[0] = new float[n*m]; 
 for(i=1;i<n;i++) 
 A[i] = &A[0][i*m]; 
 
 for(i=0;i<n;i++) 
 for(j=0;j<m;j++) 
 cin >> A[i][j]; 
 
 for(i=0;i<n;i++) { 
 cout << endl; 
 for(j=0;j<m;j++) 
 cout << "A["<<i<<"]["<< j << "]= " << A[i][j]; 
 } 
 delete [] A[0]; 
 delete [] A; 
} 
 27 
4 – OBJETOS E CLASSES 
 
A programação orientada a objeto é uma estratégia de programação onde definimos novos 
tipos de dados (os objetos) e as operações que faremos sobre esses dados. A definição de 
um objeto é feita pela noção de classe, que será descrita nesta seção. 
4.1 – Membros da Classe 
 
 Uma classe tem dois tipos principais de componentes: 
 
1. Váriável Membro: correspondem aos dados, representados pelos campos da classe. 
2. Função Membro: são funções que operam sobre os campos da classe. 
 
Vamos iniciar com um exemplo, definindo um círculo com duas funções membros e três 
variáveis membros: 
 
Circulo.hpp 
class Circulo{ 
public: 
 Circulo(); // Funcao membro 
 double area(); // Funcao membro 
private: 
 double raio; // Variavel membro 
 double centrox,centroy; // Variavel membro 
}; 
 
As funções membros foram declaradas mas não implementadas. Isso será feito em outro 
módulo: 
 
Circulo.cpp 
#define _USE_MATH_DEFINES 
#include <math.h> 
#include "Circulo.hpp" 
 
Circulo::Circulo() { 
 raio = 1.0; 
 centrox = 0.0; 
 centroy = 0.0; 
} 
 
double Circulo::area() 
{ 
 return(M_PI * raio * raio); 
} 
 
 
 
 
 
 28 
O programa abaixo utiliza a classe circulo: 
 
main.cpp 
 
#include <iostream> 
#include "Circulo.hpp" 
using namespace std; 
 
int main() { 
 Circulo A; 
 
 cout << "Area do Circulo = " << A.area(); 
} 
 
 
4.2 – Construtores 
 
A declaração feita no programa main: 
 
Circulo A; 
 
cria o objeto círculo, chamando a função Circulo(). Esta função, em particular, tem 
propriedades especiais pois é responsável pela criação de um novo objeto e por essa razão é 
denominada construtor. 
Um construtor pode ser identificado na definição de uma classe por ser a única função cujo 
nome coincide exatamente com o nome da classe. Algumas características importantes do 
construtor: 
1) Tem sempre o mesmo nome da classe 
2) Pode ou não ter argumentos 
3) Não retorna nenhum campo (ou seja, não possui return). 
 
Observe que no nosso exemplo a classe se chama Circulo e portanto o construtor se 
chama Circulo(...) também. 
 
#include <iostream> 
 
class Circulo { 
public: 
 Circulo(); // Construtor 
 double area(); // Funcao membro 
private: 
 double raio; // Campos 
 double centrox,centroy; 
} 
 
Um construtor, ao contrário de uma função membro usual, não tem um tipo. Por exemplo: a 
função double area() retorna um double, enquanto o construtor Circulo(), não 
tem nenhum tipo como prefixo. 
 29 
O objetivo principal do construtor é garantir que todo objeto criado possa ter seus campos 
inicializados. Muitas vezes gostaríamos de definir como os campos devem ser iniciados e 
possivelmente executar alguns comandos específicos na criação do objeto. Neste caso 
utilizamos os construtores. 
Uma classe pode ter vários construtores diferentes conforme os parâmetros de entrada. Por 
exemplo: 
Circulo.hpp 
class Circulo { 
public: 
 Circulo(); // Construtor 
 Circulo(double r,double cx, double cy); // Construtor 
 double area(); // Funcao membro 
private: 
 double raio; // Campos 
 double centrox,centroy; 
}; 
 
O construtor Circulo(double r,double cx, double cy) permite que se inicialize os 
campos do objeto conforme os parâmetros de entrada. 
Circulo.cpp 
#define _USE_MATH_DEFINES 
#include <math.h> 
#include "Circulo.hpp" 
 
Circulo::Circulo() { 
 raio = 1.0; 
 centrox = 0.0; 
 centroy = 0.0; 
} 
 
Circulo::Circulo(double r,double cx, double cy) { 
 raio = r; 
 centrox = cx; 
 centroy = cy; 
} 
 
double Circulo::area() 
{ 
 return(M_PI * raio * raio); 
} 
 
main.cpp 
#include <iostream> 
#include "Circulo.hpp" 
using namespace std; 
 
int main() { 
 Circulo A; 
 Circulo B(2.5,1.0,1.0); 
 
 cout << "Area do Circulo A = " << A.area(); 
 cout << "Area do Circulo B = " << B.area(); 
} 
 30 
É possível definir uma classe sem construtores. Nesse caso as variáveis membro são criadas 
mas não inicializadas. Para alterar os campos será necessário criar funções membro que 
modifiquem os valores dos campos. 
4.3 – Controle de Acesso aos Campos e Funções 
4.3.1 - Seção Pública 
Observe que a primeira parte da classe Circulo inicia com uma seção pública, denotada por 
“public:”. A lista de itens que segue após essa declaração (funções ou variáveis) 
ficam disponíveis para acesso. Este elemento define o controle de acesso aos elementos, 
definindo assim se um dado campo da classe pode ou não ser alterado por outra classe. 
4.3.2 - Seção Privada 
Os elementos definidos na seção private somente são acessíveis pela própria classe. 
Utilizamos private quando queremos que os campos não sejam alterados exceto pelas 
funções da classe. 
Exemplo 1: 
Se os campos da classe Círculo fossem definidas como públicas, então no main, 
poderíamos acessar as variáveis do objeto e alterá-lo. Veja o exemplo: 
Circulo.hpp 
class Circulo { 
public: 
 Circulo(); // Construtor 
 double area(); // Funcao membro 
 
 double raio; // Campos 
 double centrox,centroy; 
}; 
 
main.cpp 
#include <iostream> 
#include "Circulo.hpp" 
using namespace std; 
 
int main() { 
 Circulo A; 
 
 A.raio = 2; 
 A.centrox = 0.2; 
 
 cout << "Area do Circulo A = " << A.area() << endl; 
} 
 
Exemplo 2: 
Os elementos da seção private não podem ser acessados fora da classe. Assim o exemplo 
abaixo causaria erros de compilação nas linhas indicadas: 
 Circulo.hpp 
 31 
class Circulo { 
public: 
 Circulo(); // Construtor 
 double area(); // Funcao membro 
private: 
 double raio; // Campos 
 double centrox,centroy; 
}; 
 
main.cpp 
#include <iostream> 
#include "Circulo.hpp" 
using namespace std; 
 
int main() { 
 Circulo A; 
 
 A.raio = 2; // ERRO NA COMPILAÇÃO ! 
 A.centrox = 0.2; // ERRO NA COMPILAÇÃO ! 
 
 cout << "Raio do Circulo A = " << A.raio << endl; // ERRO ! 
 cout << "Area do Circulo A = " << A.area() << endl; 
} 
 
Neste caso, para alterar as variáveis da classe precisamos definir funções na classe que 
façam essa tarefa. 
 
4.3 – Funções Membros 
4.3.1 - Introdução 
 
Uma função membro da classe é uma rotina (código) que atua sobre o objeto, como por 
exemplo, alterando seus campos, respondendo propriedades sobre o objeto, etc. No nosso 
exemplo, implementamos um método que responde a área do objeto círculo. 
4.3.2 – Acesso as variáveis da classe 
 
Podemos definir funções que alteram ou exibem as variáveis da classe. 
Circulo.hpp 
class Circulo { 
public: 
 Circulo(); // Construtor 
 void translacao(double x,double y); 
 double get_centrox(); 
 double get_centroy(); 
 double area(); // Funcao membro 
private: 
 double raio; // Campos 
 double centrox,centroy; 
}; 
 
 32 
Circulo.cpp 
#define _USE_MATH_DEFINES 
#include <math.h> 
#include "Circulo.hpp" 
 
Circulo::Circulo() { 
 raio = 1.0; 
 centrox = 0.0; 
 centroy = 0.0; 
} 
 
void Circulo::translacao(double x,double y) 
{ 
 centrox += x; 
 centroy += y; 
} 
 
double Circulo::get_centrox() 
{ 
 return(centrox); 
} 
 
double Circulo::get_centroy() 
{ 
 return(centroy); 
} 
 
double Circulo::area() 
{ 
 return(M_PI * raio * raio); 
} 
 
main.cpp 
#include <iostream> 
#include "Circulo.hpp" 
using namespace std; 
 
int main() { 
 Circulo A; 
 
 A.translacao(2,3); 
 
 cout << "Centro do Circulo A = (" << A.get_centrox() << "," << 
 A.get_centroy() << ")" << endl; 
 cout << "Area do Circulo A = " << A.area() << endl; 
} 
 
 
 
 
 
 
 
 33 
4.3.3 – Exemplo de uma Classe para Representar Números Racionais 
 
O exemplo abaixo ilustra a implementação de uma classe que represente um número 
racional por seu numerador e denominador inteiro. 
 
Racional.hpp 
class Racional { 
private: 
 int p,q; 
 void simplifica(); 
public: 
 Racional(int a = 0,int b = 1) { p = a; q = b; simplifica(); }; 
 Racional(Racional &R) { p = R.p; q = R.q; }; 
 
 Racional soma(const Racional& p); 
 Racional subtrai(const Racional& q); 
 Racional multiplica(const Racional &n); 
 void show(); 
}; 
 
Racional.cpp 
#include "Racional.h" 
#include <math.h> 
#include <iostream> 
using namespace std; 
 
void Racional::simplifica() 
{ 
 int r; 
 int b = p; 
 int a = q; 
 
 do { 
 r = b %a; 
 b = a; 
 a = r; 
 } while(r != 0); 
 
 p = p / b; 
 q = q / b; 
} 
 
Racional Racional::soma(const Racional& z) { 
 Racional s; 
 
 s.p = z.p * q + z.q * p; 
 s.q = z.q * q; 
 s.simplifica(); 
 return(s); 
} 
 
Racional Racional::subtrai(const Racional& z) 
{ 
 Racional dif; 
 34 
 dif.p = z.q * p - z.p * q; 
 dif.q = z.q * q; 
 dif.simplifica(); 
 return(dif); 
} 
 
Racional Racional::multiplica(const Racional& z) { 
 Racional s; 
 s.p = z.p * p; 
 s.q = z.q * q; 
 s.simplifica(); 
 return(s); 
} 
 
void Racional::show() 
{ 
 if (q == 1) 
 cout << p; 
 else 
 if ( q == -1) 
 cout << -p; 
 else 
 cout << p << "/" << q; 
} 
 
main.cpp 
#include "Racional.h" 
#include <iostream> 
using namespace std; 
int main() 
{ 
 for(int i = 1;i<8;i++) { 
 Racional x(i,i+2); 
 Racional u(i+1,i); 
 x.show(); 
 cout << " + "; 
 u.show(); 
 cout << " = "; 
 (x.soma(u)).show(); 
 cout << endl; 
 
 x.show(); 
 cout << " - "; 
 u.show(); 
 cout << " = "; 
 (x.subtrai(u)).show(); 
 cout << endl; 
 
 x.show(); 
 cout << " . "; 
 u.show(); 
 cout << " = "; 
 (x.multiplica(u)).show(); 
 cout << endl; 
 } 
} 
 35 
4.3.4 – Exemplo de uma Classe Vetor 
 
O exemplo abaixo ilustra a implementação de uma classe vetor de double. 
 
Vetor.hpp 
class Vetor 
{ 
 double *v ; // Os primeiros campos sao private 
 int dim; 
public: 
 Vetor(int n); // Construtor 
 Vetor(Vetor& W); // Construtor 
 ~Vetor(); // Destruidor 
 
 void set(int i,double x); // Funcoes de acesso e modificadores 
 double get(int i); 
 int get_dim(); 
}; 
 
Vetor.cpp 
#include "Vetor.h" 
 
Vetor::Vetor(int n) { 
 dim = n; 
 v = new double[n]; 
} 
 
Vetor::Vetor(Vetor& C) { 
 dim = C.get_dim(); 
 v = new double[dim]; 
 for(int j=0;j<dim;j++) 
 v[j] = C.get(j); 
} 
 
Vetor::~Vetor() { 
 delete [] v; 
} 
 
void Vetor::set(int i,double x) { 
 if ((i >= 0) && (i<dim)) 
 v[i] = x; 
} 
 
double Vetor::get(int i) { 
if ((i >= 0) && (i<dim)) 
 return (v[i]); 
else return 0; 
} 
 
int Vetor::get_dim() { 
 return(dim); 
} 
 
 
 36 
 
main.cpp 
#include <iostream> 
using namespace std; 
#include "Vetor.h" 
 
int main() 
{ 
 int i,n; 
 
 cout << "Entre com a dimensão do vetor: = "; 
 cin >> n; 
 
 Vetor A(n); 
 
 cout << "Entre com os elementos do vetor" << endl; 
 for(i=0;i<n;i++) { 
 double x; 
 cout << "V[" << i << "]="; 
 cin >> x; 
 A.set(i,x); 
 } 
 
 for(i=0;i<n;i++) 
 cout << " A["<<i<<"]= " << A.get(i) << endl; 
} 
 
 
Soma de vetores 
 
Existem diferentes formas de se implementar a soma de dois objetos. No caso de vetores, 
vamos considerar como um primeiro exemplo somar dois vetores u e v resultando em um 
novo vetor soma. A operação de soma sera implementada como uma função da classe 
Vetor. 
 
Vetor.h 
class Vetor 
{ 
 double *v ; // Os primeiros campos sao private 
 int dim; 
public: 
 Vetor(int n); // Construtor 
 Vetor(Vetor& W); // Construtor 
 ~Vetor(); // Destruidor 
 
 void set(int i,double x); // Funcoes de acesso e modificadores 
 double get(int i); 
 int get_dim(); 
 
 Vetor soma(Vetor b); 
}; 
 
 
 
 37 
Vetor.cpp 
#include "Vetor.h" 
 
. 
. 
. 
 
Vetor Vetor::soma(Vetor b) 
{ 
 if (dim != b.dim) 
 return 0; 
 Vetor soma(dim); 
 
 for(int i = 0; i < dim; i++) 
 soma.v[i] = v[i] + b.v[i]; 
 
 return soma; 
} 
 
main.cpp 
#include <iostream> 
using namespace std; 
#include "Vetor.h" 
 
int main() 
{ 
 int i,n; 
 
 cout << "Entre com a dimensão do vetor: = "; 
 cin >> n; 
 
 Vetor A(n); 
 Vetor B(n); 
 
 cout << "Entre com os elementos do vetor" << endl; 
 for(i=0;i<n;i++) { 
 double x; 
 cout << "v[" << i << "]="; 
 cin >> x; 
 A.set(i,x); 
 cout << "w[" << i << "]="; 
 cin >> x; 
 B.set(i,x); 
 } 
 
 Vetor C = A.soma(B); 
 
 for(i=0;i<n;i++) 
 cout << " v["<<i<<"]= " << A.get(i) << endl; 
 for(i=0;i<n;i++) 
 cout << " w["<<i<<"]= " << B.get(i) << endl; 
 for(i=0;i<n;i++) 
 cout << " soma["<<i<<"]= " << C.get(i) << endl; 
} 
 
 
 38 
Sobrecarga de Operadores 
 
Em C++ podemos redefinir operadores que permitem realizar operações entre objetos. Um 
exemplo é somar vetores usando o símbolo “+”. Outro exemplo na classe Vetor seria 
definir um operador [ ] para acessarmos o elemento v[i] (substituindo o comando A.get(i) e 
A.set(i)). 
 
 
Vetor.h 
class Vetor 
{ 
 double *v ; // Os primeiros campos sao private 
 int dim; 
public: 
 Vetor(int n); // Construtor 
 Vetor(Vetor& W); // Construtor 
 ~Vetor(); // Destruidor 
 double& operator[] (int i); // Funcoes de acesso e modificadores 
 int get_dim(); 
}; 
 
 
 
Vetor.cpp 
#include "Vetor.h" 
 
Vetor::Vetor(int n) { 
 dim = n; 
 v = new double[n]; 
} 
 
Vetor::Vetor(Vetor& C) { 
 dim = C.get_dim(); 
 v = new double[dim]; 
 for(int j=0;j<dim;j++) 
 v[j] = C[j]; 
} 
 
Vetor::~Vetor() { 
 delete [] v; 
} 
 
double& Vetor::operator[](int i) { 
 if ((i < 0) || (i >= dim)) { 
 std::cout << "Indice fora de dimensao \n"; 
 exit(0); 
 } 
 return v[i]; 
} 
 
int Vetor::get_dim() { 
 return(dim); 
} 
 
 39 
 
main.cpp 
#include <iostream> 
using namespace std; 
#include "Vetor.h" 
 
int main() 
{ 
 int i,n; 
 
 cout << "Entre com a dimensão do vetor: = "; 
 cin >> n; 
 
 Vetor A(n); 
 
 cout << "Entre com os elementos do vetor" << endl; 
 for(i=0;i<n;i++) { 
 double x; 
 cout << "V[" << i << "]="; 
 cin >> x; 
 A[i] = x; 
 } 
 
 for(i=0;i<n;i++) 
 cout << " A["<<i<<"]= " << A[i] << endl; 
} 
 
A classe racional poderia ser reimplementada da seguinte forma: 
 
Racional.h 
#include <iostream> 
using namespace std; 
 
class Racional { 
private: 
 int p,q; 
 void simplifica(); 
public: 
 Racional(int a = 0,int b = 1) { p = a; q = b; simplifica(); }; 
 Racional(Racional &R) { p = R.p; q = R.q; }; 
 
 Racional operator+(const Racional& n); 
 Racional operator*(const Racional& n); 
 Racional operator-(const Racional& n); 
 friend ostream& operator<<(ostream& out, const Racional& r); 
 friend bool operator==(const Racional& r,const Racional& s); 
}; 
 
Racional.cpp 
#include "Racional.h" 
 
Racional Racional::operator-(const Racional& z) 
{ 
 Racional dif; 
 
 dif.p = z.q * p - z.p * q; 
 40 
 dif.q = z.q * q; 
 dif.simplifica(); 
 
 return(dif); 
} 
 
ostream& operator<<(ostream& out, const Racional& r) 
{ 
 if (r.q == 1) 
 out << r.p; 
 else 
 if ( r.q == -1) 
 out << -r.p; 
 else 
 out << r.p << "/" << r.q; 
 return(out); 
} 
 
void Racional::simplifica() 
{ 
 int r; 
 int b = p; 
 int a = q; 
 
 do { 
 r = b % a; 
 b = a; 
 a = r; 
 } while(r != 0); 
 
 p = p / b; 
 q = q / b; 
} 
 
 
Racional Racional::operator+(const Racional& z) 
{ 
 Racional s; 
 
 s.p = z.p * q + z.q * p; 
 s.q = z.q * q; 
 s.simplifica(); 
 
 return(s); 
 
} 
 
Racional Racional::operator*(const Racional& z) 
{ 
 Racional s; 
 
 s.p = z.p * p; 
 s.q = z.q * q; 
 s.simplifica(); 
 
 return(s); 
} 
 41 
 
bool operator== (const Racional& r,const Racional& s) 
{ 
 return(r.p * s.q == r.q * s.p); 
} 
 
main.cpp 
#include "Racional.h" 
 
int main() 
{ 
 Racional a(6,3); 
 Racional b(3,4); 
 
 Racional c = a + b; 
 
 cout << c; 
 for(int i = 1;i<10;i++) { 
 Racional x(i,i+2); 
 Racional u(i+1,i); 
 cout << x << " + " << u << " = " << x + u << endl; 
 cout << x << " * " << u << " = " << x * u << endl; 
 cout << x << " - " << u << " = " << x - u << endl; 
 if (x == b) 
 cout << "Igual" << endl; 
 } 
} 
 
 
 1 


 2 
 
1. PONTOS E RETAS NO OPENGL ......................................................................................... 3 
1.1 – Sistemas Gráficos ............................................................................................................................3 
1.2 – Cores .......................................................................................................................................................3 
1.3 – Introdução ao OpenGL ..................................................................................................................41.4 – Funções Básicas...............................................................................................................................4 
1.5 – gluOrtho2D ...........................................................................................................................................6 
1.6 – Exemplo: Plotar uma reta unindo dois pontos...................................................................7 
1.6.1 – Algoritmo ingênuo .....................................................................................................................................7 
1.6.2 – Retas no Opengl ........................................................................................................................................8 
1.7 – Exemplo: Plotar o gráfico de uma função ............................................................................9 
1.8 – Fontes ..................................................................................................................................................11 
2. TECLADO E MOUSE(Callbacks) .......................................................................................13 
2.1 – Introdução ..........................................................................................................................................13 
2.2 – Teclado................................................................................................................................................13 
2.2.1 – Exemplo: Utilização do teclado no programa funções........................................................13 
2.3 – Mouse ..................................................................................................................................................14 
2.3.1 – Interrupções a partir do mouse .......................................................................................................14 
2.3.2 – Aplicações: Realizando o “zoom” do gráfico............................................................................17 
2.3.3 – Aplicações: Pilha.....................................................................................................................................22 
3. RETAS E POLÍGONOS NO OPENGL ...............................................................................28 
3.1 – Primitivas............................................................................................................................................28 
3.2 – Exemplo: Visualização de Métodos Numéricos de Integração .............................29 
4. CURVAS PARAMÉTRICAS ..................................................................................................32 
4.1 – Introdução ..........................................................................................................................................32 
4.2 – Exemplo: Visualização de Curvas Paramétricas ..........................................................32 
4.3 – Curvas na forma Polar ................................................................................................................36 
4.4 – Exemplo: Visualização de Curvas Polares ......................................................................37 
5. CURVAS IMPLÍCITAS ............................................................................................................39 
5.1 – Introdução ..........................................................................................................................................39 
5.2 – Visualização de Curvas Implícitas ........................................................................................39 
5.3 – Programa Curva Implícita..........................................................................................................40 
 
 3 
Capítulo II – Aplicações Gráficas 2D 
 
1. PONTOS E RETAS NO OPENGL 
 
1.1 – Sistemas Gráficos 
 
Uma imagem gráfica é formada por uma matriz de elementos denominados pixels. Os pixels são 
armazenados em uma porção da memória denominada Frame Buffer. 
 
0,0 1,0 2,0 … 
0,1 1,1 2,1 … 
 
 
 
A resolução do frame buffer corresponde ao número de pixels que ele representa e varia conforme a placa 
gráfica disponível. As resoluções básicas encontradas são: 
640 x 480 
800 x 600 
1024 x 768 
1280 x 1024 
 
1.2 – Cores 
A profundidade do frame buffer corresponde ao número de bits presentes para cada pixel e através do 
qual fica estabelecido, por exemplo, o número de cores que podem ser representados em cada pixel. O 
número de cores possíveis varia conforme o hardware. Cada pixel tem uma mesma quantidade de 
memória para armazenar suas cores. 
O buffer de cores (Color Buffer) é uma porção da memória reservada para armazenar as cores em cada 
pixel. Um buffer de 8 bits pode exibir 256 cores diferentes simultaneamente. Conforme a capacidade da 
placa gráfica podemos ter: 
 
 8 bits – 256 cores 
(High Color) 16 bits – 65.536 cores 
(True Color) 24 bits – 16.777.216 cores 
(True Color) 32 bits – 4.294.967.296 cores 
 
Existem duas formas básicas de acessar as cores no OpenGL: RGB e Modo Indexado. Trabalharemos 
sempre em formato RGB. No formato RGB você deve informar as intensidades de Vermelho, Verde e 
Azul. Estas intensidades devem variar entre 0,0 a 1.0. A tabela abaixo mostra como obter as cores 
básicas: 
 
Cores R G B 
Vermelho 1.0 0.0 0.0 
Verde 0.0 1.0 0.0 
Azul 0.0 0.0 1.0 
Amarelo 1.0 1.0 0.0 
Cyan 0.0 1.0 1.0 
Magenta 1.0 0.0 1.0 
Branco 1.0 1.0 1.0 
Preto 0.0 0.0 0.0 
 
 
 
 4 
1.3 – Introdução ao OpenGL 
 
O sistema gráfico OpenGL (GL significa Graphics Library) é uma biblioteca (de aproximadamente 350 
funções) para aplicações gráficas. O OpenGL foi desenvolvido pela Silicon Graphics (SGI) voltado para 
aplicações de computação gráfica 3D, embora possa ser usado também em 2D. As funções permitem a 
geração de primitivas (pontos, linhas, polígonos, etc.) e utilizar recursos de iluminação. 
O OpenGL é independente do sistema de janelas, ou seja, suas funções não especificam como manipular 
janelas. Isto permite que o OpenGL possa ser implementado para diferentes sistemas: Linux, Windows, 
Mac OS X, etc. 
 
1.4 – Funções Básicas 
 
O código abaixo cria uma janela gráfica. 
#include <gl\glut.h> 
 
void display() 
{ 
} 
 
void main(int argc, char **argv) 
{ 
 glutInit(&argc,argv); 
 glutCreateWindow("Ponto"); 
 glutDisplayFunc(display); 
 glutMainLoop(); 
} 
 
Vamos comentar função a função: 
 
1) glutInit(&argc,argv); 
 Esta função é utilizada para iniciar a biblioteca GLUT. 
 
2) glutCreateWindow("Ponto"); 
 Cria uma janela para o OpenGL com o nome: Ponto 
 
3) glutDisplayFunc(display); 
 Esta função registra que a função void display() será a função a ser chamada sempre que a 
janela gráfica necessita ser atualizada. 
 
4) glutMainLoop(); 
 Inicia o gerenciamento de eventos, aguardando que algum evento seja acionado. 
 
O próximo passo é gerar uma primeira saída gráfica. Para isso, precisamos implementar o código 
desejado na função display(). No exemplo, ilustramos como acender o pixel central na cor vermelha. 
 
#include <gl\glut.h> 
 
void display() 
{ 
 glClearColor(0.0,0.0,0.0,0.0); 
 glClear(GL_COLOR_BUFFER_BIT); 
 glColor3f(1.0,0.0,0.0); 
 glBegin(GL_POINTS); 
 glVertex2f(0.0,0.0); 
 glEnd(); 
 glFlush(); 
 glutSwapBuffers(); 
 } 
 
 
 
 5 
Quando a função display é chamada temos o seguinte resultado: 
 
glClearColor(0.0,0.0,0.0,0.0); 
 Indica a cor para ser utilizada no fundo da janela. 
 
glClear(GL_COLOR_BUFFER_BIT); 
 Limpa o buffer indicado com a cor do glClearColor() 
 
glColor3f(1.0,0.0,0.0); 
 Define o vermelho como cor atual. 
 
glBegin(GL_POINTS); 
 glVertex2f(0.0, 0.0); 
glEnd(); 
 Inicialmente a janela gráfica está definida para valores no intervalo [-1,1], tanto em x quanto em y. 
Assim a função glVertex2f(0.0, 0.0) acende o pixel na posição do centro 
 
glFlush(); 
 Envia uma solicitaçãoque o conteúdo do Frame Buffer seja exibido. 
 
Podemos alterar as configurações iniciais da janela gráfica: 
#include <gl\glut.h> 
 
void display() 
{ 
 glClearColor(0.0,0.0,0.0,0.0); 
 glClear(GL_COLOR_BUFFER_BIT); 
 glColor3f(1.0,0.0,0.0); 
 glBegin(GL_POINTS); 
 glVertex2f(0.0,0.0); 
 glEnd(); 
 glFlush(); 
 glutSwapBuffers(); 
 } 
 
void main(int argc, char **argv) 
{ 
 glutInit(&argc,argv); 
 glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA); 
 glutInitWindowSize(400,400); 
 glutInitWindowPosition(1,1); 
 glutCreateWindow("Ponto"); 
 glutDisplayFunc(display); 
 glutMainLoop(); 
} 
 
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA); 
 Quando uma janela é criada, seu tipo é determinado pelo Display Mode. O tipo da janela inclui um 
conjunto de características desejadas. Neste caso temos três: 
 
GLUT_DOUBLE: Buffer duplo 
GLUT_RGBA...: Modelo de representação das cores. 
GLUT_DEPTH.: Buffer de profundidade (utilizado em remoção de superfícies escondidas). 
 
glutInitWindowSize(400,400); 
 Indica o tamanho da janela a ser aberta (em pixels). 
 
glutInitWindowPosition(1,1); 
 Indica a posição inicial da janela. 
 
glutSwapBuffers(); 
 Troca os buffers (duplo buffer) 
 6 
 
Exercícios: 
1) Comente as seguintes linhas na função display e veja o resultado: 
 glClearColor(0.0,0.0,0.0,0.0); 
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); 
 
2) Acrescente um contador para verificar quantas vezes a função display é chamada. 
 
void display() 
{ 
 static int i = 0; 
 
 glClearColor(0.0,0.0,0.0,0.0); 
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); 
 glColor3f(1.0,0.0,0.0); 
 glBegin(GL_POINTS); 
 glVertex2f(200.0,200.0); 
 glEnd(); 
 glFlush(); 
 cout << i++ << endl; 
 } 
3) Comente a seguinte linha do código e veja o resultado. 
 glutDisplayFunc(display); 
 
1.5 – gluOrtho2D 
 
 Na maioria de nossas aplicações desejamos nos referenciar a um ponto na janela, não por coordenadas 
correspondendo as dimensões informadas na função glutInitWindowSize(), mas sim levando-se 
em conta o domínio de visualização relacionado ao problema. Para isso, a função gluOrtho2D() 
realiza a mudança para o sistema de coordenadas desejado. 
Esta tarefa é realizada fazendo a correspondência entre os intervalos em questão: 
 
Assim: 
 e segue que 
e identicamente para a coordenada y: . 
 
O programa abaixo ilustra o efeito do gluOrttho2D. 
#include <iostream> 
using namespace std; 
#include <gl\glut.h> 
 
const int DIMX = 400; 
const int DIMY = 600; 
 
float xmin = -1; 
float xmax = 1; 
float ymin = -1; 
float ymax = 1; 
 
void converte(float L,float R,float T,float B,float& x,float& y) { 
 /* Faz a funcao do glOrtho */ 
 x = ((x - L)/(R-L) * DIMX); 
 y = ((y - B)/(T-B) * DIMY); 
} 
 
 7 
void display() 
{ 
 
 float x = 0.5; /* Ponto que gostariamos de converter */ 
 float y = 0.5; 
 
 converte(xmin,xmax,ymin,ymax,x,y); 
 cout << "x= " << x << " y= " <<y << endl; 
 
 glClearColor(0.0,0.0,0.0,0.0); 
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); 
 glColor3f(1.0,0.0,0.0); 
 glBegin(GL_POINTS); 
 glVertex2f(x,y); 
 glEnd(); 
 glFlush(); 
 glutSwapBuffers(); 
} 
 
int main(int argc, char **argv) 
{ 
 glutInit(&argc,argv); 
 glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); 
 glutInitWindowSize(DIMX,DIMY); 
 glutInitWindowPosition(50,50); 
 glutCreateWindow("Ortho"); 
 gluOrtho2D(0,DIMX-1,DIMY-1,0);/* Matriz de pontos DIMx x DIMy */ 
 glutDisplayFunc(display); 
 glutMainLoop(); 
} 
 
1.6 – Exemplo: Plotar uma reta unindo dois pontos 
 
Como exemplo vamos desenhar uma reta (não vertical) unindo dois pontos (x0,y0) e (x1,y1). 
A equação da reta que passa por dois pontos é: 
 
 
1.6.1 – Algoritmo ingênuo 
 
A primeira idéia de como resolver este problema é proposto pelo programa abaixo. Este é um exemplo 
ingênuo de como desenhar a reta que passa por dois pontos dados. Vamos discutir a seguir os principais 
problemas deste programa e as possíveis soluções. 
 
* -------------------------------------------------------------- */ 
/* Exemplo ingenuo de como plotar a reta definida por dois pontos */ 
/* -------------------------------------------------------------- */ 
 
#include <gl\glut.h> 
#include <iostream> 
using namespace std; 
 
float x0,y0,x1,y1; 
 
void display() 
{ 
 
 8 
 float x,y; 
 
 glClearColor(0.0,0.0,0.0,0.0); 
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); 
 glColor3f(1.0,0.0,0.0); 
 glBegin(GL_POINTS); 
 for (x = x0;x <= x1;x+=0.001) { 
 y = (y1-y0)/(x1-x0)*(x-x0) +y0; 
 glVertex2f(x,y); 
 } 
 glEnd(); 
 glFlush(); 
 glutSwapBuffers(); 
} 
 
void main(int argc, char **argv) 
{ 
 
 cout << "x0 = "; 
 cin >> x0; 
 cout << "y0 = "; 
 cin >> y0; 
 cout << "x1 = "; 
 cin >> x1; 
 cout << "y1 = "; 
 cin >> y1; 
 
 glutInit(&argc,argv); 
 glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); 
 glutInitWindowSize(400,400); 
 glutInitWindowPosition(50,50); 
 glutCreateWindow("Reta"); 
 gluOrtho2D(-3,3,-3,3); 
 glutDisplayFunc(display); 
 glutMainLoop(); 
} 
 
 
Algumas desvantagens do programa proposto: 
 
1) Este método requer operações em ponto flutuante (float ou double) para cada pixel. Isto acarreta 
em um algoritmo lento, se comparado a um algoritmo que opera somente com números inteiros. 
Para o caso da reta, existe um tal algoritmo que utiliza somente aritmética com números inteiros. 
Este algoritmo foi desenvolvido por Jack E. Bresenham na década de 60 e será descrito adiante. 
2) O usuário estabelece o número de pontos da reta a serem plotados entre os dois pontos. Podem 
ocorrer dois casos: faltarem pontos (a reta fica pontilhada), sobrarem pontos (neste caso o 
algoritmo faz contas desnecessárias). O ideal é o próprio programa se encarregar de determinar o 
número de pontos necessários e suficientes para resolver o problema. 
3) O caso particular da reta vertical (onde K é constante) não pode ser plotado. 
 
 
 
1.6.2 – Retas no Opengl 
 
O OpenGL dispõe em sua biblioteca interna de uma função que plota uma reta por dois pontos dados. 
Esta função é descrita abaixo: 
 
 
 
 
 9 
 
void display() 
{ 
 float x,y; 
 
 glClearColor(0.0,0.0,0.0,0.0); 
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); 
 glColor3f(1.0,0.0,0.0); 
 glBegin(GL_LINES); 
 glVertex2f(x0,y0); 
 glVertex2f(x1,y1); 
 glEnd(); 
 glFlush(); 
} 
 
 
1.7 – Exemplo: Plotar o gráfico de uma função 
 
Vamos começar com uma versão bem simplificada, para plotar o gráfico de uma função y=f(x). 
 
#include <gl\glut.h> 
 
float funcao(float x) 
{ 
 return(x*x); 
} 
 
void display() 
{ 
 float x,y,dx; 
 
 glClearColor(0.0,0.0,0.0,0.0); 
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); 
 glColor3f(1.0,0.0,0.0); 
 
 dx = 0.02; 
 x = -1; 
 for(int i = 0;i < 100;i++) 
 { 
 y = funcao(x); 
 glBegin(GL_POINTS); 
 glVertex2f(x,y); 
 glEnd(); 
 x += dx; 
 } 
 
 glutSwapBuffers(); 
} 
 
void main(int argc, char **argv) 
{ 
 
 glutInit(&argc,argv); 
 glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); 
 glutInitWindowSize(400,400); 
 glutInitWindowPosition(50,50); 
 glutCreateWindow("Funcao"); 
 gluOrtho2D(-1,1,-1,1); 
 glutDisplayFunc(display); 
 glutMainLoop(); 
} 
 10 
 
 
 
Em seguida vamos definir a classe função: 
 
funcao.h 
#include <cmath> 
 
class funcao { 
 int pontos; 
 float xmin,xmax,ymin,ymax; 
public: 
 
 funcao(int p = 300,float xm = -1,float xM = 1); 
 
 float f(float x) { return(sin(x)); } 
 
 void dominio(); 
 void plota_funcao(); 
}; 
 
 
funcao.cpp 
#include <gl\glut.h> 
#include "funcao.h" 
#include <iostream> 
using namespace std; 
 
funcao::funcao(int p ,float xm ,float xM) { 
 pontos = p; 
 xmin = xm; 
 xmax = xM; 
} 
 
void funcao::dominio() { 
 cout << "xmin = "; 
 cin >> xmin; 
 cout << "xmax = "; 
 cin >> xmax; 
} 
 
void funcao::plota_funcao() { 
 float dx; 
 float x, y; 
 
 dx = (xmax - xmin)/pontos; 
 glColor3f(1.0, 0.0, 0.0); 
 x = xmin; 
 for (int i = 0; i < pontos; i++) { 
 y = f(x); 
 glBegin ( GL_POINTS); 
 glVertex2f (x,y); 
 glEnd(); 
 x = x + dx; 
 } 
} 
 
 
 
 
 
 11 
main.cpp 
 
#include <gl\glut.h> 
#include <cmath> 
#include "funcao.h" 
 
float L = -5; 
float R = 5; 
float B = -5; 
float T = 5; 
 
funcao f(400,L,R); 
 
void plota_eixo() 
{ 
 glColor3f (0.0, 1.0, 0.0); 
 glBegin (GL_LINES); 
 glVertex2f (L,0); 
 glVertex2f (R,0); 
 glVertex2f (0,B); 
 glVertex2f (0,T); 
 glEnd(); 
} 
 
void display() 
{ 
 glClearColor(0.0,0.0,0.0,0.0); 
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); 
 plota_eixo(); 
 f.plota_funcao(); 
 glFlush(); 
 glutSwapBuffers(); 
} 
 
void main(int argc, char **argv) 
{ 
 glutInit(&argc,argv); 
 glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); 
 glutInitWindowSize(400,400); 
 glutInitWindowPosition(50,50); 
 glutCreateWindow("Funcao"); 
 glutDisplayFunc(display); 
 gluOrtho2D(L,R,B,T); 
 glutMainLoop(); 
} 
 
 
 
1.8 – Fontes 
 
Utilizando o glut é possível incluir textos na visualização do gráficos. Para isso precisamos de duas 
funções: 
 
glRasterPos2f(float x, float y); 
Define a posição inicial do texto, 
 
glutBitmapCharacter(void *font, int character); 
Define a fonte e o caracter a ser exibido.
 12 
Assim podemos, no exemplo do gráfico, incluir variáveis que indiquem os eixos e pontos no nosso 
gráfico. 
 
main.cpp 
void display_fontes(float x,float y,void *tipo_fonte,char *texto) 
// font = GLUT_BITMAP_9_BY_15 
// GLUT_BITMAP_8_BY_13 
// GLUT_BITMAP_HELVETICA_10 
// GLUT_BITMAP_HELVETICA_14 
{ 
 glRasterPos2f(x, y); 
 for (int i = 0; texto[i] != '\0'; i++) { 
 glutBitmapCharacter((tipo_fonte, texto[i]); 
 } 
} 
 
void plota_eixo() 
{ 
 glColor3f (1, 1, 1); 
 display_fontes(4.7,-0.3,GLUT_BITMAP_HELVETICA_12,"x"); 
 display_fontes(0.1, 4.7,GLUT_BITMAP_HELVETICA_12,"y"); 
 display_fontes(0.1,-0.3,GLUT_BITMAP_HELVETICA_12,"0"); 
 
 glColor3f (0, 1, 0); 
 glBegin (GL_LINES); 
 glVertex2f (w.getL(),0); 
 glVertex2f (w.getR(),0); 
 glEnd(); 
 
 glBegin (GL_LINES); 
 glVertex2f (0,w.getB()); 
 glVertex2f (0,w.getT()); 
 glEnd(); 
} 
. 
. 
. 
 
 
 13 
2. TECLADO E MOUSE(Callbacks) 
 
2.1 – Introdução 
 
O usuário pode interagir com o programa de duas formas principais: através do Mouse ou Teclado. Para 
isso o GLUT dispõe de dois tipos de funções (que denominamos Callbacks) específicas para habilitar a 
utilização do teclado e do mouse. Vamos descrevê-las a seguir. 
 
2.2 – Teclado 
Para registrar ocorrências no teclado o GLUT dispõe da função: 
 
void glutKeyboardFunc(void (*func)(unsigned char key, int x, int y)) 
 
Esta função determina que quando uma tecla for pressionada, o controle do programa deve passar a 
função definida no campo (*func) e esta função receberá como parâmetros de entrada, a tecla 
pressionada (unsigned char key), e a posição do mouse (int x, int y). O exemplo abaixo 
exemplifica uma aplicação para o programa funções. 
 
2.2.1 – Exemplo: Utilização do teclado no programa funções 
Como exemplo vamos acrescentar no programa funções a possibilidade de alterarmos o domínio da 
função durante a execução do programa. Assim podemos estabelecer que quando o usuário pressionar a 
tecla “D” ou “d”, o programa interrompe e solicita as novas informações sobre o domínio da função. 
 
main.cpp 
#include <gl\glut.h> 
#include <cmath> 
#include "funcao.h" 
#include <iostream> 
using namespace std; 
 
float L = -5; 
float R = 5; 
float B = -5; 
float T = 5; 
 
funcao f(400,L,R); 
 
void plota_eixo() 
{ 
 glColor3f (0.0, 1.0, 0.0); 
 glBegin (GL_LINES); 
 glVertex2f (L,0); 
 glVertex2f (R,0); 
 glVertex2f (0,B); 
 glVertex2f (0,T); 
 glEnd(); 
} 
 
void display() 
{ 
 glClearColor(0.0,0.0,0.0,0.0); 
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); 
 plota_eixo(); 
 f.plota_funcao(); 
 glFlush(); 
 glutSwapBuffers(); 
} 
 
void teclado(unsigned char key, int x, int y) 
 14 
{ 
 switch(key) 
 { 
 case 'D': 
 case 'd': 
 f.dominio(); 
 glutPostRedisplay(); 
 break; 
 case 'W': 
 case 'w': 
 cout << "L = "; cin >> L; 
 cout << "R = "; cin >> R; 
 cout << "B = "; cin >> B; 
 cout << "T = "; cin >> T; 
 glLoadIdentity(); 
 gluOrtho2D(L,R,B,T); 
 glutPostRedisplay(); 
 break; 
 } 
} 
 
void main(int argc, char **argv) 
{ 
 glutInit(&argc,argv); 
 glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); 
 glutInitWindowSize(400,400); 
 glutInitWindowPosition(50,50); 
 glutCreateWindow("Funcao"); 
 glutDisplayFunc(display); 
 glutKeyboardFunc(teclado); 
 gluOrtho2D(L,R,B,T); 
 glutMainLoop(); 
} 
 
 
2.3 – Mouse 
O GLUT é capaz de obter três tipos de ocorrências diferentes a partir do mouse. Vamos descrevê-las em 
seguida e discutir uma interessante aplicação para o estudo de gráficos de funções. 
 
2.3.1 – Interrupções a partir do mouse 
 
a) glutMouseFunc 
 
void glutMouseFunc(void (*func)(int button, int state, int x, int y)) 
 
Este evento detecta quando algum botão do mouse foi pressionado. Quando isto ocorre, o programa 
executa a rotina definida em void (*func). Os parâmetros desta rotina podem receber os seguintes 
valores: 
- button : informa qual botão do mouse foi pressionado, sendo atribuído com um dos seguintes 
valores: GLUT_LEFT_BUTTON, GLUT_MIDDLE_BUTTON, GLUT_RIGHT_BUTTON. 
- state: informa quando o botão foi pressionado e quando o botão foi solto, sendo atribuído com 
dois possíveis valores: GLUT_DOWN ou GLUT_UP. 
- x,y: informa a posição do mouse quando o botão foi pressionado. 
 
Para ilustrar essa interrupção, alteramos o main.cpp e acrescentamos outra forma de interrupção para 
alterar o domínio. Assim se o usuário pressionar o botão direito do mouse, o programa solicita no console 
o novo domínio de visualização. Se pressionar o botão esquerdo, o programa informa em qual coordenada 
da tela o mouse se encontra. 
 
 15 
#include <gl\glut.h> 
#include <cmath> 
#include "funcao.h" 
#include <iostream> 
using namespace std; 
 
float L = -5; 
float R = 5; 
float B = -5; 
float T = 5; 
 
funcao f(400); 
 
void plota_eixo() 
{ 
 glColor3f (0.0, 1.0, 0.0); 
 glBegin (GL_LINES); 
 glVertex2f (L,0); 
 glVertex2f (R,0); 
 glVertex2f (0,B); 
 glVertex2f (0,T); 
 glEnd(); 
} 
 
void display() 
{ 
 glClearColor(0.0,0.0,0.0,0.0); 
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); 
 plota_eixo(); 
 f.plota_funcao(); 
 glFlush(); 
 glutSwapBuffers(); 
} 
 
void window_dimension() 
{ 
 cout << "L = "; cin >> L; 
 cout << "R = "; cin >> R; 
 cout << "B = "; cin >> B; 
 cout << "T = "; cin >> T; 
 glLoadIdentity(); 
 gluOrtho2D(L,R,B,T); 
} 
 
void teclado(unsigned char key, int x, int y) 
{ 
 switch(key) 
 { 
 case 'D': 
 case 'd': 
 f.dominio(); 
 glutPostRedisplay(); 
 break; 
 case 'W': 
 case 'w': 
 window_dimension(); 
 glutPostRedisplay(); 
 break; 
 } 
} 
 
void botao_mouse(int b,int state,int x, int y) 
{ 
 switch(b) { 
 case GLUT_RIGHT_BUTTON: 
 if (state == GLUT_DOWN) { 
 window_dimension(); 
 glutPostRedisplay(); 
 } 
 break; 
 case GLUT_LEFT_BUTTON: 
 if (state == GLUT_DOWN) 
 cout << "Botão esquerdo pressionado: x = " << x << " y = " << y << endl; 
 else 
 if (state == GLUT_UP) 
 cout << "Botão esquerdo solto: x = " << x << " y = " << y << endl; 
 break; 
 16 
 } 
} 
 
void main(int argc, char **argv) 
{ 
 glutInit(&argc,argv); 
 glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); 
 glutInitWindowSize(400,400); 
 glutInitWindowPosition(50,50); 
 glutCreateWindow("Funcao"); 
 glutDisplayFunc(display); 
 glutKeyboardFunc(teclado); 
 glutMouseFunc(botao_mouse); 
 gluOrtho2D(L,R,B,T);glutMainLoop(); 
} 
 
b) glutMotionFunc 
 
void glutMotionFunc(void (*func)(int x, int y)) 
 
Este evento detecta o movimento do mouse enquanto algum botão do mouse está pressionado. Quando 
isto ocorre, o programa executa a rotina definida em void (*func) e informa em x,y a posição do 
mouse na janela. 
No exemplo abaixo, a rotina botao_movimento_mouse(int x, int y) imprime a posição do 
mouse enquanto mantemos um de seus botões pressionados. 
 
 
. 
. 
. 
 
void botao_movimento_mouse(int x, int y) 
{ 
 cout << "Botao+movimento x = " << x << " y = " << y << endl; 
} 
 
void main(int argc, char **argv) 
{ 
 glutInit(&argc,argv); 
 glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); 
 glutInitWindowSize(400,400); 
 glutInitWindowPosition(50,50); 
 glutCreateWindow("Funcao"); 
 glutDisplayFunc(display); 
 glutKeyboardFunc(teclado); 
 glutMouseFunc(botao_mouse); 
 glutMotionFunc(botao_movimento_mouse); 
 gluOrtho2D(L,R,B,T); 
 glutMainLoop(); 
} 
 
 
 
 
 
c) glutPassiveMotionFunc 
 
 
void glutPassiveMotionFunc(void (*func)(int x, int y)) 
 
Este evento detecta o movimento do mouse quanto nenhum botão do mouse está pressionado. Quando 
isto ocorre, o programa executa a rotina definida em void (*func) e informa em x,y a posição do 
mouse na janela. 
No exemplo abaixo, a rotina movimento_mouse(int x, int y) imprime a posição do mouse 
quando movimentamos o mouse dentro da janela OpenGL. 
 
 17 
 
. 
. 
. 
 
void movimento_mouse(int x, int y) 
{ 
 cout << "Movimento x = " << x << " y = " << y << endl; 
} 
 
void main(int argc, char **argv) 
{ 
 glutInit(&argc,argv); 
 glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); 
 glutInitWindowSize(400,400); 
 glutInitWindowPosition(50,50); 
 glutCreateWindow("Funcao"); 
 glutDisplayFunc(display); 
 glutKeyboardFunc(teclado); 
 glutMouseFunc(botao_mouse); 
 glutMotionFunc(botao_movimento_mouse); 
 glutPassiveMotionFunc(movimento_mouse); 
 gluOrtho2D(L,R,B,T); 
 glutMainLoop(); 
} 
 
2.3.2 – Aplicações: Realizando o “zoom” do gráfico 
 
No processo de visualização das funções, ou mesmo da integração numérica, muitas vezes desejamos 
alterar o domínio do nosso gráfico. Para isso selecionamos a tecla “D” e “d” como uma interrupção do 
teclado para que pudéssemos informar o novo domínio. Uma forma mais ágil seria selecionar com o 
mouse interativamente um retângulo que gostaríamos de visualizar. É o que faremos no próximo 
programa. 
Para isso utilizaremos as interrupções do mouse para selecionarmos a região desejada. Quando o botão 
direito do mouse é pressionado, marcamos o ponto inicial da região. Enquanto o mouse está em 
movimento (com o botão direito pressionado), desenhamos o retângulo desejado. Quando o botão do 
mouse é solto, obtemos o ponto final da região e atualizamos o domínio da função. 
Observe que as coordenadas obtidas pelos eventos do mouse precisam ser convertidas para o sistma de 
coordendas indicado nos parâmetros da janela de visualização. Para isso, basta considerarmos a 
transformação inversa a aplicada na seção 1.5: 
 
 e segue que 
e identicamente para a coordenada y. 
 
funcao.h 
 
#include <cmath> 
 
class funcao { 
 
 int pontos; 
 float xmin,xmax; 
 
public: 
 
 funcao(int p = 300,float xm = -1,float xM = 1); 
 
 18 
 float get_xmin() { return xmin; } 
 float get_xmax() { return xmax; } 
 
 void set_dominio(float x,float y); 
 
 float f(float x) { return(sin(x)); } 
 
 void dominio(); 
 void plota_funcao(); 
}; 
 
 
funcao.cpp 
#include <gl\glut.h> 
#include "funcao.h" 
#include <iostream> 
using namespace std; 
 
funcao::funcao(int p ,float xm ,float xM) { 
 pontos = p; 
 xmin = xm; 
 xmax = xM; 
} 
 
void funcao::dominio() 
{ 
 cout << "xmin = "; 
 cin >> xmin; 
 cout << "xmax = "; 
 cin >> xmax; 
} 
 
void funcao::set_dominio(float xi,float xf) 
{ 
 xmin = xi; 
 xmax = xf; 
} 
 
void funcao::plota_funcao() 
{ 
 float dx; 
 float x, y; 
 
 dx = (xmax - xmin)/pontos; 
 glColor3f (1.0, 0.0, 0.0); 
 
 x = xmin; 
 glBegin ( GL_POINTS); 
 for (int i = 0; i < pontos; i++) { 
 y = f(x); 
 glVertex2f (x,y); 
 x = x + dx; 
 } 
 glEnd(); 
} 
 
window.h 
class window { 
 float L,R,B,T; 
public: 
 window(float L = -1,float R = 1,float B = -1,float T = 1); 
 19 
 
 float getL() { return(L); } 
 float getR() { return(R); } 
 float getB() { return(B); } 
 float getT() { return(T); } 
 
 void set(); 
 void set_window (int xv_1,int yv_1,int xv_2,int yv_2,int 
DIMX,int DIMY) ; 
 void plota_retangulo(int xv0,int yv0,int xv1,int yv1,int 
DIMX,int DIMY); 
}; 
 
window.cpp 
#include <gl\glut.h> 
#include <iostream> 
using namespace std; 
#include "window.h" 
 
window::window(float Left,float Right,float Bottom,float Top) 
{ 
 L = Left; 
 R = Right; 
 B = Bottom; 
 T = Top; 
} 
 
static float converte(int p, float min, float max, int dim) { 
 float x; 
 
 x = min + ( (p * (max-min))/(dim - 1) ); 
 return (x); 
} 
 
void window::set_window (int xv_1,int yv_1,int xv_2,int yv_2, 
 int DIMX,int DIMY) 
{ 
 float xmin1,xmax1; 
 float ymin1,ymax1; 
 
 xmin1 = converte(xv_1,L,R,DIMX); 
 xmax1 = converte(xv_2,L,R,DIMX); 
 L = xmin1; 
 R = xmax1; 
 
 ymin1 = converte(yv_2,T,B,DIMY); 
 ymax1 = converte(yv_1,T,B,DIMY); 
 B = ymin1; 
 T = ymax1; 
 glLoadIdentity(); 
 gluOrtho2D(L,R,B,T); 
} 
 
void window::set() 
{ 
 cout << "L = "; cin >> L; 
 cout << "R = "; cin >> R; 
 cout << "B = "; cin >> B; 
 cout << "T = "; cin >> T; 
 glLoadIdentity(); 
 gluOrtho2D(L,R,B,T); 
} 
 20 
 
 
void window::plota_retangulo(int xv0,int yv0,int xv1,int yv1, 
 int DIMX,int DIMY) 
{ 
 float t; 
 float retxmin,retxmax,retymin,retymax; 
 
 retxmin = converte(xv1,L,R,DIMX); 
 retxmax = converte(xv0,L,R,DIMX); 
 retymin = converte(yv0,T,B,DIMY); 
 retymax = converte(yv1,T,B,DIMY); 
 
 glColor3f(1.0,1.0,1.0); 
 glBegin(GL_LINE_LOOP); 
 glVertex2f(retxmin,retymin); 
 glVertex2f(retxmin,retymax); 
 glVertex2f(retxmax,retymax); 
 glVertex2f(retxmax,retymin); 
 glEnd(); 
} 
 
main.cpp 
#include <gl\glut.h> 
#include <cmath> 
#include "funcao.h" 
#include "window.h" 
#include <iostream> 
using namespace std; 
 
const int DIMX = 400; 
const int DIMY = 400; 
 
window w(-5,5,-5,5); 
funcao f(400,w.getL(),w.getR()); 
 
int mov = 0; /* Detecta o movimento do mouse */ 
int xv1,xv2,yv1,yv2; /* Domínio da nova janela */ 
 
void plota_eixo() 
{ 
 glColor3f (0.0, 1.0, 0.0); 
 glBegin (GL_LINES); 
 glVertex2f (w.getL(),0); 
 glVertex2f (w.getR(),0); 
 glVertex2f (0,w.getB()); 
 glVertex2f (0,w.getT()); 
 glEnd(); 
} 
void display() 
{ 
 glClearColor(0.0,0.0,0.0,0.0); 
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); 
 plota_eixo(); 
 f.plota_funcao(); 
 if (mov == 1) 
 w.plota_retangulo(xv1,yv1,xv2,yv2,DIMX,DIMY); 
 glFlush(); 
 glutSwapBuffers(); 
} 
 
 21 
 
void teclado(unsigned char key, int x, int y) 
{ 
 switch(key) 
 { 
 case 'D': 
 case 'd': 
 f.dominio(); 
 glutPostRedisplay(); 
 break; 
 case 'W': 
 case 'w': 
 w.set(); 
 glutPostRedisplay(); 
 break; 
 } 
} 
 
void botao_mouse(int b,int state,int x, int y) 
{ 
 switch(b) { 
 case GLUT_RIGHT_BUTTON: 
 if (state == GLUT_DOWN) { 
 xv1 = x; 
 yv1 = y; 
 mov = 1; 
 } 
 else 
 if (state == GLUT_UP) { 
 xv2 = x; 
 yv2 = y; 
 mov = 0; 
 w.set_window(xv1,yv1,xv2,yv2,DIMX,DIMY); 
 f.set_dominio(w.getL(),w.getR()); 
 glutPostRedisplay(); 
 } 
 break; 
 case GLUT_LEFT_BUTTON: 
 if (state == GLUT_DOWN) 
 cout << "Botao esquerdo pressionado em: x = " << x << " y 
= " << y << endl; 
 else 
 if (state == GLUT_UP) 
 cout << "Botao esquerdo solto em: x = " << x << " y = " 
<< y << endl; 
 break; 
 } 
} 
 
void botao_movimento_mouse(int x, int y) 
{ 
 xv2 = x; 
 yv2 = y; 
 glutPostRedisplay(); 
 
} 
 
void window_size(int dimx,int dimy)

Outros materiais