Sei sulla pagina 1di 145

http://agnor.gamedev-pt.net/gamedev/cpp.

html - main(), como funo principal - cout, como comando de escrita na consola - endl, como comando de mudana de linha - cin.get(), como comando de espera pelo ENTER - Bloco, o que est entre chavetas - Instruo, que necessita sempre de um ';' no final - Comentrio, como ferramenta para ajudar a documentar o cdigo

C++ - breve introduo


C++ uma linguagem de programao, criada em 1983 por Bjarne Stroustrup. , at agora, a linguagem mais usada nos videojogos: C++ foi utilizado em "bombas" como Far Cry, Half-Life 2, Unreal Tournament 2004, e muitos outros. Acho que poderia arriscar que 99% dos melhores jogos dos ltimos 10 anos tero usado ou C (C++ uma evoluo da linguagem C) ou C++. Esta linguagem que vo aprender fornecer as bases para os jogos que podero fazer, sejam eles uma aventura em modo de texto, ou um jogo em 3D que vai revolucionar o Mundo. No entanto no direi que seja fcil de aprender. A impacincia poder levar muitos a desistir, pois no prncipio vero que os programas que faro no sero muito atraentes. Mas acreditem, vale a pena!

4 razes para aprender C++


ultra-rpida - em parte por culpa dos jogos que os computadores (e principalmente as placas grficas) tm evoludo de uma forma estonteante. Os jogos so os programas que exigem mais do computador e por isso que a escolha dos profissionais recai em C++. permite vrios estilos de programao - enquanto linguagens mais modernas, como Java e C#, s permitem programar utilizando o paradigma de Programao Orientada a Objectos, o C++ permite construir programas usando 4 estilos de programao diferentes. Alis, os primeiros programas iro ser feitos utilizando o paradigma procedimental, mais frente ser utilizado o paradigma de Programao Orientada a Objectos. est bastante difundida - h muita informao sobre a linguagem, difundida em livros e na Internet. Alm disso, h bastantes bibliotecas conhecidas que funcionam (e encontram-se bem documentadas) com C++, como o OpenGL, DirectX, SDL, Lua, Havoc. o standard na indstria - se quiserem entrar na indstria de programao de jogos tm que saber esta linguagem. Alm disso, depois de aprenderem bem esta linguagem, so capazes de utilizar em pouco tempo outras linguagens similares, como C# e Java.

Exemplo 1.1 - O primeiro programa


#include <iostream> using namespace std; int main() { cout << "Este e o primeiro programa de um futuro programador de jogos" << endl; cin.get(); // Pra o programa at o utilizador premir uma tecla return 0; }

http://agnor.gamedev-pt.net/gamedev/cpp.html Exemplo 1.1 - Primeiro Programa O meu primeiro programa foi assim, s que em vez de estar escrito "Este o primeiro programa de um futuro programador de jogos" era o mtico "Hello World" Vou explicar linha por linha o que acontece.

#include <iostream>
O #include faz com que o contedo do ficheiro que est a sua frente, entre <> (neste caso o ficheiro iostream) seja inserido no programa. Sem ele no poderamos utilizar o comando cout, nem o endl. Estes comandos no existem em C++ puro, mas graas biblioteca iostream, eles passam a existir. Esta biblioteca disponibiliza ferramentas para o programador tratar do input e do output, tornando a vida do programador muito mais fcil. No se preocupem se ainda no perceberam, vamos aprender em lies mais avanadas.

using namespace std;


Esta instruo tambm necessria para se poder utilizar os comandos cout e endl. Resumidamente, todos os comandos que fazem parte da biblioteca std (standard) do C++ esto dentro de uma namespace. Deste modo necessrio mostrar ao compilador que pretendemos usar (using) a namespace std para termos acesso aos comandos cout e endl. Esta instruo tambm vai ser explicada em lies futuras.

int main()
Qualquer programa de C++ tem de ter uma funo main, que a primeira funo a ser chamada pelo programa. Uma funo em C++ declara-se da seguinte forma: tipo_de_retorno nome_da_funcao (argumentos) { instrues } O tipo_de_retorno o tipo da varivel de retorno. No caso da funo main, o int (do ingls integer), que significa que a funo ir actuar at encontrar uma instruo (return) a devolver um valor inteiro. O nome_da_funcao o identificador (nome com que chamamos a funo) e, como esta a funo principal, main. Os argumentos so facultativos (neste exemplo no so usados, logo os '()' apresentam-se vazios) e sero explicados mais frente No se preocupem se no perceberam os termos. A matria de funes ser explicada na lio 6.

cout
O cout representa o console output, que neste caso a janela que aberta pelo programa. Como se trata do output, ns queremos "mandar" para l texto, e fizemos isso utilizando o operador de output (<<). Pensem nestes smbolos como se fossem um sinal a indicar a direco: ns queremos mandar a expresso "Este e o primeiro programa de um futuro programador de jogos" e o comando endl para o console output. Tem bastante lgica :P .

"Este e o primeiro programa de um futuro programador de jogos"


Isto uma string em C++. As strings so um conjunto de caracteres e so definidos entre aspas "".

http://agnor.gamedev-pt.net/gamedev/cpp.html

endl
O endl (end line) faz com que se mude de linha ( o mesmo que usar o ENTER num editor de texto)

cin.get()
O cin.get uma funo que fica espera que o utilizador carregue numa tecla, impedindo que o programa abrisse e desligasse logo.

return 0;
O return faz com que a funo termine e devolve (ou "retorna") um valor funo. Neste caso (na funo main) serve para dizer funo main para parar e devolve-lhe o valor 0, significando que tudo ocorreu como previsto. Mais sobre isto na lio 6.

Conceito de bloco
Tambm convm falar no conceito de bloco. Um bloco o que est dentro de chavetas em C++. Neste caso serve para dizer que o cdigo que est dentro das chavetas '{' '}' pertence funo main.

Conceito de instruo
A maior parte dos erros cometidos pelos aspirantes a programadores em C++ (e um erro comum em programadores mais experientes :) o esquecimento de colocar os ';' no final de cada instruo. A maior parte das vezes (no programador menos experiente) isto deve-se dvida de quando se deve colocar os ';'. Cada ';' deve ser colocado no fim de cada instruo em C++. Uma instruo pode ser definida como um passo. Cada vez que definimos algo para o programa fazer, temos que colocar um ';' no final. H algumas excepes, como as instrues do preprocessador (as que so precedidas por um '#', como o #include) e a definio de funes (no colocam ';' no final das chavetas das funes). Felizmente o erro no muito grave, uma vez que o compilador acusa-o logo e s com prtica que iro super-lo. .............. Neste ponto s precisam de saber que a estrutura mais bsica de um programa em C++ esta. Podem alterar vontade o que est depois de "int main() {" e antes de "cin.get();" (adicionando outros cout, com outros textos). Podem tambm retirar o cin.get() a ver o efeito (o programa abre e fecha logo).

Comentrios
Os comentrios servem para explicar a outras pessoas o que uma parte/instruo do cdigo faz. Pode-se prescindir deles, mas aconselhvel a sua frequente utilizao de modo a perceber-se melhor o cdigo. H 2 tipos de comentrios: // Comentrio de uma linha - Faz com que tudo o que esteja nessa linha seja um comentrio. /* Comentrio que pode ser de vrias linhas */ - Faz com que tudo a seguir ao /* seja um comentrio, at encontrar o */.

http://agnor.gamedev-pt.net/gamedev/cpp.html Dica: Normalmente no incio de cada programa h uma breve descrio do programa. Por exemplo: /********************************** Programa de C++ Autor: Joo Portela aka Agnor Data: 23 de Dezembro de 2004 Desc: Programa de introduo a C++ **********************************/

Exemplo 1.2 - Prottipo de um Menu de um jogo


Este apenas um prottipo de um menu. Nenhum dos comandos funciona (obviamente), serve apenas como um exemplo final.
/********************************** Exemplo 1.2 - Prottipo de um menu Autor: Joo Portela aka Agnor Data: 16 de Agosto de 2006 Desc: Prottipo de um menu de um jogo, s de leitura. http://agnor.gamedev-pt.net/ **********************************/ #include <iostream> using namespace std; int main() { cout << cout << cout << cout << cout << cout << cout <<

"Menu de Jogo" << endl; endl; //cria uma linha vazia "1 - Novo Jogo" << endl; "2 - Continuar Jogo" << endl; "3 - Opcoes" << endl; "4 - Ajuda" << endl; "5 - Creditos" << endl;

cin.get(); // Pra o programa at o utilizador premir uma tecla return 0; }

Exemplo 1.2 - Prottipo de um Menu de Jogo Final da aula 01 de C++: Prxima aula -> C++ 02 - Variveis Fazer o download do cdigo fonte dos exemplos da aula Fazer o download da aula em PDF (verso experimental)

http://agnor.gamedev-pt.net/gamedev/cpp.html Ir para o topo da pgina

Aula 02 - Variveis
<!-google_ad_client = "pub-9639791948153775"; google_ad_width = 336; google_ad_height = 280; google_ad_format = "336x280_as"; google_ad_type = "text"; google_ad_channel ="3703014365"; google_color_border = "FFFFFF"; google_color_bg = "FFFFFF"; google_color_link = "0000FF"; google_color_url = "000000"; google_color_text = "000000"; //-->Conceitos-Chave: - varivel, como ferramenta para armazenar valores; - tipos de variveis, compreender a necessidade da existncia de vrios tipos de variveis; - cin, como comando para captar valores inseridos pelo utilizador; - caracteres especiais, certos caracteres necessitam de serem "escritos" de forma especial para serem reconhecidos pelo C++;

Varivel
As variveis so um dos conceitos mais importantes em programao. Pondo de uma forma simples, lembrem-se de matemtica: x = 23 y = 40 Uma varivel , portanto, um lugar na memria do computador que armazena um valor. Este valor poder ser alterado ao longo do programa (embora tambm possamos declarar variveis constantes). Em C++ as variveis so expressas desta forma: int x; x = 20; float pi = 3.14; char caracter = 'a'; bool exit = false; Vamos linha por linha:

int x;
Cria uma varivel do tipo integer (int) (um numero inteiro). Neste momento atribudo um nmero qualquer varivel, pois no definimos um nmero.

http://agnor.gamedev-pt.net/gamedev/cpp.html

x = 20;
A partir de agora a varivel x assume o valor 20.

float pi = 3.14;
Cria uma varivel do tipo float, ou seja, um nmero com casas decimais

char caracter = 'a';


Cria uma varivel do tipo char (um carcter). Notem que s d para inserir um caracter. Para inserir vrios caracteres numa varivel teremos que utilizar arrays (ser explicado na lio 7)

bool exit = false;


Cria uma varivel de tipo bool (s pode conter 2 valores: true ou false (verdadeiro ou falso, respectivamente))

Tipos de varveis
Abaixo esto listados os tipos essenciais de variveis em C++: int - Nmero inteiro que vai de - 2 147 483 648 a + 2 147 483 647. Ocupa 4 bytes (32 bits) float - Nmero racional (por exemplo 1.8 ou 1.62). Ocupa 4 bytes. double - o mesmo que o float, s que tem um maior alcance (ex. 1.23413445123). Ocupa 8 bytes. char - Cria um caracter de texto. Valores de -128 a +127 e ocupa 1 byte. bool - Cria uma varivel booleana. Os valores podem ser true ou false (1 ou 0, respectivamente). Ocupa 1 byte. Estes so os tipos essenciais. Depois h vrias palavras-chave que estendem ou encurtam o alcance da varivel. Por exemplo: unsigned - a varivel declarada frente s pode ter valores positivos. long - aumenta o alcance da varvel pelo dobro, tornando-a numa varavel com o dobro de bytes. short - diminui o alcance da varvel pelo dobro, tornando-a numa varavel com metade de bytes. Exemplo: short int a; unsigned short int b; long int c; unsigned char d; Na maior parte das vezes vamos apenas utilizar o tipo int para nmeros inteiros, o tipo float para nmeros decimais, o tipo char (e mais frente o string) para caracteres e strings (conjunto de caracteres) e o tipo bool, para variveis de testes de condies.

Console Input
Na primeira aula, aprendemos a trabalhar com o console output (cout) que servia para o programador escrever no ecr o que desejasse. Nesta vamos aprender console input, que serve para o utilizador escrever o que quiser no ecr (e para ser tratado pelo programa). O Console Input faz-se atravs do comando cin. Desta maneira poderemos fazer com que o utilizador interaja com o programa, e isso mesmo muito importante em programao de jogos (seno seria um mero "filme" e no uma experincia

http://agnor.gamedev-pt.net/gamedev/cpp.html interactiva). Vou mostrar um exemplo:


#include <iostream> using namespace std; int main() { int x; cout << "Insira um numero: "; /* nota a ausncia do endl. opcional pr endl ou no. Experimentem pr o endl para ver o efeito */ cin >> x; // notem que >> e no << porque estamos a usar input e no output cout << "\nVoce digitou " << x << endl; cin.get(); cin.get(); return 0; } //neste caso necessrio colocar 2 cin.get()

Exemplo 2.1 - Nmero inserido pelo utilizador Hummm.... J um programa maior... vamos linha por linha (vou ignorar o que j aprendemos)

int x;
Cria uma varivel de tipo inteiro, chamada x.

cout << "Insira um nmero: ";


Como tinha dito, no mesmo preciso usar o endl. Poderiam ter usado o endl, mas assim o nmero no aparecia frente dos dois pontos, mas na linha a seguir. O melhor mesmo experimentarem das 2 maneiras.

cin >> x;
Faz com que a varivel x, tenha o valor que o utilizador introduziu. Basicamente este comando espera que o utilizador prima ENTER e fique com o valor que o utilizador introduziu antes do ENTER. Lembrem-se do exemplo do sinal a seguir: ns estamos a mandar o contedo do cin (o que o utilizador escreveu) para a varivel x)

cout << "\nVoc digitou " << x << endl;


Estamos a mandar uma string (Voc digitou...) e uma varivel (x) para ser mostrado no console output Repararam que no incio da frase h um carcter um tanto estranho. Esse carcter '\n' faz com que se mude de linha. O endl tambm faz isso, mas melhor usar o carcter '\n' no incio da frase e endl no fim. Dica:

http://agnor.gamedev-pt.net/gamedev/cpp.html Reparem que usei 2 vezes o cin.get(); Se o comando cin.get(); no funcionar devidamente substituam por system("PAUSE"); e incluam o ficheiro stdlib.h #include <iostream> #include <stdlib.h> using namespace std; int main() { ... system("PAUSE"); return 0; } Ou usem 2 vezes o comando cin.get(); cin.get(); cin.get();

Caracteres especiais
J que estamos no fim da aula vou-vos falar de alguns caracteres especiais. Vocs sabem de um: o '\n' Vou pr aqui uma tabela com os caracteres e uma breve explicao de cada um: Caractr Descrio \a bell, emite um som \b retrocesso ( backspace ) \0 caractr terminador \f incio de pgina \n mudana de linha \r incio de linha \t tab horizontal \v tab vertical \\ backslash \' plica \" aspas \ooo caractr cujo cdigo em octal ooo \xhh caractr cujo cdigo em hexadecimal hh Esta tabela foi retirada do site do Pedro Santos. J agora, esse site tem um tutorial de C++ muito bom ( eu aprendi C++ com esse tutorial ) e acho que todos devem perder algum tempo a l-lo, pois se no perceberem alguma coisa neste tutorial, sempre podem ver se percebem com outro. O site www.psantos.net/cpptutorial/

http://agnor.gamedev-pt.net/gamedev/cpp.html

Exemplo 2.2 - Adivinhe o nmero (Verso I)


#include <iostream> using namespace std; int main() { int numero = 8; int tentativa;

//escolham um nmero qualquer //a tentativa do utilizador

cout << "ADIVINHE O NUMERO - VERSAO I" << endl; cout << "\n\nInsira a sua tentativa (1-10): "; cin >> tentativa; cout << "\nEscolheu o numero \'" << tentativa << "\'." << endl; cout << "O numero escolhido pelo programador e \'" << numero << "\'." << endl; cout << "\nSe acertou a primeira, parabens!" << endl; cout << "Se nao acertou algo me diz que vai acertar a seguir :)" << endl; cin.get(); cin.get(); return 0;

Exemplo 2.2 - Adivinhe o nmero (Verso I) Final da aula 02 de C++: Prxima aula -> C++ 03 - Variveis Fazer o download do cdigo fonte dos exemplos da aula Fazer o download da aula em PDF (Brevemente) Ir para o topo da pgina

Aula 03 - Operaes Aritmticas


<!-google_ad_client = "pub-9639791948153775"; google_ad_width = 336; google_ad_height = 280; google_ad_format = "336x280_as"; google_ad_type = "text"; google_ad_channel ="3703014365"; google_color_border = "FFFFFF"; google_color_bg = "FFFFFF"; google_color_link = "0000FF"; google_color_url = "000000"; google_color_text = "000000"; //-->Conceitos-Chave: - afectao, '=' - adio, '+'

http://agnor.gamedev-pt.net/gamedev/cpp.html - subtraco, '-' - multiplicao, '*' - diviso, '/' - mdulo, '%'

Operaes aritmticas
Nenhuma linguagem de programao estaria completa sem suporte a operaes aritmticas. A programao de jogos exige muitos clculos, por exemplo, a diminuio de Pontos de Vida, o aumento de coordenadas de movimento, etc.. Comecemos pelos tipos de operaes aritmticas mais simples: int int int int cout cout cout cout x y z a = = = = 4 4 4 4 + * / 2; 2; 2; 2; = = = = " " " " << << << << // // // // x y z a adio subtraco multiplicao diviso << << << << endl; endl; endl; endl;

Simples no ? Se agora quisssemos mostrar o valor do x, y, z, a, acrescentaramos isto: << << << << "x "y "z "a

Abaixo est uma tabela com as operaes aritmticas mais frequentes. Esta tabela foi retirada do Tutorial de C++ do Pedro Santos: operador exemplo descrio = a = b = c; afectao, o exemplo teria o seguinte resultado a = ( b = c ) + a = b + c; soma, afecta a varivel a com a soma de b e c a = b - c; subtrao, afecta a varivel a com a diferena entre b e c * a = b * c; multiplicao, afecta a com o produto de b e c / a = b / c; diviso, afecta a com o resultado da diviso de b com c % a = b % c; mdulo, afecta a com o resto da diviso de b com c Daqui penso que esto familiarizados com a maior parte dos operadores. No entanto h um que ningum (que eu conhea) aprendeu na escola, que o operador %. Esse operador (muito til por sinal) devolve (ou "retorna") o resto da diviso entre 2 nmeros. Por exemplo: 20 % 3 d 2 porque 20 a dividir por 3 no dava um nmero inteiro, por isso faz-se 18 a dividir por 3 mais o resto de 2. Alguns exemplos: 7 % 4 -> d 3 6 % 4 -> d 2 10 % 5 -> d 0, pois 10 a dividir por 5 d 2 certos, no tem resto. A sua utilidade vamos aprender quando falarmos em gerar nmeros aleatrios. Quanto afectao, usada para darmos um valor a uma varivel. Por exemplo: int int int c = c = a = b = c; a + c + 8; 2; b; b; // c igual a 10 // c igual a 10 + 2 = 12

http://agnor.gamedev-pt.net/gamedev/cpp.html c = c / b; // c igual a 12 a dividir por 2 = 6 b = c; // b vai ser igual a c = 6 Para facilitar-nos um pouco a vida, o C++ tem outras formas de afectar variveis. Vejam-nas na seguinte tabela (tambm do site do Pedro Santos): operador a += b; a -= b; a /= b; a *= b; a %= b; ++a; --a; Acho que est tudo fcil de entender, s um pequeno exemplo: int a = 6; int b = 4; b += 3; // b igual a b + 3 = 4 + 3 = 7 b -= a; // b igual a b - a = 7 - 6 = 1 b++; // b igual a b + 1 = 1 + 1 = 2 b--; // b igual a b - 1 = 1 Tambm em C++ se pode usar os parnteses '( )' para definir prioridades nas instrues aritmticas. Por exemplo: (2 + 3) * 2 . Isto d igual a 10. 2 + 3 * 2 . Isto d igual a 8, pois a multiplicao tem prioridade sobre a adio. o mesmo que: a = a + b; a = a -b; a = a / b; a = a *b; a = a % b; a = a + 1; a = a - 1;

O Primeiro Programa til: Uma Calculadora de Somar


#include <iostream> using namespace std; int main() { int a, b, c; cout << "Introduza o primeiro numero, carregue em ENTER e introduza o 2:" << endl; cin >> a >> b; c = a + b; cout << "A soma dos 2 numeros e igual a " << c << endl; cin.get(); cin.get(); return 0; }

Exemplo 3.1 - Calculadora de Somar Vamos linha por linha: int a, b, c; - O mesmo que int a; int b; int c; cin >> a >> b - O mesmo que cin >> a; cin >> b;

http://agnor.gamedev-pt.net/gamedev/cpp.html c = a + b; - A varivel c fica com a soma da varivel a e da varivel b. O resto do programa dever ser fcil de entender.

Operadores Relacionais
Alm dos operadores aritmticos, h outros operadores em C++ que servem para comparar valores. Por exemplo, poderemos saber se uma determinada varivel tem o mesmo valor do que outra, ou se tem um valor maior ou menor. Vejam o quadro abaixo: operador significado == igual a != no igual a > maior que >= maior ou igual a < menor que <= menor ou igual a O resultado do uso destes operadores uma varivel booleana. Se verificar a condio em cima, ento a varivel vai ser igual a 1 (verdadeiro). Se no, vai ser igual a 0 (falso). Vejam o seguinte programa de exemplo, que explica tudo sobre a operadores relacionais:
#include <iostream> using namespace std; int main() { int a, b; bool varteste; cout << "PROGRAMA DE COMPARACAO" << endl; cout << "\nInsira dois valores (insira o primeiro, prima ENTER e" << " depois insira o segundo):"; //isto foi s para mostrar que isto possivel //ver explicao na nota abaixo cin >> a >> b; varteste = a == b; //varteste vai assumir o valor de 1 se a for igual a b cout << "Igualdade entre " << a << " e " << b << " e igual a " << varteste << endl; varteste = a > b; cout << "Teste de superioridade de " << a << " para " << b << " e igual a " << varteste << endl; varteste = a < b; cout << "Teste de inferioridade de " << a << " para " << b << " e igual a " << varteste << endl; cout << "\n\nCodigo: \n\n0 -> Falso\n1 -> Verdadeiro" << endl; cin.get(); cin.get(); // Pra o programa at o utilizador premir uma tecla } return 0;

http://agnor.gamedev-pt.net/gamedev/cpp.html

Exemplo 3.2 - Operadores Relacionais Final da aula 03 de C++: Prxima aula -> C++ 04 - Operadores Lgicos e Condicionais Fazer o download do cdigo fonte dos exemplos da aula Fazer o download da aula em PDF (Brevemente) Ir para o topo da pgina

Aula 04 - Operadores Lgicos e Condicionais


<!-google_ad_client = "pub-9639791948153775"; google_ad_width = 336; google_ad_height = 280; google_ad_format = "336x280_as"; google_ad_type = "text"; google_ad_channel ="3703014365"; google_color_border = "FFFFFF"; google_color_bg = "FFFFFF"; google_color_link = "0000FF"; google_color_url = "000000"; google_color_text = "000000"; //-->Conceitos-Chave: - AND (&&), e - OR (||), ou - NOT (!), no - if, se - else, caso contrrio - else if, caso contrrio se

Operadores lgicos
Os operadores lgicos so, talvez, um bocado difceis de compreender, uma vez que no fazem parte da matemtica bsica. Para dar um exemplo simples: Imaginem que queramos saber se o HP(Pontos de Vida) de uma personagem est compreendido entre 0 e 100. Poderamos faz-lo da seguinte forma:
#include <iostream> using namespace std; int main() { int min = 0, max = 100; //valores mnimos e mximos de HP bool varteste; //a varivel para verificao int valor; //o valor a ser introduzido pelo utilizador cout << "VERIFICACAO DO LIMITE DE HP" << endl;

http://agnor.gamedev-pt.net/gamedev/cpp.html
cout << "\nInsira um valor de HP:" << endl; cin >> valor; varteste = valor >= min && valor <= max; /* Se o valor for maior ou igual ao minimo E o valor for menor ou igual ao mximo, ento varteste verdadeiro */ cout << "O teste e igual a " << varteste << endl; cout << "\n\nCodigo: \n\n0 -> Falso\n1 -> Verdadeiro" << endl; cin.get(); cin.get(); // Pra o programa at o utilizador premir uma tecla } return 0;

Exemplo 4.1 - Verificao do Limite de HP O caracter && (AND) a nica coisa de novo. Para uma melhor explicao criei umas tabelas de cada um dos trs operadores lgicos:

Operador && (AND, e):


A B Resultado (A && B) false false false false false true true false false

true true true L-se: A e B so verdadeiros (true)?

Operador || (OR, ou):


A B Resultado (A || B) true false false false false true true false true

true true true L-se: A ou B (algum deles) verdadeiro?

Operador ! (NOT, no )
A Resultado (!A) false true true false L-se: o contrrio de A.

http://agnor.gamedev-pt.net/gamedev/cpp.html E um exemplo prtico: bool bool bool bool bool a = b = c = d = e; true; true; false; false;

e = a && c; // e vai ser igual a false e = a && b; // e vai ser igual a true e = c && d; // e vai ser igual a false e = a || c; // e vai ser igual a true e = a || b; // e vai ser igual a true e = c || d; // e vai ser igual a false e = a == c; // e vai ser igual a false e = a == b; // e vai ser igual a true e = c == d; // e vai ser igual a true e = !a; // e vai ser igual a false e = !c; // e vai ser igual a true

Operadores condicionais: If
Chegamos agora a um dos pontos mais importantes em programao, os operadores condicionais. Quem nunca programou e est a ler este curso deve ter alguma vez pensado como que atravs de simples conjuntos de instrues (a maior parte deles matemticos), poderemos criar jogos. At agora no temos construdos jogos muito interactivos (podemos at dizer que no criamos jogos nenhuns :), so mais pedaos de texto que enviamos ao utilizador. Os operadores condicionais vo possibilitar essa interaco. Por exemplo, imaginem que queramos saber se o jogador morreu para mostrar uma mensagem de "Game Over". O que que precisaramos? Primeiro uma varivel de HP (Health Points ou Pontos de Vida). Precisaramos tambm de utilizar o operador menor ou igual (para saber se o HP menor ou igual a 0). Vamos criar um programa com o que sabemos at agora:
#include <iostream> using namespace std; int main() { bool varteste; //a varivel para verificao int hp; //os pontos de sade cout << "PROGRAMA GAMEOVER 0.1" << endl; cout << "\nInsira um valor de HP:" << endl; cin >> hp; varteste = hp <= 0; //at agora nada de novo... cout << "O teste e igual a " << varteste << endl;

http://agnor.gamedev-pt.net/gamedev/cpp.html
cout << "\n\nCodigo: \n\n0 -> Falso\n1 -> Verdadeiro" << endl; cin.get(); cin.get(); // Pra o programa at o utilizador premir uma tecla } return 0;

Exemplo 4.2 - Programa Game Over 0.1 Com os conhecimentos anteriores s poderamos chegar a isto, mas no isto que queremos. Queremos que o programa mostre um texto a dizer "Game Over". Para isso vamos utilizar o operador condicional IF. Se(if) varteste for verdadeiro, ento vai ser mostrado "Game Over".
#include <iostream> using namespace std; int main() { bool varteste; //a varivel para verificao int hp; //os pontos de sade cout << "PROGRAMA GAMEOVER 1.0" << endl; cout << "\nInsira um valor de HP:" << endl; cin >> hp; varteste = hp <= 0; //at agora nada de novo... if (varteste) //se varteste for verdadeiro... { cout << "\nGame Over" << endl; //ento... } cin.get(); cin.get(); // Pra o programa at o utilizador premir uma tecla } return 0;

Exemplo 4.3 - Programa Game Over 1.0 Vamos parte por parte: if (condicao) { ...instrucoes } Se a condicao (que est dentro de parentises) for verdadeira, ento as instrucoes vo ser executadas. Notem no uso de chavetas. Estas s so necessrias se o bloco do if tiver mais que uma instruo. Tambm podemos colocar a condio directamente no if, sem precisar de uma varivel booleana:
#include <iostream>

http://agnor.gamedev-pt.net/gamedev/cpp.html
using namespace std; int main() { int hp;

//os pontos de sade

cout << "PROGRAMA GAMEOVER 1.01" << endl; cout << "\nInsira um valor de HP:" << endl; cin >> hp; if (hp <= 0) //se o HP for menor ou igual a 0... { cout << "\nGame Over" << endl; //ento... } cin.get(); cin.get(); // Pra o programa at o utilizador premir uma tecla return 0; }

Exemplo 4.4 - Programa Game Over 1.01 Este cdigo muito melhor, tanto em questes de performance ( mais curto e no usa uma varivel booleana) como de legibilidade: muito mais fcil compreender a condio. Se o HP for menor ou igual a 0, ento mostra a frase "Game Over". S usei o Exemplo 4.3 para demonstrar como funciona o if: se o que est entre parntises (condio) for verdadeiro (igual a 1), ento executa as instrues que fazem parte do if (geralmente as que esto no bloco seguinte). Dica: A condio if, se tiver apenas uma instruo, no tem que possuir chavetas. Por exemplo: if (hp <= 0) cout << "Game Over" << endl; cin.get(); Neste caso cout << "Game Over" << endl; faria parte das instrues a serem executadas pelo if, enquanto o cin.get() no. no entanto encorajado a continuarem a usar chavetas com uma instruo, pois permite uma maior legibilidade no cdigo (qualquer pessoa saber facilmente quando comea e termina o if). Dica: J na primeira lio falei sobre um bloco. Agora o conceito de bloco mais importante. Um bloco serve para agrupar vrias instrues numa nica instruo e definido entre chavetas ('{' e '}'). por isso que podemos optar por no usar chavetas numa condio if, isto se s esta s possuir uma instruo. Se tivermos mais que uma temos que usar um bloco (atravs das chavetas). Dica:

http://agnor.gamedev-pt.net/gamedev/cpp.html Decerto que repararam nas 3 diferentes verses do programa GameOver. A verso 0.1 significa que o programa est ainda numa fase experimental, ainda no atingiu o necessrio para chegar a 1.0. Isto deve-se ao programa ainda no mostrar a mensagem Game Over. A verso 1.0 significa que o programa Game Over j atingiu o seu propsito, a primeira verso que cumpre o objectivo. A verso 1.01 significa que foram feitas ligeiras alteraes no programa (a eliminao da variavel varteste). Mais abaixo vamos desenvolver a verso 1.1, uma verso de programa um pouco mais alterada (com alteraes mais visveis).

Operadores condicionais: Else e Else if


Vamos aprender agora os operadores condicionais else e else if. Estes operadores servem de complemento ao operador if. Embaixo est o exemplo 4.5: Programa Game Over 1.1, que utiliza o operador else:
#include <iostream> using namespace std; int main() { int hp;

//os pontos de sade

cout << "PROGRAMA GAMEOVER 1.1" << endl; cout << "\nInsira um valor de HP:" << endl; cin >> hp; if (hp <= 0) //se o HP for menor ou igual a 0... { cout << "\nGame Over" << endl; //ento... } else // caso contrrio (se o HP no for menor ou igual a 0)... { cout << "\nConseguiu sobreviver!" << endl; } cin.get(); cin.get(); // Pra o programa at o utilizador premir uma tecla } return 0;

Exemplo 4.5 - Programa Gameover 1.1 Penso que no ser muito dificil compreender o que o else faz. Caso o if anterior no seja cumprido, ento vai cumprir o que est dentro do else. ento necessrio uma condio if a preceder o else (no pode existir sozinho). Agora vou mostrar a condio else if, criando um menu de um jogo interactivo:
#include <iostream> using namespace std;

http://agnor.gamedev-pt.net/gamedev/cpp.html
int main() { int escolha; cout cout cout cout cout << << << << << "MENU DE UM JOGO" << endl; "\n\n1 - Novo Jogo" << endl; "2 - Carregar Jogo" << endl; "3 - Opcoes" << endl; "4 - Sair" << endl;

cin >> escolha; if (escolha == 1) cout << "Escolheu comecar um novo jogo" << endl; else if (escolha == 2) cout << "Escolheu carregar um jogo antigo" << endl; else if (escolha == 3) cout << "Opcoes:" << endl; else if (escolha == 4) cout << "Deseja mesmo sair?" << endl; else // Caso contrrio... cout << "Escolha errada" << endl; cin.get(); cin.get(); return 0; }

Exemplo 4.6 - Menu de um Jogo No acho muito difcil de perceber. Primeiro temos o if. Se a escolha for igual a 1 executa a instruo (ou bloco). Caso contrrio (else) se (if) a escolha for igual a 2.... Experimentem compilar o programa e alterar os textos. Basicamente est assim: Programa: Mostra o menu, Espera que o utilizador fornea um valor, Se o valor for igual a 1 Escreve no ecr: Escolheu comecar um novo jogo Caso o valor no seja igual a 1, Se o valor for igual a 2 Escreve no ecr:...... (vocs sabem ;) Caso o valor no seja igual a 2, Se o valor for igual a 3 Escreve no ecr:...... (vocs sabem ;)

http://agnor.gamedev-pt.net/gamedev/cpp.html Caso o valor no seja igual a 3, Se o valor for igual a 4 Escreve no ecr:...... (vocs sabem ;) Caso o valor no seja igual a 4 (logo diferente dos outros valores acima), Escreve no ecr: Escolha errada

O Primeiro Jogo: Adivinha o Nmero


Sim, aps 4 aulas de C++ j pode fazer um jogo!!! Aqui vai o cdigo:
#include <iostream> #include <stdlib.h> using namespace std; int main() { int numero = 6; int utilizador; cout << "*********************************" << endl; cout << " ADIVINHE O NMERO " << endl; cout << "*********************************" << endl; cout << "Insira um numero por favor: _\b"; cin >> utilizador; if (utilizador == numero) { cout << "\n\n\nPARABENS!!!!\nACERTOU" << endl; } else if (utilizador < numero) { cout << "\n\n\nNao acertaste :(\nDemasiado baixo" << endl; } else if (utilizador > numero) { cout << "\n\n\nNao acertaste :(\nDemasiado alto" << endl; } cin.get(); cin.get(); return 0; // para podermos usar o system("PAUSE");

Exemplo 4.7 - Jogo - Adivinhe o Nmero Dou-vos para trabalho de casa perceberem o que faz o programa :P Este o primeiro jogo! Falta muita coisa, como o primeiro nmero ( sempre 6 e no outro), e uma opo para tentar novamente, mas o que querem? Ainda no aprendemos muito, mas j fizemos um jogo!

http://agnor.gamedev-pt.net/gamedev/cpp.html Final da aula 04 de C++: Prxima aula -> C++ 05 - Mais Operadores Condicionais Fazer o download do cdigo fonte dos exemplos da aula Fazer o download da aula em PDF (Brevemente) Ir para o topo da pgina

Aula 05 - Mais operadores condicionais


<!-google_ad_client = "pub-9639791948153775"; google_ad_width = 336; google_ad_height = 280; google_ad_format = "336x280_as"; google_ad_type = "text"; google_ad_channel ="3703014365"; google_color_border = "FFFFFF"; google_color_bg = "FFFFFF"; google_color_link = "0000FF"; google_color_url = "000000"; google_color_text = "000000"; //-->Conceitos-Chave: - switch, analisa a varivel - case, caso a varivel analisada pelo switch seja... - break, sai do switch, impedindo que as outras instrues fossem executadas - while, enquanto... - do...while, diferente do operador while na ordem de execuo - for, como alternativa ao while - operador ternrio, como alternativa ao if...else

O operador switch
Neste ponto das aulas, vocs j sabem fazer o menu de um jogo (como viram na aula anterior). Vamos relembrar:
#include <iostream> using namespace std; int main() { int escolha; cout cout cout cout cout << << << << << "MENU DE UM JOGO" << endl; "\n\n1 - Novo Jogo" << endl; "2 - Carregar Jogo" << endl; "3 - Opcoes" << endl; "4 - Sair" << endl;

cin >> escolha; if (escolha == 1)

http://agnor.gamedev-pt.net/gamedev/cpp.html
cout << "Escolheu comecar um novo jogo" << endl; else if (escolha == 2) cout << "Escolheu carregar um jogo antigo" << endl; else if (escolha == 3) cout << "Opcoes:" << endl; else if (escolha == 4) cout << "Deseja mesmo sair?" << endl; else // Caso contrrio... cout << "Escolha errada" << endl; cin.get(); cin.get(); } return 0;

Exemplo 4.6 - Menu de um Jogo O switch simplifica esta tarefa. Vejamos como ficaria o programa com switch:
#include <iostream> using namespace std; int main() { int escolha; cout cout cout cout cout << << << << << "MENU DE UM JOGO" << endl; "\n\n1 - Novo Jogo" << endl; "2 - Carregar Jogo" << endl; "3 - Opcoes" << endl; "4 - Sair" << endl;

cin >> escolha; switch (escolha) { case 1:

// caso a escolha seja 1

cout << "Escolheu comecar um novo jogo" << endl; break; case 2: // caso a escolha seja 2 cout << "Escolheu continuar um jogo antigo" << endl; break; case 3: // caso a escolha seja 3 cout << "Opcoes:" << endl; break; case 4: // caso a escolha seja 4 cout << "Tem a certeza que quer sair?" << endl; break; default: // caso no seja nenhuma das escolhas

http://agnor.gamedev-pt.net/gamedev/cpp.html
cout << "Escolha errada, tente novamente" << endl; } cin.get(); cin.get(); return 0; }

Exemplo 5.1 - Menu de um Jogo (Verso 2) A estrutura do switch poder ser explicada desta forma: switch (variavel) //verifica o valor da varivel { case n: //caso o seu valor seja n (um valor qualquer)... //... default: //caso contrrio... //... O nico comando que dever ser estranho o comando break. O break diz-nos para ir para sair imediatamente do switch, se no o pusssemos o programa executava todas as instrues que esto no switch (aparecia-nos os 5 textos em vez de aparecer s aquele que o utilizador queria). Experimentem retirar o break e executar o programa. Podemos tambm agrupar vrios case, desta forma:
#include <iostream> using namespace std; int main() { int escolha; cout << "Quer saber o numero de dias de que mes? 1 - 12" << endl; cin >> escolha; switch (escolha) { case 1: case 3: case 5: case 7: case 8: case 10: case 12: //caso seja 1 ou 3 ou 5 ou 7 ou... cout << "Esse mes tem 31 dias" << endl; break; case case case case 4: 6: 9: 11: //caso seja 4 ou 6 ou 9 ou 11... cout << "Esse mes tem 30 dias" << endl;

http://agnor.gamedev-pt.net/gamedev/cpp.html
break; case 2: //caso seja 2 (Fevereiro) cout << "Esse mes tem 28 ou 29 dias" << endl; break; default: // caso no seja nenhuma das escolhas cout << "Numero errado" << endl; break; } cin.get(); cin.get(); return 0; }

Exemplo 5.2 - Nmero de dias de um ms Como podem ver, agrupar cases muito til. Caso contrrio teramos de repetir bastantes vezes a mesma instruo.

Operador while
O operador while, cria um ciclo, que vem a ser muito til na programao de jogos. Por exemplo, dentro de um jogo h um ciclo que termina quando o jogador quiser desligar o jogo. Um exemplo:
#include <iostream> using namespace std; int main() { int escolha; bool done = false;

/* varivel booleana (verdadeiro ou falso) caso seja falsa continua a executar o ciclo principal, se for verdadeira sai do ciclo */ //enquanto o done for igual a falso....

while (done == false) { << endl;

cout << "\n\nBem vindo a este programa irritante, quer ve-lo outra vez?" cout << "1 - Sim\n2- Nao" << endl; cin >> escolha; switch(escolha) { case 1: break; // sai do switch case 2: done = true; break; default: break; //done vai ser igual a true, logo sai do while

http://agnor.gamedev-pt.net/gamedev/cpp.html
} //volta ao princpio do while.... } } return 0;

Exemplo 5.3 - Programa Irritante Isto vai ser muito til para, por exemplo, criar uma janela de Loading Game(Carregar Jogo), o ciclo do jogo, etc. Dica: Em vez de utilizarmos while (done == false) poderamos utilizar while (!done) A estrutura do while pode ser vista desta forma: while (condicao) //enquanto a condicao for verdadeira... { //executa estas instrues } Aviso: Tenham cuidado com os ciclos infinitos! Estes ciclos so criados quando impossvel ao utilizador sair do programa. Por exemplo, se retirarem o segundo case ao programa, o utilizador no conseguir sair do programa (ciclo infinito)

O operador do...while
H uma pequena diferena entre While e Do...While. Seno vejamos este exemplo:
#include <iostream> using namespace std; int main() { while (cin.get() != '*') (asteristico) { cout << "\n\nBem vindo a este programa irritante (versao 2)." << endl; cout << "Se quiser sair pressione * seguido de ENTER" << endl; //volta ao princpio do while.... //enquanto o cin.get() for diferente de *

http://agnor.gamedev-pt.net/gamedev/cpp.html
} return 0; }

Exemplo 5.4 - Programa Irritante (Verso 2) Se experimentarem o programa, vero que primeiro tem que se pressionar ENTER para aparecer a mensagem. Porqu? Porque a condio while primeiro testa a condio. Se for verdadeira executa as instrues. Neste exemplo, para testar a condio primeiro temos que pressionar ENTER (experimentem no incio escreverem * e depois dar ENTER). O do...while faz com que a instruo seja executada primeiro, e s depois a testa:
#include <iostream> using namespace std; int main() { do { cout << "\n\nBem vindo a este programa irritante (versao 3)." << endl; cout << "Se quiser sair pressione * seguido de ENTER" << endl; } while (cin.get() != '*'); return 0; } //no se esqueam do ;

Exemplo 5.5 - Programa Irritante (Verso 3) Esta verso muito melhor! S mesmo experimentando que percebem melhor a diferena entra as duas.

A condio for
A condio for tambm muito usada. Vejamos este exemplo com o while:
#include <iostream> using namespace std; int main() { int x = 0; while (x < 5) // enquanto x menor que 5 .... { cout << "X e igual a " << x << endl; x++; //incrementa o x ( x = x + 1 ) }

http://agnor.gamedev-pt.net/gamedev/cpp.html
cin.get(); return 0; }

Exemplo 5.6 - X igual a ... (at 5) Com o for este tipo de cdigo fica muito melhor:
#include <iostream> using namespace std; int main() { for (int x = 0; x < 5; x++) { cout << "X e igual a " << x << endl; } cin.get(); } return 0;

Exemplo 5.7 - X igual a ... (at 5) (Verso 2) Isto pode parecer um bocado complicado. Mas no ! Analisemos o for: for (int x = 0; x < 5; x++) Temos a primeira instruo, que a iniciao do for (s vai ser executada uma nica vez). Normalmente declara-se variveis aqui. Depois temos a segunda, que o teste condio. Se for true sai do for, se for false executa o bloco. A ltima instruo a ser realizada , normalmente, um incremento (x++). O operador for torna-se muito til quando queremos realizar algo repetvel um determinado nmero de vezes.

O operador ternrio
Para acabar, vou-vos mostrar o operador ternrio. Vejamos um exemplo usando if e else:
#include <iostream> using namespace std; int main() { int a; int b = 10; bool maior; cout << "Insira um numero: "; cin >> a;

http://agnor.gamedev-pt.net/gamedev/cpp.html
if (a <= b) { maior = false; } else { maior = true; } cin.get(); cin.get(); } return 0;

Exemplo 5.8 - Maior de dois nmeros E usando o operador ternrio:


#include <iostream> using namespace std; int main() { int a; int b = 10; bool maior; cout << "Insira um numero: "; cin >> a; a > b ? maior = true : maior = false; //l-se a maior que b ? Se sim maior igual a true, se no maior igual a false. cin.get(); cin.get(); return 0; }

Exemplo 5.9 - Maior de dois nmeros (verso 2)

Jogo de Adivinhar o Nmero (Verso 1.1)


Esta verso tem novas funcionalidades: s sai do programa quando o utilizador adivinhar o nmero e mostra o nmero de tentativas efectuadas. O cdigo abaixo:
#include <iostream> using namespace std; int main() { int numero = 21;

//o numero a ser adivinhado

http://agnor.gamedev-pt.net/gamedev/cpp.html
int valor; int tentativa = 0; bool done = false; //o numero a ser inserido pelo utilizador //o numero de tentativas que o utilizador precisou

cout << "Bem Vindo a versao 1.1 do jogo de ADIVINHAR O NUMERO" << endl; while (!done) { cout << "\nInsira a sua tentativa: "; cin >> valor; tentativa++; //incrementa o numero de tentativas

endl;

if (numero == valor) { cout << "\nBoa, acertou na " << tentativa << " tentativa!" << endl; cout << "Tera que deixar o jogo, uma vez que ja sabe o numero :)" << done = true; } if (valor < numero) { cout << "\nO numero e demasiado baixo. Tente um mais alto" << endl; } if (valor > numero) { cout << "\nO numero e demasiado alto. Tente um mais baixo" << endl; } //sai do while

} cin.get(); cin.get(); return 0; }

Exemplo 5.10 - Jogo - Adivinhar o Nmero 1.1 Deixo-vos novamente a tarefa de perceberem o que faz o programa para casa. Final da aula 05 de C++: Prxima aula -> C++ 06 - Funes Fazer o download do cdigo fonte dos exemplos da aula Fazer o download da aula em PDF (Brevemente) Ir para o topo da pgina

http://agnor.gamedev-pt.net/gamedev/cpp.html

Aula 06 - Funes
<!-google_ad_client = "pub-9639791948153775"; google_ad_width = 336; google_ad_height = 280; google_ad_format = "336x280_as"; google_ad_type = "text"; google_ad_channel ="3703014365"; google_color_border = "FFFFFF"; google_color_bg = "FFFFFF"; google_color_link = "0000FF"; google_color_url = "000000"; google_color_text = "000000"; //-->Conceitos-Chave: - funo, como declarar, definir e us-la - argumentos, como os parmetros passados s funes - alcance, uma varivel dentro de uma funo s pode ser acedida pela mesma - return, devolve valores para fora da funo - do...while, diferente do operador while na ordem de execuo - for, como alternativa ao while - operador ternrio, como alternativa ao if...else

Funes
Uma funo um conjunto de instrues que pode (e deve) ser reutilizada (usada mais do que uma vez), em qualquer ponto do programa. At agora temos utilizado sempre uma funo: a funo main. So muito teis pois permitem que muitas linhas de cdigo sejam substitudas numa s. Por exemplo, o seguinte cdigo seria possvel caso Como expliquei na primeira aula, a funo main sempre a primeira a ser chamada pelo programa Finalmente chegamos a uma das partes mais divertidas de programao com C++: as funes! Isso porque podemos criar funes para praticamente tudo e depois us-las. Por exemplo poderamos fazer: desenharPersonagem(); moverPersonagem(); mostrarVideo(SEQUENCIA_DE_VIDEO_23); Resumindo, uma funo uma simples linha de cdigo que permite executar vrias linhas mais complexas. Vou criar uma funo simples para perceberem a ideia:
#include <iostream> using namespace std; int criarPersonagem() { cout << "Personagem Criada.\nNome: Agnor" << endl; return 0; }

http://agnor.gamedev-pt.net/gamedev/cpp.html
int main() { criarPersonagem(); cin.get(); return 0; }

Exemplo 6.1 - Funo Criar Personagem Na primeira lio vimos a estrutura bsica de uma funo: tipo_de_retorno nome_da_funcao (argumentos) { instrues } Esta funo segue uma estrutura prxima da funo main: no tem argumentos e o tipo de retorno um int. No entanto, esta funo pode ser chamada por outras funes (neste caso, chamada pela funo main). Por exemplo, o seguinte cdigo possvel:
#include <iostream> using namespace std; int criarPersonagem() { cout << "Personagem Criada.\nNome: Agnor" << endl; return 0; } int main() { criarPersonagem(); criarPersonagem(); criarPersonagem(); cin.get(); return 0; }

Exemplo 6.2 - Utilizando a mesma funo para criar vrias personagens Como vm, as funes ajudam em muito a encurtar o cdigo e na sua compreenso (temos uma linha de cdigo, em vez de 200, por exemplo). Alm disso, se quisermos alterar a forma de criar personagens, basta alter-la apenas uma vez (a funo), no preciso alterar o cdigo em cada ponto.

Argumentos de Funes
Uma dada funo pode possuir vrios (ou nenhuns) argumentos. Os argumentos (ou parmetros) de uma funo servem para o programador passar algumas variveis para a funo tratar. Por exemplo, se quisssemos criar uma funo Soma (cujo objectivo fosse mostrar a soma de dois nmeros), teramos que passar duas variveis funo. Os argumentos encontram-se entre os parntises '()' da funo e apresentam o tipo de varivel e o identificador ("int x", por exemplo). Uma funo pode ter os argumentos que desejarmos. Vejam o seguinte exemplo:

http://agnor.gamedev-pt.net/gamedev/cpp.html
#include <iostream> using namespace std; /************* FUNO SOMA **************** * Desc: Mostra no output o valor de a + b * ******************************************/ int soma (int a, int b) { int valor = a + b; cout << "\nA soma de " << a << "+" << b << " e igual a " << valor << endl; } return 0;

int main() { soma(8, 19); soma(21, 32); soma(26, 27); soma(1, 1); soma(5, 2);

// 8 o valor que 'a' vai assumir e 19 o valor de 'b'

cin.get(); // Pra o programa at o utilizador premir uma tecla } return 0;

Exemplo 6.3 - Soma de dois nmeros 1.0 Aqui podem vr a versatilidade das funes: com apenas algumas linhas de cdigo temos uma calculadora de somar totalmente personalizvel. Por exemplo, em vez do ambiente em modo de texto, poderamos criar um ambiente totalmente em 3D, sem necessitarmos de alterar o cdigo dentro da funo main.

Noes bsicas de alcance (scope)


Uma varivel que seja declarada dentro do bloco de uma funo (ou nos argumentos) s existe dentro da mesma. Assim, o exemplo abaixo est incorrecto:
#include <iostream> using namespace std; int soma (int a, int b) //a e b s existem dentro da funo soma! { int valor = a + b; //valor s existe dentro da funo soma! cout << "\nA soma de " << a << "+" << b << " e igual a " << valor << endl; } return 0;

int main() { a = 5;

//erro... 'a' s pode ser usado dentro da funo soma

int a; //este 'a' diferente do 'a' dentro da funo soma

http://agnor.gamedev-pt.net/gamedev/cpp.html
a = 4; //correcto, pois 'a' existe dentro da funo main, porm //diferente do 'a' que est na funo soma

cin.get(); // Pra o programa at o utilizador premir uma tecla return 0; }

Exemplo no compilvel - Introduo ao alcance em funes H uma lio dedicada ao alcance de variveis, a lio 10, onde este tema ser visto em pormenor.

Retorno de Valores
At agora temos sempre utilizado a instruo return no fim de cada funo, mas sem saber o seu verdadeiro significado. A funo soma do exemplo 6.3 encontra-se ainda limitada, pois o programador no pode aceder varivel "valor" (a varivel que contm a soma). A instruo return devolve (ou retorna) um valor que esteja dentro da funo. No caso da calculadora, iremos usar a instruo return valor; :
#include <iostream> using namespace std; int soma (int a, int b) //a e b s existem dentro da funo soma! { int valor = a + b; //valor s existe dentro da funo soma! } return valor;

int main() { int a; //como sabem, estes dois valores no so os mesmos que os que esto int b; //dentro da funo soma int resultado; cout << "Insira o primeiro valor: "; cin >> a; cout << "Insira o segundo valor: "; cin >> b; //resultado vai ser igual ao valor retornado pela //funo soma cout << "\nA soma entre os dois numeros inseridos e de " << resultado << endl; cin.get(); cin.get(); } return 0; resultado = soma(a, b);

http://agnor.gamedev-pt.net/gamedev/cpp.html Exemplo 6.4 - Funo Soma 2.0 Tambm possvel criar uma funo que no retorne nada. Esta funo ter de ser do tipo void (vazio). De notar que, segundo os standards de C++, a funo main ter obrigatoriamente de ser to tipo int:
void falar() { cout << "Bem-Vindo: "; //sem return! }

Declarao e Definio de funes


Ao fazermos: int a; - estamos apenas a declarar a varivel a = 5; - estamos a definir a varivel int b = 5; - estamos a declarar e a definir a varivel As funes tambm seguem este esquema. At agora temos declarado a funo e definido ao mesmo tempo, mas podemos declarar primeiro e definir apenas no fim:
#include <iostream> using namespace std; int soma(int a, int b) { return (a + b); //nem precisamos de criar uma varivel intermdia } //estamos a fazer a declarao e definio da funo ao mesmo tempo int subtraccao(int a, int b); int multiplicacao(int a, int b); int divisao(int a, int b); /* s fizemos a declarao, a definio est em baixo. Notem a presena do ponto e vrgula ';', como na declarao de variveis */ int main() { int a, b; cout << "Insira dois valores:" << endl; cin >> a >> b; cout cout cout cout << << << << "\nSoma: " << soma(a, b) << endl; "Subtraccao: " << subtraccao(a, b) << endl; "Multiplicacao: " << multiplicacao(a, b) << endl; "Divisao: " << divisao(a, b) << endl;

cin.get(); cin.get(); } return 0;

/*DEFINIES DAS FUNES*/

http://agnor.gamedev-pt.net/gamedev/cpp.html
int subtraccao(int a, int b) { return (a - b); } int multiplicacao(int a, int b) { return (a * b); } int divisao(int a, int b) { return (a / b); }

Exemplo 6.5 - Calculadora 1.0

Funo Random
Vou colocar aqui uma funo que ser muito til: A funo random. Esta funo gera nmeros aleatrios!
#include <iostream> #include <stdlib.h> #include <windows.h> using namespace std; //para poderem usar o rand() //para poderem usar o GetTickCount()

/*********************************************************** int getRandom(int de, int ate) DESC: gera nmeros aleatrios que vo desde "de" at "ate" ***********************************************************/ int getRandom(int de, int ate); int main() { srand( GetTickCount() );

varias vezes! for (int x = 0; x < 10; x++) cout << getRandom(0,5) << endl; uma linha cin.get(); return 0;

//explicarei isto quando falar de arrays. //experimentem retirar e correr o programa //no necessrio { } porque so

int getRandom(int de, int ate) { int random; ate -= de; random = rand() % (ate + 1) + de; return random; }

http://agnor.gamedev-pt.net/gamedev/cpp.html Exemplo 6.6 - Funo getRandom O srand() no precisam de entender por agora, s precisam de saber que sem ele o programa gerava os mesmos nmeros sempre que o iniciamos (experimentem retir-lo, s a experimentar e a criar que aprendem programao). Vou s tentar explicar a linha: random = rand() % (ate +1) + de; O que o rand() faz originar um nmero aleatrio (que poder ser por exemplo 9828383893 ou 36). Como queremos limitar o nmero a um certo valor usamos o mdulo ou resto (%). Assim se ate for 5, o resto de 36 a dividir por 5 1 por isso o nmero vai ser 1. Porm s gera nmeros de 0 a 4 e no at 5. Por isso adicionamos mais 1 valor. O de faz com que acrescente o valor pretendido. A linha ate -= de faz com que s acrescente a diferena entre ate e de. Confuso? Neste momento s precisam de saber que funciona!

Jogo de adivinhar o Nmero - Verso 2


Deixo como trabalho de casa perceberem o que esta nova verso do jogo de adivinhar o nmero faz. S h uma coisa que ainda no falei: variveis globais, mas acho que se explicam por si prprias:
/******************************************** ADIVINHA O NMERO Verso: 2.0 Autor: Joo Portela a.k.a. Agnor Data de Desenvolvimento: 27 de Maro de 2005 *********************************************/ #include <iostream> #include <stdlib.h> #include <windows.h> using namespace std; //para poderem usar o rand() //para poderem usar o GetTickCount()

/* VARIVEIS GLOBAIS Estas variveis podem ser usadas por todas as funes do programa! */ int escolha; //as escolhas do utilizador int numero; //o numero para adivinhar int ContadorTentativa; //conta o numero de tentativas int numeroTentativa; //numero disponivel de tentativas bool done = false; void void void void void void Dica(int escolha); Menu(); inGame(); novoJogo(); Ganhou(); Perdeu(); //mostra uma dica //menu do jogo //dentro do jogo //cria novo jogo //mensagem mostrada a quem ganhou //... a quem perdeu

int getRandom(int de, int ate) //gera numeros aleatorios { int random; ate -= de; random = rand() % (ate + 1) + de; return random; } int main() {

http://agnor.gamedev-pt.net/gamedev/cpp.html
srand(GetTickCount()); cout << "Bem-Vindo ao JOGO ADIVINHA O NUMERO - VERSAO 2" << endl; cout << "Por Joao Portela a.k.a. Agnor" << endl; while(!done) { Menu(); } cin.get(); return 0; //ja viram que main pequeno? :P

void Menu() { cout << "\nO que pretende fazer?" << endl; cout << "\n1 - Novo jogo" << endl; cout << "2 - Sair" << endl; cin >> escolha; switch(escolha) { case 1: novoJogo(); break; case 2: done = true; //acaba o loop do while break; default: cout << "\nErro...Tecla errada" << endl; Menu(); //volta ao menu break; } } void novoJogo() { ContadorTentativa = 0; cout << "\nEscolha o nivel de dificuldade:" << endl; cout << "1 - 1 a 10" << endl; cout << "2 - 1 a 20" << endl; cout << "3 - 1 a 30" << endl; cout << "4 - 1 a 40" << endl; cout << "E por ai a diante :P" << endl; cin >> escolha; if (escolha <= 0) { cout << "\nErro, numero menor ou igual a 0...\nIniciando com nivel 1" << endl; escolha = 1; } cout << "\nEscolheu de 1 a " << escolha * 10 << endl; numeroTentativa = escolha + 1;

http://agnor.gamedev-pt.net/gamedev/cpp.html
numero = getRandom(1, 10*escolha); inGame(); } void inGame() { if ((numeroTentativa - ContadorTentativa) > 0) { cout << "\nNumero de tentativas restantes: " << numeroTentativa ContadorTentativa << endl; cout << "Insira um numero: "; cin >> escolha; ContadorTentativa++; if (escolha == numero) { Ganhou(); } else { Dica(escolha); } } else { Perdeu(); } } void Ganhou() { cout << "\nParabens, Ganhou!!!" << endl; } void Perdeu() { cout << "\nPode ser que tenhas mais sorte para a proxima... perdeste..." << endl; } void Dica(int escolha) { if (escolha < numero) cout << "\nTem que apostar mais para cima" << endl; else cout << "\nTem que apostar mais para baixo" << endl; inGame(); }

Exemplo 6.7 - Jogo Adivinha o Nmero 2.0

http://agnor.gamedev-pt.net/gamedev/cpp.html Final da aula 06 de C++: Prxima aula -> C++ 07 - Arrays Fazer o download do cdigo fonte dos exemplos da aula Fazer o download da aula em PDF (Brevemente) Ir para o topo da pgina

Aula 07 - Arrays
<!-google_ad_client = "pub-9639791948153775"; google_ad_width = 336; google_ad_height = 280; google_ad_format = "336x280_as"; google_ad_type = "text"; google_ad_channel ="3703014365"; google_color_border = "FFFFFF"; google_color_bg = "FFFFFF"; google_color_link = "0000FF"; google_color_url = "000000"; google_color_text = "000000"; //-->Conceitos-Chave: - array, como um grupo de variveis com o mesmo identificador - strings, conjunto de caracteres, normalmente colocados num array - arrays bidimensionais, normalmente utilizados em mapas

Arrays
Os arrays so um "grupo de lugares na memria, que tm o mesmo nome e guardam o mesmo tipo de dados". Para explicar melhor, um exemplo: Imaginem que estamos a fazer um programa que calcule a mdia de temperatura semanal, considerando, por exemplo, estes valores: Dia Segunda Tera Quarta Quinta Sexta Sbado Domingo Temperatura (C) 15 19 19 17 16 20 14

At agora a maneira mais fcil seria criar 7 inteiros... Mas no . Sete inteiros no muito trabalho, mas imaginem que seria para 30 dias. Que nomes vo arranjar? int dia1, int dia2, int dia3....

http://agnor.gamedev-pt.net/gamedev/cpp.html Os arrays simplificam muito. So declarados assim: int dias[7]; Temos aqui um array de 7 inteiros, que vo desde o nmero 0 at ao 6. Fiquem com um exemplo prtico:
#include <iostream> using namespace std; int dias[7]; //cria um array de 7 caracteres ( de dias[0] a dias[6] ) int main () { for(int n = 0; n < 7; n++) { cout << "Introduza o valor do " << n + 1 << "o dia: " << endl; //n + 1 porque em C++ o array comea no 0 em vez de 1 cin >> dias[n]; } int media = ( dias[0] + dias[1] + dias[2] + dias[3] + dias[4] + dias[5] + dias[6] ) / 7; cout << "A media semanal das temperaturas e de " << media << endl; cin.get(); cin.get(); return 0; }

Exemplo 7.1 - Calcular a mdia semanal das temperaturas Os arrays comeam no 0 ( dias[0] ) foi por isso que fiz int n = 0 em vez de int n = 1. No cout << "Introduza o valor do " << n + 1 << "o dia: " << endl; o n + 1 serve para o numero do dia visualizado ser apresentado correctamente... Abaixo iremos ver o uso do operador for

Preenchendo arrays utilizando o operador for


Uma forma simples de preencher arrays utilizando o operador for. No exemplo seguinte, veremos como preencher um array com um nmero escolhido pelo utilizador:
#include <iostream> using namespace std; int main() { int MAX_ELEMENTS = 10; int arr[MAX_ELEMENTS]; elementos int valor;

//o numero mximo de elementos do array //declara um array com um nmero predefinido de

//valor de cada elemento do array ( igual...)

cout << "Insira o valor a ser atribuido a cada elemento do array: "; cin >> valor; for (int i = 0; i < MAX_ELEMENTS; i++) {

http://agnor.gamedev-pt.net/gamedev/cpp.html
arr[i] = valor; //vai percorrer o array de 0 a MAX_ELEMENTS } cin.get(); cin.get(); } return 0;

Exemplo 7.2 - Dar um valor a todos os elementos do array No exemplo acima, o programa vai percorrer todos os elementos do array, comeando no 0 (int i = 0), acabando no MAX_ELEMENTS (i = MAX_ELEMENTS) e incrementando o i por 1 (i++). uma forma bastante simples e com pouco cdigo. Agora veremos como dar um valor personalizado a cada elemento do array:
#include <iostream> using namespace std; int main() { int MAX_ELEMENTS = 5; int arr[MAX_ELEMENTS]; elementos int valor;

//o numero mximo de elementos do array //declara um array com um nmero predefinido de

//valor de cada elemento do array ( igual...)

//escrever no array for (int i = 0; i < MAX_ELEMENTS; i++) { cout << "Insira o valor a ser atribuido ao elemento " << i << " do array: "; cin >> valor; arr[i] = valor; //vai percorrer o array de 0 a MAX_ELEMENTS } //ler no array for (int a = 0; a < MAX_ELEMENTS; a++) { cout << "array[" << a << "] = " << arr[a] << endl;; } cin.get(); cin.get(); return 0; }

Exemplo 7.3 - Dar valores aos elementos dos arrays As alteraes nem foram assim tantas: a disposio do cout e do cin que mudaram para dentro do for. Tambm criei outro for para o utilizador poder ver os resultados, seguindo o mesmo princpio

http://agnor.gamedev-pt.net/gamedev/cpp.html de escrita.

Trabalhando com caracteres - Introduo


At agora temos usado s o tipo de varivel int. Vou-vos ensinar a trabalhar com caracteres (utilizando o tipo de varivel char), que utilizado se quisermos armazenar o nome da personagem, por exemplo. Eu no falei sobre o tipo char porque se fizermos: char nome; o nome s pode armazenar 1 caracter. Com o estudo de arrays podemos ento armazenar um nome. Por exemplo: char nome[6] = "Agnor"; Isto iria criar um array de 6 variveis de tipo char. Repararam que declaramos 6 variveis no array, mas Agnor tem s 5 letras. Isto porque obrigatoriamente todas as strings (arrays de caracteres) terminam com o "caracter terminador" ('\0'). Vejam este exemplo bsico:
#include <iostream> using namespace std; int main() { int MAX_CHARS = 30; char nome[MAX_CHARS]; cout << "Por favor insira o seu nome: "; cin >> nome; cout << "\nOla, " << nome; cin.get(); cin.get(); return 0; }

Exemplo 7.4 - Mensagem de Boas Vindas Como vm o vosso nome no pode ter mais de 29 caracteres neste exemplo, mas podem expandir vontade (desde que no exagerem, pois cada caracter ocupa 1 byte).

Arrays Bidimensionais
Os arrays bidimensionais so muito utilizados nos mapas... Vamos dar o exemplo de um mapa da Batalha Naval: 0 0 1 2 3 4 5 6 0 0 0 0 0 2 0 1 5 0 0 0 0 2 0 2 5 0 0 0 0 0 0 3 5 0 0 0 0 0 0 4 5 0 0 4 3 4 4 5 5 0 0 0 0 0 0 6 0 0 0 0 3 0 0 7 0 0 0 0 3 0 0 8 0 0 0 0 3 0 0

http://agnor.gamedev-pt.net/gamedev/cpp.html Legenda: 0 - gua 2 - Navio que ocupa 2 lugares 3 - Navio que ocupa 3 lugares 4 - Navio que ocupa 4 lugares 5 - Navio que ocupa 5 lugares Para passarmos isso num array normal....era complicado, mas num array bidimensional razoavelmente fcil: int mapa[7][9]; Depois "s" tnhamos que fazer mapa[0][0] = 0; mapa[0][1] = 2; etc... Felizmente h um mtodo mais simples de carregar mapas, utilizando o operador for e a leitura de ficheiros. Isto ser explorado em lies futuras. Final da aula 07 de C++: Prxima aula -> C++ 08 - Leitura e Escrita em Ficheiros de Texto - Introduo Fazer o download do cdigo fonte dos exemplos da aula Fazer o download da aula em PDF (Brevemente) Ir para o topo da pgina

Aula 08 - Escrita e Leitura em Ficheiros - Introduo


<!-google_ad_client = "pub-9639791948153775"; google_ad_width = 336; google_ad_height = 280; google_ad_format = "336x280_as"; google_ad_type = "text"; google_ad_channel ="3703014365"; google_color_border = "FFFFFF"; google_color_bg = "FFFFFF"; google_color_link = "0000FF"; google_color_url = "000000"; google_color_text = "000000"; //-->Conceitos-Chave: - fstream, biblioteca standard do C++ para leitura e escrita em ficheiros - ofstream, para escrita em ficheiros - ifstream, para leitura em ficheiros - getline(), funo para receber uma frase do utilizador (cin.getline) ou de um ficheiro (ifstream::getline)

Escrita e Leitura em Ficheiros


A leitura (e escrita) de ficheiros tornou-se essencial em programao de jogos, por exemplo na construo de mapas e para guardar o percurso do jogador no jogo. Durante esta lio vamo-nos concentrar no bsico da escrita e leitura em ficheiros. O carregamento de mapas e tratamento de dados vir depois.

http://agnor.gamedev-pt.net/gamedev/cpp.html Para podermos ter acesso leitura (ou escrita) de ficheiros teremos que usar a biblioteca fstream (file stream). A melhor forma de explicar o bsico da escrita/leitura em ficheiros com um programa:
#include <iostream> #include <fstream> //inclui a biblioteca fstream, para usar o ofstream e ifstream using namespace std; int main() { // para escrita a instruo ofstream variavel("nome_do_ficheiro.txt) ofstream doc_out("save.txt"); //abre o ficheiro save.txt para escrita // para leitura a instruo ifstream variavel("nome_do_ficheiro.txt) ifstream doc_in("save.txt"); //abre o ficheiro save.txt para leitura char aux[50]; //cria um array com capacidade para 50 caracteres doc_out << "Nivel:1\n" << "Nick:Agnor" << endl; doc_out.close(); //no se esqueam de fechar os ficheiros de escrita!!!!

while (doc_in >> aux) //enquanto o contedo do documento no for transferido para o aux... { cout << aux << endl; //...imprime no ecr as palavras. } //notem que o ficheiro de leitura no necessita de ser fechado cin.get(); return 0; }

Exemplo 8.1 - Escrever e Ler num ficheiro de texto Vamos por partes:

ofstream
ofstream significa output file stream e serve para a escrita em ficheiros. Antes de poder escrever alguma coisa, temos que definir em que ficheiro queremos guardar o texto: ofstream nome_da_variavel(nome_do_ficheiro). Tanto o ofstream e o ifstream pertencem bilbioteca fstream, que tem de ser includa no programa ( #include <fstream>). De notar que todos os ficheiros de escrita necessitam de ser fechados, quando no precisarmos mais deles (usando o close() ).

ifstream
ifstream serve para a leitura de ficheiros (input file stream). Define-se como a biblioteca ofstream: ifstream nome_da_variavel(nome_do_ficheiro) Dica:

http://agnor.gamedev-pt.net/gamedev/cpp.html Para aceder a um ficheiro de texto que esteja dentro de uma pasta, temos de separar o nome da pasta do nome do ficheiro, atravs de uma barra '/'. Por exemplo: ofstream mapa("mapas/nivel1.map");

doc_out << string; e doc_in >> string;


Enviamos texto para um ficheiro da mesma forma que enviamos para o console output e lemos um ficheiro da mesma forma que o lemos atravs do console input. Neste exemplo: doc_out << "Nivel:1" <<- estamos a enviar a string "Nivel:1" e o comando endl (para mudar de linha) para o doc_out, ou seja, para o ficheiro identificado por doc_out (save.txt). doc_in >> aux - estamos a enviar o contedo de doc_in (apenas a primeira palavra) para a string aux.

doc_out.close()
Sempre que acabarmos de escrever no ficheiro, temos de fech-lo. Para tal existe a funo close() dentro da biblioteca fstream. Notem que utilizado um '.' (ponto) para unir o doc_out "funo" close(). Isto ser explicado quando falarmos de classes.

while (doc_in >> aux)


Como ao fazermos doc_in >> aux s transferida a primeira palavra para o output, temos de criar um loop. A expresso (doc_in >> aux) vai ser verdadeira quando chegar ao fim do ficheiro. Ento, enquanto no chegar ao fim do ficheiro, ser executada o doc_in >> aux e ser mostrado no cout o contedo de aux. Como cada vez que fazemos doc_in >> aux este avana para a palavra seguinte, mostrado o contedo todo do ficheiro, palavra por palavra.

Usar cin.getline()
O uso de cin.getline() pode-vos parecer totalmente fora do assunto da lio, mas depois percebero porque o pus aqui. At agora, j devem ter reparado que num programa que receba dados do utilizador atravs de cin (console input), s recebero uma palavra e no uma frase. O cin.getline() , como o prprio nome indica, recebe uma linha do utilizador. O prottipo da funo : cin.getline(char *buffer, int length, char terminal_char); O char *buffer ser a string (conjunto de carcteres) onde ser armazenado o input, a lenght ser o tamanho da string e o ltimo ser o carcter terminador. O carcter terminador est predefenido como \n ou seja, quando a frase acabar. Devem notar que h um asterisco (*) antes da varivel buffer. Isso uma declarao de um apontador (que ser explorado na aula 11. O uso de apontadores (char* buffer) permite-nos criar uma string, sem que seja necessrio definir um nmero de caracteres especficos O ltimo parmetro opcional, e na maior parte das vezes pode ser ignorado. Vejam um exemplo de uso com a funo:
#include <iostream> using namespace std; int main() { char nome[150]; //cria uma varivel capaz de conter 150 caracteres

http://agnor.gamedev-pt.net/gamedev/cpp.html
cout << "Insira o seu nome completo:" << endl; cin.getline(nome, 150); cout << "O seu nome e: " << nome << endl; cin.get(); return 0;

Exemplo 8.2 - Uso de cin.getline() Deve ser o suficiente para perceberem, no entanto qualquer dvida e contactem-me.

Ler linhas de ficheiros


Para ler linhas em ficheiros a funo exactamente a mesma, s que aplicada de maneira diferente. Por exemplo: ifstream doc_in("save.txt"); doc_in.getline(variavel, 200); Difcil? Nem por isso :P Sempre que usarmos a funo getline(); o ficheiro avana para a prxima linha (em vez de avanar para a prxima palavra). Experimentem o cdigo abaixo:
#include <iostream> #include <fstream> using namespace std; int main() { char aux[150]; //cria uma varivel capaz de conter 150 caracteres, para a escrita char boas_vindas[150]; char nome[150]; char idade[4]; //s contem 4 carcteres, no preciso mais para a idade //notem que do tipo char e no int... um problema a ser explorado em aulas mais avanadas ifstream doc_in("save.txt"); ofstream doc_out("save.txt"); doc_out << "Bemvindo ao Programa" << endl; pode ser personalizada programador*/ cout << "Insira o seu nome: " << endl; cin.getline(aux, 150); doc_out << aux << endl; cout << "Insira a sua idade: " << endl; cin >> aux; doc_out << aux << endl; doc_out.close(); //fecha o documento /*a mensagem de boas-vindas no pelo utilizador, mas s pelo

http://agnor.gamedev-pt.net/gamedev/cpp.html
doc_in.getline(boas_vindas, 150); muda-se de linha doc_in.getline(nome, 150); doc_in.getline(idade, 4); //cada vez que faz a chamada funo

cout << boas_vindas << " " << nome << ", " << idade << " anos" << endl; system("PAUSE"); return 0;

Exemplo 8.3 - Mensagem de Boas-Vindas 2.0 No necessita de muitas explicaes. H alguns problemas com este cdigo que impedem de ser uma forma vivel de salvar jogos, mas sero explorados (e resolvidos espero :) em futuras lies. Um bom exerccio seria separar o programa, criando uma verso que serviria somente para criar o ficheiro de texto, e outra para l-lo, seria uma verso bastante primitiva de um editor de nveis. Final da aula 08 de C++: Prxima aula -> C++ 09 - Leitura e Escrita em Ficheiros de Texto - Introduo Fazer o download do cdigo fonte dos exemplos da aula Fazer o download da aula em PDF (Brevemente) Ir para o topo da pgina

Aula 09 - Enumeraes e Estruturas


<!-google_ad_client = "pub-9639791948153775"; google_ad_width = 336; google_ad_height = 280; google_ad_format = "336x280_as"; google_ad_type = "text"; google_ad_channel ="3703014365"; google_color_border = "FFFFFF"; google_color_bg = "FFFFFF"; google_color_link = "0000FF"; google_color_url = "000000"; google_color_text = "000000"; //-->Conceitos-Chave: - enumeraes, como forma de atribuir um sentido lgico ao cdigo - estruturas, como um conjunto de propriedades de uma varivel

Enumeraes
As enumeraes servem para ajudar a fazer um cdigo mais lgico. Imaginemos que temos uma funo que recebe o parmetro: int cor;

http://agnor.gamedev-pt.net/gamedev/cpp.html Decidamos, para representar cores em nmeros inteiros, convencionar o valor do azul como 1, o do vermelho como 2 e o do verde como 3. Assim, para representar a cor azul faramos algo do tipo: cor = 1; Teramos ento que memorizar uma tabela com as cores, ou andar sempre com uma quando programamos... Felizmente, existem as enumeraes:
#include <iostream> using namespace std; enum CORES { AZUL = 1, VERMELHO = 2, VERDE = 3 }; //no se esqueam das chavetas, NEM DO PONTO E VRGULA int VerificarCor(CORES cor_a_ver); int main() { CORES cor; cor = AZUL; VerificarCor(cor); cor = VERMELHO; VerificarCor(cor); VerificarCor(VERDE); cout << AZUL << " " << VERMELHO << " " << VERDE << " " << cor << endl; cin.get(); return 0; } int VerificarCor(CORES cor_a_ver) { if (cor_a_ver == AZUL) { cout << "A Cor que escolheu foi Azul" << endl; } else if (cor_a_ver == VERMELHO) { cout << "A Cor que escolheu foi Vermelho" << endl; } else if (cor_a_ver == VERDE) { cout << "A Cor que escolheu foi Verde" << endl; } } //funo para verificar qual a cor

//vejam! CORES um tipo de varivel

Exemplo 9.1 - Enumeraes: Cores Acho simples de perceber, afinal as enumeraes existem para simplificar a escrita (e posterior leitura) do cdigo.

http://agnor.gamedev-pt.net/gamedev/cpp.html Resta s dizer que uma enumerao uma varivel constante, ou seja, o valor de AZUL, VERMELHO e VERDE no poder ser alterada. No se esqueam que, se fizerem cout << AZUL; ir aparecer '1' e no "AZUL", mas isso obvio... Dica: No exemplo acima fizemos: enum CORES { AZUL = 1, VERMELHO = 2, VERDE = 3 }; Mas poderamos ter feito: enum CORES { AZUL = 1, VERMELHO, VERDE}; Que faz rigorosamente o mesmo efeito, pois basta atribuir valor a uma varivel, que as outras so incrementadas ( += 1) Tambm poderamos fazer: enum CORES { AZUL, VERMELHO, VERDE}; Mas desta vez AZUL seria igual a 0 e no a 1

Uso de enumeraes em jogos


Dentro de programao de jogos existem vrios usos para enumeraes. Por exemplo, comum usar enumeraes para representar o teclado, uma vez que, em algumas bibliotecas, o valor da tecla premida pelo utilizador est expresso em nmeros (em alguns casos em hexadecimal). Assim: enum Teclas { ... KEY_LEFT = 112, KEY_RIGHT = 113, ... }; Teclas t; if(t == KEY_LEFT) { moverNaveEsquerda(); } Os valores so inventados, mas processa-se algo semelhante nos jogos. Em vez de fazermos if(t == 112) podemos fazer if(t == KEY_LEFT) que muito mais simples. Outro uso para enumeraes dentro dos jogos no ciclo de jogo. So criados vrios estados (CORRER, PARADO, NOVO_JOGO, MENU_JOGO, por exemplo) e sempre que quisermos mudar de um estado para o outro, bastaria modificar a varivel que guarda os valores. Veremos isto mais adiante, quando criarmos o primeiro jogo em 2D.

Estruturas
Uma estrutura pode ser considerada como um esboo das propriedades de uma determinada varivel. Imaginemos que temos 3 personagens num jogo: Nillight, Laveius e Nysker. Cada personagem tem as seguintes variveis: int hp (Health Points = Pontos de Sade), int mp (Magic Points = Pontos de Magia) e Criaremos ento uma estrutura chamada Personagem:
#include <iostream>

http://agnor.gamedev-pt.net/gamedev/cpp.html
using namespace std; struct Personagem { int hp, mp; //podem fazer isto; explicao abaixo. }; //Olhem o ponto e vrgula ; !!!!!!!

int main() { //diferentes maneiras de preencher as variveis: Personagem Nillight = { 30, //HP 10, //MP }; Personagem Laveius = { 50, 7 }; Personagem Nysker; Nysker.hp = 20; //d para fazer isto Nysker.mp = 60; cout << Nillight.mp cout << << endl; cout << endl; "HP de Nillight e de " << Nillight.hp << " e o MP e de " << << endl; "HP de Laveius e de " << Laveius.hp << " e o MP e de " << Laveius.mp "HP de Nysker e de " << Nysker.hp << " e o MP e de " << Nysker.mp <<

cin.get(); return 0;

Exemplo 9.2 - Estrutura Personagem Uma estrutura define-se da seguinte forma: struct nome_da_estrutura { //...variveis }; Aviso: Nunca se esqueam do ';' depois de fecharem as chavetas '{}'. Para podermos aceder s variveis que esto dentro da estrutura, utilizamos um ponto a separar a varivel "estruturada" e a propriedade: Personagem teste; teste.hp = 0; cout << teste.hp; Podemos criar estruturas para praticamente tudo. No exemplo seguinte vou representar uma estrutura de um quadrado (figura geomtrica):
#include <iostream> using namespace std; struct Quadrado {

http://agnor.gamedev-pt.net/gamedev/cpp.html
int lado; int area;

};

int calcularArea(Quadrado quadrado) { return (quadrado.lado * quadrado.lado); } int main() { Quadrado square; square.lado = 4; square.area = calcularArea(square); cout << "Area do Quadrado: " << square.area << endl; cin.get(); return 0; }

Exemplo 9.3 - Estrutura Quadrado - Mostrar a rea de um quadrado Para trabalho de casa, podem criar funes para alterar ou mostrar facilmente os vrios atributos. Assim o prottipo da funo para visualizar o HP de uma personagem seria: int getHP(Personagem personagem); E para modificar o valor seria: void setHP(int hp, Personagem personagem);

Jogo - Hall of Monsters


um jogo simples, criado por mim, baseado nas aventuras em modo de texto (estilo MUD). Podese dizer que um resumo das aulas at agora:
/* * * * * * * * */ Exemplo 9.4 - Hall of Monsters Propriedade de http://agnor.gamedev-pt.net Autor : Joo Portela aka Agnor Data : 20/02/2004 a 21/02/2004 Desc : Hall of Monsters - jogo-tutorial

#include <iostream> #include <windows.h> //para usar o GetTickCount(); using namespace std; /************************************ **************ESTRUTURAS************* ************************************/

http://agnor.gamedev-pt.net/gamedev/cpp.html
struct Personagem { int hp; //os pontos de vida int mp; //Pontos de Mana int max_hp; // vai ser usada para recuperar o personagem no fim de cada partida int max_mp; // como dito em cima..... int forca; // a forca do personagem }; struct Monstro { int hp; // HP do monstro int forca; //forca do monstro //monstros no necessitam de MP char *nome; // necessrio para podermos alterar o valor do nome sempre que quisermos... //ser explicado na aula 11 - referncias e apontadores }; ///////////////////////////////////// ///////////Variveis///////////////// ///////////////////////////////////// Personagem player = {50, 7, 50, 7, 5}; Monstro ORC = { 40, 10, "Orc" }; Monstro LIZARD = { 60, 15, "Lizard" }; Monstro SHADOW = { 100, 23, "Shadow" }; Monstro BAHAMUT = { 140, 31, "Bahamut" }; Monstro ULTIMA = { 1000, 100, "Ultima" }; // tentem matar este :P /* Declaraes das funes * int int int int int int int menuJogo(); chamarBatalha(Monstro monstro); menuBatalha(Monstro monstro); MonstroIA(Monstro monstro); ganhou(); perdeu(); getRandom(int de, int ate); */ *

//que main pequeno no ? int main() { menuJogo(); cin.get(); return 0; } /* chamarBatalha(monstro); Desc: chama uma Batalha para um determinado monstro ( ex: chamarBatalha(SHADOW); ) */

http://agnor.gamedev-pt.net/gamedev/cpp.html
int chamarBatalha (Monstro monstro) { cout << "\n\nApareceu um " << monstro.nome << endl; menuBatalha(monstro); return 0; } /* Cria o menu de Batalha ( utilizada por chamarBatalha(monstro); ) */ int menuBatalha (Monstro monstro) { int escolha; cout << "\n\nSeu HP: " << player.hp << '/' << player.max_hp << endl; cout << "Seu MP: " << player.mp << '/' << player.max_mp << endl; cout << "Escolha um ataque:" << endl; cout << "\n1 - Ataque normal" << endl; cout << "2 - Fogo" << endl; cin >> escolha; switch (escolha) case 1: monstro.hp -= player.forca * 7; cout << "\nVoce atacou!" << endl; break; case 2: monstro.hp -= player.forca * 10; player.mp -= 7; cout << "\nVoce usou o fogo!" << endl; break; default: cout << "\nComando nao conhecido..." << endl; menuBatalha(monstro); //estamos a utilizar recursividade nas funes: o menu vai ser break; } if ( monstro.hp <= 0 ) ganhou(); //se s tiver uma instruo, um if no precisa de ter chavetas { ... } else MonstroIA(monstro); return 0; } // A intelegncia artificial do Monstro. Para dar mais hipoteses aos jogadores // s h 25% do Monstro utilizar o ataque especial int MonstroIA(Monstro monstro) { int random; random = getRandom(1, 4); switch (random) {

chamado de novo

http://agnor.gamedev-pt.net/gamedev/cpp.html
{ case 1: case 2: case 3: cout << "\n\n" << monstro.nome << " atacou!" << endl; player.hp -= monstro.forca; break; case 4: especial" << endl; cout << "\n\n" << monstro.nome << " usou o seu ataque player.hp -= monstro.forca * 2; break; } if (player.hp <= 0) perdeu(); else menuBatalha(monstro); } return 0;

//a popular funo getRandom int getRandom(int de, int ate) {

srand(GetTickCount()); int random = ( rand() % ate ) + de; return random;

// perdeu :((((( int perdeu() { cout << "\nPerdeu... Na proxima vez vais ter mais sorte :(" << endl; menuJogo(); return 0; } //ganhou... e tambm subiu de nvel :PPPP int ganhou() { cout << "\n\n\nWee ganhou!!!!! e subiu de nivel :P" << endl; player.forca += 2; //as modificaes para "subir de nivel" player.max_hp += 10; player.max_mp += 7; player.hp = player.max_hp; //recuperar a energia player.mp = player.max_mp; //esperar..... cin.get(); menuJogo(); return 0;

http://agnor.gamedev-pt.net/gamedev/cpp.html
} // o menu do jogo int menuJogo() { int escolha; cout << "\nEscolha um adversario:" << endl; cout << "\n1 - Orc" << endl; cout << "\n2 - Lizard" << endl; cout << "\n3 - Shadow" << endl; cout << "\n4 - Bahamut" << endl; cout << "\n5 - ULTIMA" << endl; cin >> escolha; switch (escolha) { case 1: chamarBatalha(ORC); break; case 2: chamarBatalha(LIZARD); break; case 3: chamarBatalha(SHADOW); break; case 4: chamarBatalha(BAHAMUT); break; case 5: chamarBatalha(ULTIMA); break; default: cout << "Comando nao conhecido.... tente outra vez\n\n" << endl; menuJogo(); break; } return 0; }

Exemplo 9.4 - Hall of Monsters um jogo bastante simples e com alguns bugs (erros lgicos), mas demonstra tudo o que aprendemos. Experimentem fazer uma modificao do programa, adicionando mais monstros, corrigindo bugs, adicionando ataques. Podem usar o email rpgplus@iol.pt para me mandarem o jogo para corrigir (e quem sabe publicar no site as modificaes :) Final da aula 09 de C++: Prxima aula -> C++ 10 - Alcance e Tempo de Vida de Variveis

http://agnor.gamedev-pt.net/gamedev/cpp.html Fazer o download do cdigo fonte dos exemplos da aula Fazer o download da aula em PDF (Brevemente) Ir para o topo da pgina

Aula 10 - Alcance e Tempo de Vida de Variveis


<!-google_ad_client = "pub-9639791948153775"; google_ad_width = 336; google_ad_height = 280; google_ad_format = "336x280_as"; google_ad_type = "text"; google_ad_channel ="3703014365"; google_color_border = "FFFFFF"; google_color_bg = "FFFFFF"; google_color_link = "0000FF"; google_color_url = "000000"; google_color_text = "000000"; //-->Conceitos-Chave: - varivel global, varivel que pode ser acedida em todos os blocos do programa - varivel local, varivel que s pode ser acedida no bloco em que foi declarada - operador resoluo de alcance (::), operador para aceder a variveis globais que tenham o mesmo identificador de uma varivel local - tempo de vida de uma varivel, espao de tempo em que uma determinada varivel fica guardada na memria - variveis estticas, variveis que, embora locais (de um ponto de vista de alcance), possuem o mesmo tempo de vida de uma varivel global

Declarao de variveis globais e locais


Se j tentaram fazer algum programa, de certeza que j se depararam com diversos erros de compilao. Decerto que alguns foram por distrao, mas outros podero ter sido originados pelo simples facto de declarar uma varivel localmente, em vez de declar-la globalmente. Se vos aconteceu, em parte foi culpa minha, por no ter explicado isto h mais tempo (embora tenha dado uma pequena introduo na aula 06), por isso esta aula dedicada a explicar este conceito. Primeiro de tudo, uma varivel global uma varivel que poder ser usada em todo o programa. Uma varivel local s poder ser usada no bloco ou funo onde foi declarada. Para podermos declarar uma varivel global teremos que a declarar fora da definio de uma funo ou um bloco. Para termos uma varivel local teremos que declarar a varivel dentro da definio de uma funo ou um bloco. Est aqui um exemplo:
#include <iostream> using namespace std; int func(); int x = 100; //varivel global, portanto pode ser usada em todo o programa int main() {

http://agnor.gamedev-pt.net/gamedev/cpp.html
int y = 2; //varivel local, s pode ser usada na funo main() return 0; } int func() { int z = 10; //varivel local, s pode ser usada na funo func() return x; }

Exemplo 10.1 - Variveis globais vs variveis locais Acho que j perceberam como se define uma varivel global e uma varivel local. Notem tambm que os argumentos de uma funo so locais mesma.

Variveis globais e locais num programa


Para terem uma ideia prtica dos vrios erros que podemos cometer vejam este programa todo comentado:
#include <iostream> using namespace std; int i = 20; // varivel global, usada no programa todo void funcao(); int main() { int x; i = 30; funcao(); y = 20; //erro!!! y s foi declarado dentro da funcao() logo no est acessvel dentro de main() x = 10; //correcto, por x pertencer funao main i = 20; //correcto for (int a = 1; a < 10; a++) { //inicio do bloco a = 2; //cuidado isto e um for infinito, j que a nunca passa de 2, no chegando, por isso a 10!!!!! } //fim do bloco a = 30; //errado!!! a s pode ser acedida dentro do for cin.get(); return 0; } void funcao() { int y; //declarar uma varivel dentro da funcao(); // declarar uma varivel inteira // correcto, porque i uma varivel global!

http://agnor.gamedev-pt.net/gamedev/cpp.html
x = 30; y = 10; i = 5; } //errado! x no est declarado nesta funao(); //correcto //correcto. i uma varivel global;

Exemplo no compilvel PS: Nem sequer tentem compilar este programa, pois est cheio de erros :D Dica: Alguns compiladores consideram a instruo for um caso parte, ou seja, consideram que se uma varivel for definida dentro do bloco do for essa mesma varivel ir pertencer funo onde est contida, em vez de pertencer somente ao bloco: for (int a = 0; a < 10; a++) { cout << a; } a = 2 //em alguns compiladores isto daria erro, noutros estaria tudo bem.... Toda a teoria acima descrita est aplicada neste exemplo.

Operador resoluo de alcance (::)


Vejam o seguinte exemplo:
#include <iostream> using namespace std; int x, y; void andarDireita(int x); int main() { x = 20; andarDireita(15); cout << x << endl; cin.get(); return 0; } void andarDireita(int x) { ::x += x; // a varivel global x += a varivel local x }

Exemplo 10.2 - Usando o operador de resoluo de alcance :: Desta forma podemos usar variveis globais, mesmo que existam variveis locais com o mesmo nome dentro da funo.

Memria e Tempo de Vida


Imaginem a memria como uma sequncia de bytes. Cada byte possui 2 tipos de valores: um

http://agnor.gamedev-pt.net/gamedev/cpp.html
nmero (o valor que atribumos) e um endereo. Ao criarmos uma varivel estaremos a colocar, num determinado endereo da memria, um valor. Imaginemos que estamos a olhar para a memria do computador (do endereo 93 a 107):

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

Agora se escrevssemos em C++: int x = 70; Estaramos a escrever na memria algo como: 70 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107

PS: A tabela no representa totalmente a realidade, pois cada int ocupa 4 bytes (deveria estar escrito em binrio e no em decimal), mas acho que perceberam a ideia.... Isto serviu para vocs tentarem visualizar o que a memria do computador. Como devem saber a memria que temos disponvel no computador limitada e, por isso, em programas maiores, teremos que ter cuidado para poupar o mximo possvel de memria. O prprio C++ faz isso, de uma maneira simples. As variveis globais iro estar sempre alocadas na memria (at o programa desligar) enquanto as variveis locais s iro ser alocadas na memria quando a funo ou o bloco for chamado e iro ser eliminadas quando a funo ou bloco termina.

Variveis estticas (static)


Vejam este exemplo:
#include <iostream> using namespace std; int incrementar(); //funo que tem como objectivo incrementar um valor int h; //varivel global int main() { for (int x = 0; x < 10; x++) { h = incrementar(); //incrementar 10 vezes a varivel h global } cout << h << endl; //mostrar o resultado cin.get(); return 0; } int incrementar() { int h = 0; //cria uma varivel local //notem que no existe conflito com a varivel global //que tem o mesmo nome. h++; //incrementa return h; //devolve o resultado }

http://agnor.gamedev-pt.net/gamedev/cpp.html Exemplo 10.3 - Funo incrementar v0.1 O objectivo do programa era obter, no final, o valor de 10. No entanto obtemos o valor de 1. Porqu? A resposta est no tempo de vida da varivel local h. Ela construda e destruda 10 vezes. Cada vez que destruda perde qualquer valor guardado e cada vez que construda ela assume o valor de 0. Para remediar isto o melhor construir uma varivel esttica, atravs da keyword static.
#include <iostream> using namespace std; int incrementar(); //funo que tem como objectivo incrementar um valor int h; //varivel global int main() { for (int x = 0; x < 10; x++) { h = incrementar(); //incrementar 10 vezes a varivel h global } cout << h << endl; //mostrar o resultado cin.get(); return 0; } int incrementar() { static int h = 0; //cria uma varivel local esttica //notem que no existe conflito com a varivel global //que tem o mesmo nome. h++; //incrementa return h; //devolve o resultado }

Exemplo 10.4 - Funo incrementar v1.0 Uma varivel esttica tem o mesmo tempo de vida de uma varivel global ( iniciada no incio do programa e destruda no fim), mas possui o alcance de uma varivel local (no pode ser usada fora da funo onde foi declarada). Aviso: Temos que atribuir sempre um valor quando declaramos uma varivel esttica Dica: Se declararmos uma varivel global sem atribuirmos um valor, esta vai adquirir o valor 0. Se declararmos uma varivel local sem atribuirmos um valor, esta vai adquirir um valor aleatrio. Final da aula 10 de C++: Prxima aula -> C++ 11 - Referncias e Apontadores Fazer o download do cdigo fonte dos exemplos da aula Fazer o download da aula em PDF (Brevemente) Ir para o topo da pgina

http://agnor.gamedev-pt.net/gamedev/cpp.html

Aula 11 - Referncias e Apontadores


<!-google_ad_client = "pub-9639791948153775"; google_ad_width = 336; google_ad_height = 280; google_ad_format = "336x280_as"; google_ad_type = "text"; google_ad_channel ="3703014365"; google_color_border = "FFFFFF"; google_color_bg = "FFFFFF"; google_color_link = "0000FF"; google_color_url = "000000"; google_color_text = "000000"; //-->Conceitos-Chave: - apontador, varivel que aponta para outra varivel, contendo o endereo desta - endereo, local de uma varivel na memria. Pensem como se fosse a morada de uma varivel no computador - referncia, o "nickname" de uma varivel - operador endereo de (&), serve para obter o endereo de uma varivel - operaes com o valor de de variveis apontadas por apontadores, como aceder ao valor de outra varivel, atravs do uso de apontadores

Conceito de endereo e de valor - reviso


Na aula anterior (em que falei de memria) j dei uma breve explicao de endereo e de valor de uma varivel. Nesta aula vou rever os conceitos, pois para aprenderem apontadores e referncias muito mais fcil se tiverem estes conceitos em mente. Se tivessemos um programa a correr, a memria pareceria alguma coisa como: Valor
Endereo 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177

Se o programa encontrasse uma linha de cdigo do gnero: int x = 25; o programa iria introduzir o valor 25 num endereo aleatrio: Valor 25
Endereo 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177

Apontadores - breve explicao


Apontadores so uma varivel como qualquer outra s que, em vez de conterem valores, contm endereos de variveis. Os apontadores so definidos atravs de um * (asterisco) antes da varivel ( int *pointer; ). H vrias utilidades para os apontadores. Nesta lio vou s ensinar algumas operaes bsicas com apontadores (nomeadamente com o valor da varivel apontada). Segue-se, por enquanto, uma explicao sobre referncias e o operador endereo de (que ir ser importante para o uso com apontadores)

http://agnor.gamedev-pt.net/gamedev/cpp.html

Operador referncia (&) e operador endereo de (&)


Se leram o ttulo acima devem pensar que estou enganado, pois os dois operadores so representados com o mesmo smbolo. No erro e os dois operadores so mesmo representados pelo mesmo smbolo (&) e a nica forma de distinguirmos um do outro pelo contexto, mas no se preocupem porque, como vo ver, isso muito simples. Comecemos pelo operador referncia. Quando o smbolo & utilizado ao definirmos uma varivel esta, em vez de ser uma varivel normal, ir passar a ser uma referncia para outra varivel, ou seja, ir ser como um "nickname" (alcunha) para esta:
#include <iostream> using namespace std; int main() { int i; int &i_ref = i; i = 20; cout << "Variavel i: " << i << endl; cout << "Referencia para i: " << i << endl; i_ref = 10; cout << "\nVariavel i: " << i << endl; cout << "Referencia para i: " << i << endl; cin.get(); return 0;

Exemplo 11.1 - Usando Referncias Nota: Quando declaramos uma referncia temos que atribuir logo a varivel que queremos referenciar: int &ref; ref = i; // errado! --int &ref = i; //certo! Como podem ver pelo programa tanto i como i_ref possuem os mesmos valores e, se alterarmos o valor a uma delas, a outra ir necessariamente ser alterada para o mesmo valor. Como j devem ter percebido no h muitas vantagens na utilizao de referncias neste caso, mas se as utilizarmos como argumentos para funes, vero a sua verdadeira utilidade:
#include <iostream> using namespace std; // Funo Swap // Desc: troca os valores de 2 variveis inteiras void swap(int &x, int &y); //passamos os argumentos como referncia

http://agnor.gamedev-pt.net/gamedev/cpp.html
int main() { int a = 20; int b = 10; cout << "A:" << a << endl; cout << "B:" << b << endl; swap(a, b); cout << "\n\nA:" << a << endl; cout << "B:" << b << endl; cin.get(); return 0;

void swap(int &x, int &y) { int temp; //varivel temporria, para no perdermos o valor do x temp = x; x = y; y = temp; }

Exemplo 11.2 - Funo Swap Resumindo, para que possamos alterar os 2 valores em simultneo (sem recurso a variveis globais) usamos referncias. Poderamos usar variveis globais para isso, mas com projectos enormes teramos uma lista enorma de variveis globais. Agora vou discutir o uso do operador endereo de.

Operador endereo de (&)


O operador endereo de (&) serve para obter o endereo de uma varivel. Vejamos o seguinte programa:
#include <iostream> using namespace std; int main() { int var = 30; cout << "Endereco da variavel var: " << &var << endl; cout << "Valor da variavel var: " << var << endl; cin.get(); return 0;

Exemplo 11.3 - Usando o operador endereo de (&) Como podem observar, se correrem o programa, iro obter um nmero estranho quando fazemos &var. Esse nmero o endereo da varivel var na memria e est expresso numa base

http://agnor.gamedev-pt.net/gamedev/cpp.html hexadecimal (por exemplo: 0x22ff31). Falta dizer que se quiserem guardar o endereo de uma varivel tero que o guardar atravs de um apontador. Assim:
int x = 10; int v = &x; int *p= &x; //errado //correcto

Operaes com apontadores - introduo


Para demonstrar uma introduo s operaes com apontadores segue-se um programa de exemplo:
#include <iostream> using namespace std; int main() { int x = 20; int *pointer; pointer = &x;

//apontador para uma varivel do tipo int //o apontador assume o valor do endereo da varivel

cout << "Variavel x:" << endl; cout << "\nValor de x: " << x << endl; cout << "Endereco de x: " << &x << endl; cout cout cout cout << << << << "\n\nVariavel pointer:" << endl; "\nValor de pointer: " << pointer << endl; "Endereco de pointer: " << &pointer << endl; "Valor da variavel apontada por pointer (x): " << *pointer << endl;

cin.get(); return 0; }

Exemplo 11.4 - Obter as propriedades da memria de uma varivel e de um apontador No se assustem para j com a quantidade de coisas que ainda no sabem! Ao correr o programa deu-me o seguinte output (que ser diferente dos vossos, uma vez que o endereo no vai ser o mesmo): Output Variavel x: Valor de x: 20 Endereco de x: 0x22ff74 Variavel pointer: Valor de pointer: 0x22ff74 Endereco de pointer: 0x22ff70 Valor da variavel apontada por pointer (x): 20

http://agnor.gamedev-pt.net/gamedev/cpp.html Para melhor compreenderem melhor "desmontarmos" o programa : Varivel X: Valor: 20 Endereo: 0x22ff74 (neste caso) Valor
Endereo

20
0x22ff74

-0x22ff75

-...

Varivel pointer (o apontador para a varivel x): Valor: 0x22ff74 (o valor de um apontador , ento, o endereo da varivel por ele apontada) Endereo: 0x22ff70 (o endereo de pointer. Reparem que est 4 "posies" antes do que X; isto acontece porque um int ocupa 4 bytes) Valor da varivel apontada por pointer (x): 20 Valor
Endereo

0x22ff74
0x22ff70

...
...

20
0x22ff74

Como vm importante testarmos os exemplos por ns mesmos, alterando os valores e experimentando coisas novas, pois com os erros que aprendemos.

Operaes com apontadores - operaes com o valor


H dois tipos de operaes com apontadores. Nesta lio vou s dar as operaes com o valor, visto que o mais fcil de aprender (e porque isto j vai muito longo :). De modo a "mexermos" com o valor da varivel apontada pelo apontador temos que utilizar o operador desreferncia (*):
#include <iostream> using namespace std; int main() { int x = 10; int *pointer = &x; cout << "Valor de X: " << x << endl; cout << "Valor apontado por pointer: " << *pointer << endl; x += 10; cout << "\nValor de X: " << x << endl; cout << "Valor apontado por pointer: " << *pointer << endl; *pointer += 10; cout << "\nValor de X: " << x << endl; cout << "Valor apontado por pointer: " << *pointer << endl; ++*pointer; //ou ++(*pointer) se quiserem cout << "\nValor de X: " << x << endl; cout << "Valor apontado por pointer: " << *pointer << endl; cin.get();

http://agnor.gamedev-pt.net/gamedev/cpp.html
} return 0;

Exemplo 11.5 - Operaes bsicas com o valor das variveis apontadas pelos apontadores Nunca se esqueam de usar o operador desreferncia sempre que quiserem trabalhar com o valor. Muitos dos erros que assombram os programadores atravs de mau uso de apontadores, por isso, tenham muito, mas muito cuidado :) . Vejamos agora como ficaria a funo swap com apontadores:
#include <iostream> using namespace std; // Funo Swap -> uso de apontadores // Desc: troca os valores de 2 variveis inteiras void swap(int *x, int *y); //passamos os argumentos como apontadores int main() { int a = 20; int b = 10; cout << "A:" << a << endl; cout << "B:" << b << endl; swap(&a, &b); /* no se esqueam que estamos a utilizar apontadores, logo temos que utilizar o operador endereo de para atribuir o endereo das variveis aos apontadores */ cout << "\n\nA:" << a << endl; cout << "B:" << b << endl; cin.get(); return 0;

void swap(int *x, int *y) { int temp; //varivel temporria, para no perdermos o valor do x temp = *x; //temp igual ao valor da varivel apontada por x *x = *y; //valor da varivel apontada por x vai ser igual ao valor da //varivel apontada por y *y = temp; //valor da varivel apontada por y vai ser igual ao valor de temp }

Exemplo 11.6 - Funo Swap (usando apontadores)

Para qu isto tudo?


Se leram isto tudo devem estar a perguntar-se para que que servem realmente os apontadores, pois existem referncias que, alm de serem muito mais fceis de usar e de compreender, tm exactamente o mesmo efeito. No vos culpo. H vrias razes: 1 - As referncias so uma evoluo do uso dos apontadores. Em C referncias no existiam era tudo feito atravs de apontadores (at aqui vocs continuam com razo...)

http://agnor.gamedev-pt.net/gamedev/cpp.html 2 - A verdadeira utilidade dos apontadores em C++ (e acreditem que so mesmo teis) est com a memria dinmica e com as operaes com o endereo, algo que optei no dar nesta lio (por falta de espao e porque exige mais conhecimentos). 3 - Ficaram com uma excelente introduo aos apontadores. Estes conhecimentos de memria e apontadores vo ser muito importantes para compreenderem a 100% o uso de apontadores Final da aula 11 de C++: Prxima aula -> C++ 12 - Tratamento de Caracteres Fazer o download do cdigo fonte dos exemplos da aula Fazer o download da aula em PDF (Brevemente) Ir para o topo da pgina

Aula 12 - Tratamento de caracteres


<!-google_ad_client = "pub-9639791948153775"; google_ad_width = 336; google_ad_height = 280; google_ad_format = "336x280_as"; google_ad_type = "text"; google_ad_channel ="3703014365"; google_color_border = "FFFFFF"; google_color_bg = "FFFFFF"; google_color_link = "0000FF"; google_color_url = "000000"; google_color_text = "000000"; //-->Conceitos-Chave: - caracter, um "smbolo" (pode ser uma letra, sinais de pontuao, etc) do tipo char - string, conjunto de caracteres (uma palavra ou uma frase, por exemplo) - arrays de caracteres, um conjunto de caracteres, logo uma string - apontadores para strings, apontam para conjuntos de caracteres, no sendo preciso dimensionar o apontador - classe string, biblioteca standard do C++, que tem o objectivo de ajudar na manipulao de strings

Tratamento de caracteres em C
Desde a entrada de C++ que se comeou a utilizar a classe string para o tratamento de caracteres. No entanto, como ainda muitos programadores utilizam arrays de caracteres (era o que havia em C) achei importante ensinar pelo menos o bsico. Em C uma string pode ser definida atravs de um array de caracteres (tipo char), o que lgico, uma vez que uma string um conjunto de caracteres. J dei uma introduo sobre isto na lio 7, por isso acho melhor darem uma olhadela antes para reverem como definir um array de caracteres. Como qualquer array poderemos alterar como quisermos os valores presentes.
#include <iostream> using namespace std;

http://agnor.gamedev-pt.net/gamedev/cpp.html
int main() { char nome[10] = "agnor"; necessrios cout << nome << endl; cin.get(); //vou mudar o nome para comear com letra maiscula nome[0] = 'A'; //altera o primeiro carcter (n 0) com a letra A

//comea com 10 caracteres pois sero //mais frente

cout << nome << endl; cin.get(); //vou mudar acrescentar um s HQ no fim do nome nome[5] nome[6] nome[7] nome[8] = = = = 's'; ' '; 'H'; 'Q'; //espao

cout << nome << endl; cin.get(); return 0; }

Exemplo 12.1 - Alterar caracteres num array de caracteres Embora nos d um maior grau de controlo, torna-se pouco vivel utilizar arrays de caracteres para strings que sejam alteradas constantemente. Isso pode ser solucionado se utilizarmos apontadores para caracteres:
#include <iostream> using namespace std; int main() { char *nome = "agnor"; cout << nome << endl; cin.get(); nome = "Agnor"; cout << nome << endl; cin.get(); nome = "Agnor's HQ"; cout << nome << endl; cin.get(); return 0; }

http://agnor.gamedev-pt.net/gamedev/cpp.html

Exemplo 12.2 - Usar apontadores para strings Os apontadores para caracteres tornam muito mais fcil esta tarefa. Como se trata de um apontador no podemos manipular a string de origem, logo temos um menor grau de controlo, uma vez que no podemos alterar apenas uma letra, temos que alterar a string toda. O apontador nome est a apontar para um local na memria que contm a string que criamos, "Agnor".

Iniciar uma string sem definirmos um valor


Para iniciar uma string no temos que, necessariamente, atribuir-lhe logo um valor. Porm temos que definir o nmero de caracteres que a string possui: char string[50]; string = "Agnor"; Podemos tambm usar apontadores para caracteres facilmente: char* string; string = "Agnor"

Exemplo 12.3 - Inverter os caracteres de uma palavra


#include <iostream> using namespace std; int main() { char string[8] = "exemplo"; char dest[8]; //cria uma varivel com o mesmo numero de caracteres de string for (int j = 0; j < 7; j++) { dest[j] = string[6-j]; //copia os valores de string para dest inversamente } dest[7] = '\0'; //no esquecer de colocar o terminador cout << "String inicial: " << string << endl; cout << "String invertida: " << dest << endl; cin.get(); } return 0;

Exemplo 12.3 - Inverter os caracteres de uma palavra As primeiras linhas de cdigo so fceis de entender. Criamos uma string inicial (string) e uma string que vai ser a invertida (dest). Ambos tm, obviamente, o mesmo n de caracteres (no esquecer o caracter terminador). Depois criamos uma condio for em que string vai ser copiado inversamente:

http://agnor.gamedev-pt.net/gamedev/cpp.html Programa: dest[0] = string[6] //caracter 'o' dest[1] = string[5] //caracter 'l' dest[2] = string[4] //caracter 'p' dest[3] = string[3] //caracter 'm' dest[4] = string[2] //caracter 'e' dest[5] = string[1] //caracter 'x' dest[6] = string[0] //caracter 'e' Depois inserimos o caracter terminador (\0) no fim do array e mostramos no ecr o resultado. Simples! Agora decidi complicar um bocado para podermos ter um controlo muito maior no programa:
#include <iostream> using namespace std; int main() { char string[] = "exemplo"; int n = sizeof(string) - 1; //n o n de caracteres da variavel string, //excluindo o caracter terminador \0 char dest[n+1]; //cria uma varivel com o mesmo numero de caracteres de string for (int j = 0; j < n; j++) { dest[j] = string[n-j-1]; inversamente } dest[n] = '\0'; //no esquecer de colocar o terminador cout << "String inicial: " << string << endl; cout << "String invertida: " << dest << endl; cin.get(); } return 0;

//copia os valores de string para dest //sem copiar o caracter terminador, obviamente

Exemplo 12.4 - Inverter os caracteres de uma palavra (verso 2.0) Basicamente todos os principios foram explicados no programa anterior a este. Vou s explicar a funo sizeof. Basicamente a funo sizeof diz-nos o nmero de bytes ocupados por uma varivel. Se fizessemos sizeof(n) o resultado seria 4 (o tipo int ocupa 4 bytes). Como cada char ocupa 1 byte e temos um array com 8 variveis do tipo char (uma para cada caracter + uma para o caracter terminador) ocupar 8 bytes. Com este programa j poderemos alterar vontade a string inicial sem ser necessrio modificar mais alguma coisa no programa.

http://agnor.gamedev-pt.net/gamedev/cpp.html

Strings em C++
Como C++ uma evoluo do C, natural que o C++ tenha uma forma mais fcil de manipular strings. Em C (como podemos observar acima) manipular strings d algum trabalho ao programador (tendo mesmo que criar algumas funes para o ajudar). Em C++ foi criada uma classe que facilita a vida do programador: a classe string.

Classe String
Para podermos aceder classe string temos que, primeiro, inclu-la no programa, do mesmo modo que inclumos a classe iostream: #include <string> Outra coisa importante, o que esta classe faz dar ao programador uma forma simples e poderosa de manipular strings, sem estar a "sujar as mos" em cdigo desnecessrio. Vejam o seguinte programa:
#include <iostream> #include <string> using namespace std; int main() { string String1;

//iniciamos uma string sem atribuirmos um valor //notem que no temos que atribuir nenhum tamanho //temos que

string String2("Bem Vindo ao mundo das Strings em C++"); iniciar

//as strings desta forma string String3("Agnor's HQ"); string String4(String3); //podemos iniciar facilmente uma string com outra string cout << "String2: " << String2 << endl; cout << "String3: " << String3 << endl; cout << "String4: " << String4 << endl; String1 = String3; String3 = String2; cout cout cout cout << << << << "\nString1: "String2: " "String3: " "String4: " //olhem! Nem preciso redemensionar o array... // tudo feito pela classe string " << String1 << endl; << String2 << endl; << String3 << endl; << String4 << endl;

cin.get(); return 0; }

Exemplo 12.5 - Usando a classe string Pode parecer um pouco confuso as diferentes formas de inicializao e, por isso, no quero entrar em mais detalhe na classe String, sem falar antes em classes (prxima aula).

http://agnor.gamedev-pt.net/gamedev/cpp.html Para acabar vou s mostrar que podemos aceder a apenas um caracter (que exactamente a mesma coisa que em C) com um programa que mostra cada letra de uma string:
#include <iostream> #include <string> using namespace std; int main() { string String("Agnor"); for (int j = 0; j < 5; j++) //mostra cada letra sequencialmente { cout << j+1 << "a letra: " << String[j] << endl; } cin.get(); return 0;

Exemplo 12.6 - Mostrar uma letra de cada vez com a classe string

Exemplo final - Jogo ADIVINHA A PALAVRA


O seguinte jogo baseado no da Forca. O jogador tem tentativas ilimitadas para acertar na palavra escolhida pelo jogador. Contm algumas coisas que ainda no devero perceber ( string.size() e string.replace(), por exemplo), mas que sero abordadas mais frente. Fiquem com o jogo:
/******************************** Jogo: Adivinhar a palavra Autor: Joo Portela a.k.a. Agnor http://agnor.gamedev-pt.net/ *********************************/ // Includes do programa #include <iostream> #include <windows.h> #include <string> using namespace std; // Declarao de funes //Desc: retorna o nmero de caracteres numa string //Exemplo: int x = tamanho("ola"); int tamanho(string str); //Desc: verifica se a letra que est na posio index das duas strings so iguais //Exemplo: bool teste = verificarLetra("mesa", "casa", 2); bool verificarLetra(string tentativa, string source, int index); //Desc: verifica se as duas strings so iguais //Exemplo: bool teste = verificarPalavra("mesa", "casa"); bool verificarPalavra(string tentativa, string source); //Desc: Retorna um nmero aleatrio, entre [de] e [ate] //Exemplo: int x = getRandom(0, 3);

http://agnor.gamedev-pt.net/gamedev/cpp.html
int getRandom(int de, int ate); //Desc: Mostra o menu de jogo e retorna a opo escolhida //Exemplo: int opcao = menu(); int menu(); //Desc: mostra a mensagem de vencedor //Exemplo: venceu(); void venceu(); //Desc: A lgica do jogo em si. Source a string que contm // a palavra "vencedora" e descobertas a string que diz // quais letras esto certas. Retorna true, se o jogador // acertou na string (source) //Exemplo: bool ganhou = logica_jogo("gato", descobertas); bool logica_jogo(string source, string &descobertas); //Desc: cria um novo jogo //Exemplo: novo_jogo(); void novo_jogo(); int main() { bool done = false; while (!done) //inicia um ciclo de jogo. S sai dele quando done for igual a true { cout << "Bem vindo ao jogo: ADIVINHA A PALAVRA" << endl; cout << "Este jogo e uma modificacao do jogo da Forca" << endl; cout << "Criado por Joao Portela aka Agnor" << endl; cout << "http:////agnor.gamedev-pt.net//" << endl; int escolha_menu = menu(); escolhido pelo utilizador switch (escolha_menu) { case 1: novo_jogo(); break; case 2: done = true; } } cout << "Obrigado por jogar este jogo." << endl; cin.get(); return 0; //escolha_menu vai assumir o //valor

//inicia-se um novo jogo

//sai do ciclo de jogo

// Definio de Funes int tamanho(string str) { return (int)str.size(); (explicarei mais tarde)

//retorna o n de caracteres de uma string

http://agnor.gamedev-pt.net/gamedev/cpp.html
} bool verificarLetra(string tentativa, string source, int index) { if (tentativa[index] == source[index]) //se as letra forem iguais, no mesmo index... { return true; //ao fazer return, sai da funo } } return false;

bool verificarPalavra(string tentativa, string source) { if (tentativa == source) //se as strings forem iguais... { return true; } return false; } int getRandom(int de, int ate) { int random; ate -= de; random = rand() % (ate + 1) + de; return random; } int menu() { int escolha; cout << "Escolha uma opcao: " << endl; cout << "\n1 - Novo Jogo" << endl; cout << "2 - Sair\n" << endl; cin >> escolha; } return escolha;

void venceu() { cout << "\nParabens! Venceu o jogo!\n" << endl; cin.get(); cin.get(); } bool logica_jogo(string source, string &descobertas) { string tentativa; cout << "\n\nA palavra escolhida pelo jogo tem " << tamanho(source) << " letras" << endl; cout << "Letras ja descobertas: " << descobertas << endl; cout << "\nInsira a sua tentativa: ";

http://agnor.gamedev-pt.net/gamedev/cpp.html
cin >> tentativa; if (tamanho(source) != tamanho(tentativa)) //s para assegurar que tm o mesmo n de caracteres { cout << "\nNao tem o mesmo numero de letras!" << endl; cin.get(); return false; } if (verificarPalavra(tentativa, source)) { return true; } else { for (int i = 0; i < tamanho(source); i++) //percorre todas as letras da string { if (verificarLetra(tentativa, source, i)) //se as letras forem iguais { descobertas[i] = source[i]; //iguala as descobertas } else { descobertas[i] = '-'; //pois ainda no foi descoberto } } } return false; } void novo_jogo() { srand(GetTickCount()); string source[10]; palavras source[0] source[1] source[2] source[3] source[4] source[5] source[6] source[7] source[8] source[9] = = = = = = = = = = //cria um array de strings, uma especie de coleco de //esse caracter fica com o valor '-',

"casa"; //algumas palavras... "mesa"; "rato"; "manteiga"; "luar"; "tecla"; "manto"; "canto"; "rio"; "escola";

string descobertas; //os caracteres que foram descobertos pelo utilizador

http://agnor.gamedev-pt.net/gamedev/cpp.html
int indice = getRandom(0,9); acima //escolhe a posio da palavra na lista

for (int x = 0; x < tamanho(source[indice]); x++) { descobertas.resize(tamanho(source[indice])); //faz com que descobertas fique com o mesmo tamanho de source, para o caso de haver //para podermos alterar os caracteres em baixo (ser explicado depois) descobertas[x] = '-'; (no descobertas) } bool vencer = false; while (!vencer) //enquanto no vencer... { vencer = logica_jogo(source[indice], descobertas); } } venceu(); //mostra a mensagem de vencedor //pe todas as letras com o smbolo '-'

Exemplo 12.7 - Jogo ADIVINHA A PALAVRA H alguns conceitos que no usei assim to frequentemente ao longo das lies:

bool logica_jogo(string source, string &descobertas);


Nos argumentos da funo usmos uma referncia para uma string, para podermos no s aceder ao valor de descobertas, mas tambm para o poder alterar. Assim evitamos o uso de uma varivel global.

return (int)str.size();
Esta exige uma maior dose de explicao. Pensem que str um objecto qualquer (neste caso uma palavra). Ao usarmos o '.' (ponto), estamos a aceder aos atributos desse objecto. Assim, estamos a aceder ao atributo size() do objecto string. Este um dos conceitos de Programao Orientada a Objectos, que iremos dar na prxima aula. Basta saberem que isto faz com que obtenhamos o nmero de caracteres de uma string. Outra coisa tambm nos prende a ateno, o (int): A funo size() (a que est dentro do objecto str) retorna um valor do tipo size_t, um valor que os standards de C++ definem como sendo um valor prprio para o tamanho (n de caracteres) de strings. Na verdade, o "corao" desse tipo de variveis um unsigned int, ou seja um inteiro com nmeros s positivos. Como s apresenta nmeros positivos, tem o dobro da capacidade de um int normal. Como tal, se tentarmos converter um size_t para um int, o compilador dar-nos- um aviso: "Possvel perda de dados". Isto porque, se o nmero de caracteres for na ordem dos bilies, o tipo int poder no suport-lo. Mas como sabemos que isso impossvel (nenhuma string que iremos

http://agnor.gamedev-pt.net/gamedev/cpp.html fazer ter esse nmero de caracteres), ao usarmos (int) a nossa maneira de dizermos ao compilador que no nos importamos que o size_t seja convertido para int, e o compilador j no nos vai chatear.

descobertas.resize(tamanho(source[indice]));
Dentro do objecto descobertas temos uma funo chamada resize, que tem a funo de preparar a string para um determinado nmero de caracteres. As string podem parecer "mgicas", mas fazer o seguinte cdigo seria errado: string str = "ola"; //trs caracteres str[3] = 'b'; //errado, pois s h 3 caracteres na string! E a forma correcta: string str = "ola"; //trs caracteres str.resize(4); str[3] = 'b';

Uso de plicas ' em vez de aspas "


Provavelmente repararam que usei '-' em vez de "-". Isto porque ao utilizarmos "-" estamos a definir uma string inteira, no s um caracter. Fazer char p = "a"; daria erro. A forma correcta, quando queremos utilizar apenas um caracter, char p = 'a'; Final da aula 12 de C++: Prxima aula -> C++ 13 - Classes - Parte I Fazer o download do cdigo fonte dos exemplos da aula Fazer o download da aula em PDF (Brevemente) Ir para o topo da pgina

Aula 13 - Classes - Parte I


<!-google_ad_client = "pub-9639791948153775"; google_ad_width = 336; google_ad_height = 280; google_ad_format = "336x280_as"; google_ad_type = "text"; google_ad_channel ="3703014365"; google_color_border = "FFFFFF"; google_color_bg = "FFFFFF"; google_color_link = "0000FF"; google_color_url = "000000"; google_color_text = "000000"; //-->Conceitos-Chave: - programao procedimental, estilo de programao baseado em passos/etapas, como se tratasse de um livro de receitas - programao orientada a objectos, estilo de programao onde o programador cria objectos, abstraindo-se do cdigo, baseando-se em exemplos da vida real. Cada objecto pode (e deve) interagir entre si. - classe e objecto, um objecto pertence a uma determinada classe. No exemplo, Cadeira

http://agnor.gamedev-pt.net/gamedev/cpp.html cadeira_do_escritorio;, Cadeira seria a classe e cadeira_do_escritorio o objecto. - Acessibilidade, apontam para conjuntos de caracteres, no sendo preciso dimensionar o apontador

Paradigmas de programao
At agora temos programado usando um estilo de programao procedimental, ou seja, um estilo de programao que utiliza vrias funes (vrios passos ou instrues) para serem executadas. Por exemplo: 1 - Pegar no telefone; 2 - Marcar o n; 3 - Esperar por alguma actividade do telefone; 3.1 - Se algum atender salta para o passo 4; 3.2 - Se o sinal estiver interrompido desligue o telefone, espere 1 minuto e volte ao passo 1; 3.3 - Se no atender desligue o telefone, espere 30 minutos e volte ao passo 1; 4 - Fale e tenha uma agradvel conversa; 5 - Desligue o telefone; Em C++ este cdigo (recorrendo a funes e ao paradigma procedimental) poderia ficar assim:
ligarTelefone(telefone_de_casa); marcarNumero(telefone_de_casa, numero); int sinal = sinal_do_telefone(); while(sinal == 0) { esperar(tempo_de_espera); } while (sinal != 1) { case 2: //.... } falar(); desligar_telefone(telefone_de_casa);

Um dos pontos mais fracos da linguagem C (a linguagem antecessora ao C++) foi o de no suportar a chamada Programao Orientada a Objectos (OOP - Object Oriented Programming). A linguagem C++, para alm de suportar o paradigma OOP e o procedimental, suporta outros dois (Abstract Data Type e Generic Programming). Isto uma enorme vantagem, uma vez que poderemos escolher entre programar de 4 maneiras diferentes! At agora tenho vos ensinado programao procedimental, mas a partir de agora melhor habituarem-se Programao Orientada a Objectos, uma vez que o paradigma que "est na moda" (as linguagens da nova gerao como Java e C# "obrigam" o programador a utiliz-la). Depois desta "chuva" de termos tcnicos vamos ento Programao Orientada a Objectos.

Programao Orientada a Objectos (OOP) - Introduo


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

http://agnor.gamedev-pt.net/gamedev/cpp.html Imaginemos um objecto, por exemplo, um ser humano (objecto no nesse sentido). Antes de mais, um ser humano constitudo por vrios orgos. Tem uma boca, um nariz, dois olhos, etc. Um ser humano um mamfero. Isso significa que partilha vrias caractersticas com todos os mamferos, por exemplo, possui corao, coluna vertebral, plo, alm de possuir as mesmas funes bsicas: acasalar, alimentar-se, dormir, etc. Alm disso, um ser humano tem vrias funes, como a de falar, ler, escrever, etc. Poderemos ento construir o seguinte diagrama:

Nota: O diagrama acima est desenhado seguindo a "linguagem" UML (Unified Modelling Language). Trata-se de uma "linguagem" para expr a relao entre as classes de um programa e fundamental quando estamos a planear o cdigo para um projecto grande (um jogo, por exemplo) e quando estamos a trabalhar numa equipa com mais programadores. Por agora, como os programas que iremos fazer sero muito simples, no necessrio estarmos a plane-lo atravs de diagramas. Talvez entre em mais pormenores sobre esta linguagem em futuras aulas. Bem, agora que aprendemos o conceito da programao orientada a objectos vamos ver o seu uso num programa real.

Classes
Na lio n 9 expliquei como se usavam estruturas (struct). As classes so uma evoluo das estruturas (s tm uma diferena significativa), em C usava-se estruturas, em C++, devido introduo do paradigma OOP, usam-se classes. Ento porque ensinei primeiro estruturas? Em primeiro lugar porque usar estruturas um pouco mais fcil para novatos. Segundo, porque ainda h muitos programadores que utilizam classes e estruturas no mesmo programa (eu inclusiv), por isso j esto preparados para tudo.

http://agnor.gamedev-pt.net/gamedev/cpp.html Nota: A verdade que as estruturas nem deveriam existir em C++. S existem para manter a compatibilidade com a linguagem C. As classes definem-se atravs da palavra chave class e seguem praticamente as mesmas normas que as estruturas. Um exemplo de uma classe simples :
class Ponto { int x, y; };

muito parecido com uma estrutura, mas diferente de:


struct Ponto { int x, y; };

Ento onde est a diferena?

Acessibilidade
A diferena entre classes e estruturas est na sua acessibilidade. Numa classe (ou numa estrutura) os membros podem ser declarados como pblicos ou privados. Os membros privados (private) s podem ser acedidos pela prpria classe. Os membros pblicos (public) tanto podem ser acedidos pela classe como fora dela. A acessibilidade predefinida de uma estrutura pblica. Assim, no exemplo acima, as variveis x e y tanto podem ser manipulados dentro como fora da estrutura. A acessibilidade predefinida de uma classe privada. Assim, tambm no exemplo acima, as variveis x e y podem ser manipuladas apenas dentro da classe. Parece confuso? Um simples exemplo pode esclarecer as dvidas:
class Ponto { public: int x, y; //membros publicos private: int a, b; //membros privados };

Que tambm pode ser definido por:


class Ponto { int a, b; //membros privados public: int x, y; //membros publicos };

http://agnor.gamedev-pt.net/gamedev/cpp.html Nota: Em C++ ainda h outro tipo de acesso, chamado protegido (protected), mas no precisam de se preocupar com ele por agora.

Mtodos
Mtodos so como funes, que esto contidos dentro de uma classe. Por exemplo, imaginem uma classe Ponto (classe que trabalha com as coordenadas cartesianas, x e y, de um ponto):
class Ponto { public: void alterarX(int u_x); //altera o valor de x void alterarY(int u_y); //altera o valor de y void alterar(int u_x, int u_y); //altera o valor de x e de y int mostrarX(); //devolve o valor de x int mostrarY(); //devolve o valor de y private: int x, y; }; //coordenadas do ponto

Nota: Dei o nome de u_x e u_y aos atributos das funes para no entrarem em conflito com as variveis privadas x e y. As funes acima (mtodos) fazem parte da classe. Notem que apesar das variveis x e y serem privadas podem ser acedidas pelos mtodos da prpria classe. Notem tambm que apenas declaramos os mtodos, ainda no os definimos. Para poder defini-los h duas maneiras. A primeira defini-los na definio da classe:
class Ponto { public: void alterarX(int u_x) { x = u_x; } void alterarY(int u_y) { y = u_y; } void alterar(int u_x, int u_y) { x = u_x; y = u_y; } int mostrarX() { return x; } int mostrarY() { return y; } private: int x, y; }; //coordenadas do ponto

Esta maneira bastante fcil, mas desaconselhada para funes maiores. A segunda maneira defini-los fora da definio da classe. No exemplo seguinte vou s definir fora da classe o mtodo

http://agnor.gamedev-pt.net/gamedev/cpp.html alterar().
class Ponto { public: void alterarX(int u_x) { x = u_x; } void alterarY(int u_y) { y = u_y; } void alterar(int u_x, int u_y); int mostrarX() { return x; } int mostrarY() { return y; } private: int x, y; }; void Ponto::alterar(int u_x, int u_y) { x = u_x; y = u_y; } //coordenadas do ponto

Como podem ver semelhante a definir uma funo normal, com uma nica diferena: a incluso do Ponto::. Esta instruo serve para informar o compilador que o mtodo seguinte pertence classe Ponto. O operador '::' o operador resoluo de alcance. Serve para dizermos ao compilador que queremos aceder funo (mtodo) "alterar()", que est dentro da classe "Ponto": Ponto::alterar()

Classes vs Objectos
Neste ponto algo importante conhecer a distino entre classe e objecto. No exemplo abaixo: Carro Seat; Carro seria a classe e Seat seria o objecto. Se os compararmos a uma varivel, uma classe seria o tipo de dados (int, char, etc.) e um objecto seria a varivel em si.

Aceder aos membros de classes


Podemos aceder aos membros de um objecto da mesma forma que acedemos s estruturas. Por exemplo, ponto.x = 3; cout << ponto.getX();

Exemplo final e Questes de Acessibilidade


Para acabar esta parte, um programa de exemplo com a "matria" toda.
#include <iostream> using namespace std; class Ponto { public: void alterarX(int u_x) { x = u_x; } void alterarY(int u_y) { y = u_y; }

http://agnor.gamedev-pt.net/gamedev/cpp.html
void alterar(int u_x, int u_y); int mostrarX() { return x; } int mostrarY() { return y; } private: }; int x, y; //coordenadas do ponto

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

//declaramos um objecto point da classe Ponto

//como fazer point.x ou point.y daria erro (privado).... point.alterar(3, 2); //mostrar os pontos: cout << "X: " << point.mostrarX() << "\nY: " << point.mostrarY() << endl; point.alterarX(7); //mostrar os pontos: cout << "\nX: " << point.mostrarX() << "\nY: " << point.mostrarY() << endl; cin.get(); return 0;

Exemplo 13.1 - Classe Ponto Facilmente poderamos adicionar mais mtodos, como o de somar, de incrementar, etc.. Vocs devem estar a pensar no porqu de declararmos as variveis privadas, pois seria muito mais simples fazer point.x do que point.mostrarX(). Podero fazer das duas formas, mas prefervel declarar as varaveis de forma privada e usar uma funo para a alterar e outra para obter o seu valor. Isto porque, se no futuro quiserem expandir as funcionalidades da vossa classe, torna-se muito mais fcil. Imaginem uma classe ms. Fazer: mes.dia = 50; Seria um erro, obviamente, mas ao criarmos um mtodo: mes.alterarDia(50); Poderiamos assegurar - dentro do mtodo - que a varivel seria menor que 31 (if (dia < 31)...). Assim no tnhamos que alterar cdigo nenhum (no tinhamos de todos os mes.dia dentro da funo main()), apenas algumas linhas dentro do mtodo alterarDia(). Final da aula 13 de C++:

http://agnor.gamedev-pt.net/gamedev/cpp.html Prxima aula -> C++ 14 - Apontadores - Parte II Fazer o download do cdigo fonte dos exemplos da aula Fazer o download da aula em PDF (Brevemente) Ir para o topo da pgina

Aula 14 - Apontadores - Parte II


<!-google_ad_client = "pub-9639791948153775"; google_ad_width = 336; google_ad_height = 280; google_ad_format = "336x280_as"; google_ad_type = "text"; google_ad_channel ="3703014365"; google_color_border = "FFFFFF"; google_color_bg = "FFFFFF"; google_color_link = "0000FF"; google_color_url = "000000"; google_color_text = "000000"; //-->Conceitos-Chave: - varivel alocada dinamicamente, varivel que est alocada na memria dinmica, cujo tamanho pode ser alterada - new, cria uma varivel na memria dinmica e retorna um apontador para a mesma - delete, desaloja da memria dinmica a varivel dinmica apontada - operaes com endereo, possvel aceder varivel seguinte, muito til para arrays

Memria dinmica
At agora temos alojado as variveis e arrays estaticamente. Isto significa que quando inicializmos uma varivel, esta ir possuir sempre o mesmo tamanho ao longo do programa. Numa varivel normal, no h qualquer problema, mas num array isto traz limitaes. A primeira que temos de conhecer o tamanho do array antes de comear o programa. Outra que no podemos alterar o tamanho do array, consoante as nossas necessidades. Uma soluo para o primeiro problema especificar um valor mximo para o array. No entanto, estaremos a gastar espao na memria desnecessariamente e nada nos d garantia que o espao ser suficiente (se tal no for, preparem-se para erros constantes durante a execuo). A nica alternativa vivel aloj-los dinamicamente. Uma varivel dinmica s pode ser acedida atravs de um apontador, ou seja, ao criarmos uma varivel dinmica, no podemos ter acesso directo mesma, apenas atravs de um apontador. Para alojarmos uma varivel dinamicamente, teremos que usar o operador new: int *apont = new int; Para perceberem o que est a acontecer no exemplo acima, vejam o seguinte esquema: Esquema: 1 - Declaramos um apontador para um inteiro (int *apont)

http://agnor.gamedev-pt.net/gamedev/cpp.html 2 - Criamos um inteiro na memria dinmica (atravs do operador new). Notem que o inteiro que criamos no tem um "nome" (identificador o termo mais correcto). Para podermos aceder ao inteiro criado na memria dinmica temos, ento, que utilizar um apontador (neste caso o apontador "apont"). Poderemos depois alterar o valor do inteiro criado como num apontador normal: *apont = 20; No se esqueam que estamos a afectar o valor apontado pelo apontador (uma boa maneira de ler "valor apontado por apont ser igual a 20") Poderemos tambm definir um valor ao criarmos uma varivel na memria dinmica: int *apont = new int(20); Com a criao de memria dinmica temos tambm uma enorme responsabilidade: de libert-la.

Libertar a memria dinmica


Enquanto que a memria esttica libertada automaticamente pelo programa (no precisamos de nos preocupar com ela), a memria dinmica tem de ser libertada pelo programador. Se nos esquecermos de a libertar esta ir persistir sempre. Ir ento utilizar recursos do sistema ou mesmo esgotar toda a memria do sistema. Moral da histria: no se esqueam nunca de libertar a memria aps criarem (quando no precisarem mais dela, claro). Para libertar a memria criada utiliza-se o operador delete. int *apont = new int(20); //fazer alguma coisa.... delete apont; Simples, mas o seu esquecimento a causa de muitos erros graves de programas..... Nota: Ao fazermos delete apont; estaremos a libertar a varivel criada em new int(20); e no o apontador apont. No nos temos de preocupar com ele, uma vez que um apontador criado estaticamente e ser eliminado estaticamente. Dica: bastante aconselhvel que faam apont = NULL; aps o delete apont;. Como expliquei nos exemplos acima, fazer delete apont; apenas limpa a varivel da memria dinmica. O apontador apont vai continuar a apontar para o mesmo endereo de anteriormente. Para evitar que o programador o utilize por engano (aps o termos eliminado), ao fazer apont = NULL; estamos a fazer com que o apontador no aponte para nada, e podemos utilizar uma condio para saber se o apontador existe: if (!apont) //o mesmo que if (apont == NULL) //...

http://agnor.gamedev-pt.net/gamedev/cpp.html

Alojar e libertar arrays dinamicamente


Alojar um array dinamicamente to simples como alojar uma varivel normal: int *array = new int[100]; // aloja um array com 100 ints e para libertar a memria: delete [] array;

Operaes com o endereo


Para ilustrar uma simples operao com o endereno de variveis vejam o exemplo abaixo:
#include <iostream> using namespace std; int x = 20; int y = 10; int *pointer; //apontador para uma varivel do tipo int void printthis(); int main() { pointer = &x; //o apontador assume o valor do endereo da varivel printthis(); cout << "Vai ser incrementado o endereco por um valor, prima ENTER." << endl; cin.get(); pointer++; printthis(); cin.get(); return 0;

void printthis() { cout << "Variavel x:" << endl; cout << "\nValor de x: " << x << endl; cout << "Endereco de x: " << &x << endl; cout << "\n\nVariavel y:" << endl; cout << "\nValor de y: " << y << endl; cout << "Endereco de y: " << &y << endl; cout << "\n\nVariavel pointer:" << endl; cout << "\nValor de pointer: " << pointer << endl; cout << "Endereco de pointer: " << &pointer << endl; cout << "Valor da variavel apontada por pointer (x): " << *pointer << "\n------------\n" << endl; }

http://agnor.gamedev-pt.net/gamedev/cpp.html Exemplo 14.1 - operaes com o endereo Que me d o seguinte output Variavel x: Valor de x: 20 Endereco de x: 0x434000 Variavel y: Valor de y: 10 Endereco de y: 0x434004 Variavel pointer: Valor de pointer: 0x434000 Endereco de pointer: 0x437010 Valor da variavel apontada por pointer (x): 20 -----------Vai ser incrementado o endereco por um valor, prima ENTER. Variavel x: Valor de x: 20 Endereco de x: 0x434000 Variavel y: Valor de y: 10 Endereco de y: 0x434004 Variavel pointer: Valor de pointer: 0x434004 Endereco de pointer: 0x437010 Valor da variavel apontada por pointer (x): 10 Como podem ver ao incrementarmos pointer estamos na verdade a fazer com que pointer tome o endereo da varivel seguinte (4 bytes depois), podendo ento interferir no valor desta. Nota: Este exemplo serviu apenas para explicar uma operao simples com o endereo. O prprio exemplo no muito correcto, pois em situaes reais, nada nos garante que a varivel que est posicionada depois na memria a varivel que pretendemos usar.

Apontadores e arrays
Um apontador equivalente ao endereo do primeiro elemento que aponta. Assim:
#include <iostream> using namespace std;

http://agnor.gamedev-pt.net/gamedev/cpp.html
int array[10]; int *pointer; int main() { pointer = array; array[0] = 50; cout << "array = " << array[0] << endl; cout << "pointer = " << *pointer << endl; cin.get(); return 0;

Exemplo 14.2 - Apontadores vs Arrays (Teste I) Daria o mesmo resultado. Poderemos ento aproveitar isso para aceder aos outros elementos do array. Por exemplo, se quisermos aceder ao elemento n 7:
#include <iostream> using namespace std; int array[10]; int *pointer; int main() { pointer = array; array[7] = 50; cout << "array = " << array[7] << endl; cout << "pointer = " << *(pointer+7) << endl; cin.get(); return 0;

Exemplo 14.3 - Apontadores vs Arrays (Teste II) Na verdade um array uma espcie de apontador. Assim:
#include <iostream> using namespace std; int array[10]; int *pointer; int main() { pointer = array; array[0] = 50; cout << "array = " << *array << endl; cout << "pointer = " << *pointer << endl; cin.get(); return 0;

http://agnor.gamedev-pt.net/gamedev/cpp.html Exemplo 14.4 - Apontadores vs Arrays (Teste III) E tambm:


#include <iostream> using namespace std; int array[10]; int *pointer; int main() { pointer = array; array[7] = 50; cout << "array = " << *(array+7) << endl; cout << "pointer = " << *(pointer+7) << endl; cin.get(); return 0;

Exemplo 14.5 - Apontadores vs Arrays (Teste IV) Na verdade, ao utilizarmos os parenteses rectos ( [] ), estamos a utilizar um operador de desreferncia, chamado offset operator ou em portugus operador de indexao. Assim podemos fazer:
#include <iostream> using namespace std; int main() { int array[2]; int *pointer; pointer = array; array[0] = 0; pointer[1] = 1; for (int i = 0; i < 2; i++) { cout << "Array[" << i << "] = " << array[i] << endl; cout << "Apontador[" << i << "] = " << pointer[i] << endl; } cin.get(); return 0; }

Exemplo 14.6 - Apontadores vs Arrays (Teste V) Ou seja equivalente fazer: array[10] = 15; ou fazer :

http://agnor.gamedev-pt.net/gamedev/cpp.html *(array+10) = 15; Isto torna-se especialmente til para funes. At agora nunca utilizamos arrays como argumentos de funes, vejam como no exemplo seguinte:
#include <iostream> using namespace std; int limpar_array(int *array, int tamanho); int main() { const int TAMANHO = 10; //varivel constante int lista[TAMANHO]; lista[0] = 4; //s para testarmos se o array foi limpo cout << lista[0] << endl; limpar_array(lista, TAMANHO); cout << lista[0] << endl; cin.get(); return 0; } int limpar_array(int *array, int tamanho) { for (int i = 0; i < tamanho; i++) { array[i] = 0; } }

Exemplo 14.7 - Funo limpar array Ento qual a diferena entre um apontador e um array? A diferena principal que o tamanho de um array tem de ser constante, enquanto o tamanho de um apontador (utilizado para memria dinmica) pode variar. Vejam o exemplo seguinte (uma verso aperfeioada do exemplo acima:
#include <iostream> using namespace std; int limpar_array(int *array, int tamanho); int main() { int tamanho; cout << "Insira um tamanho para o array (menor que 1000, e apenas uma sugestao)" << endl; cin >> tamanho; int *lista = new int [tamanho]; lista[0] = 4; //s para testarmos se o array foi limpo

http://agnor.gamedev-pt.net/gamedev/cpp.html
cout << lista[0] << endl; limpar_array(lista, tamanho); cout << lista[0] << endl; cin.get(); cin.get(); return 0; } int limpar_array(int *array, int tamanho) { for (int i = 0; i < tamanho; i++) { array[i] = 0; } }

Exemplo 14.8 - Funo limpar array (verso 1.1) Como podem ver, uma alterao muito pequena trouxe uma grande caracterstica a este programa (embora continue a servir para praticamente nada :) Final da aula 14 de C++: Prxima aula -> C++ 15 - Classes - Parte II Fazer o download do cdigo fonte dos exemplos da aula Fazer o download da aula em PDF (Brevemente) Ir para o topo da pgina

Aula 15 - Classes - Parte II


<!-google_ad_client = "pub-9639791948153775"; google_ad_width = 336; google_ad_height = 280; google_ad_format = "336x280_as"; google_ad_type = "text"; google_ad_channel ="3703014365"; google_color_border = "FFFFFF"; google_color_bg = "FFFFFF"; google_color_link = "0000FF"; google_color_url = "000000"; google_color_text = "000000"; //-->Conceitos-Chave: - construtor, mtodo de uma classe que executado quando o objecto criado - destrutor, mtodo de uma classe que executado quando o objecto destrudo - operator, serve para atribuir operadores a classes - this, um apontador que aponta para o objecto em que est contido

http://agnor.gamedev-pt.net/gamedev/cpp.html

Construtores
Frequentemente um objecto necessita de inicializar algumas variveis ou alojar memria dinmica aquando a sua inicializao. Para tal uma classe pode possuir uma funo para o efeito, o construtor, que ser chamado automaticamente, aquando a iniciao da classe. Por exemplo, imaginemos uma classe Rectangulo:
class Rectangulo { public: //funes bsicas de alterar valores e retorno void mudarX(int a) { x = a; } void mudarY(int a) { y = a; } void mudarAltura(int a) { altura = a; } void mudarLargura(int a) { largura = a; } void mudarValores(int x_, int y_, int alt, int larg); int int int int obterX() { return x; } obterY() { return y; } obterAltura() { return altura; } obterLargura() { return largura; }

//funes de clculo int area() { return largura * altura; } int perimetro() { return (largura * 2) + (altura * 2); } private: int x, y; //coordenadas do canto superior esquerdo do rectangulo int altura, largura; //altura e largura do rectangulo

};

void Rectangulo::mudarValores(int x_, int y_, int alt, int larg) { mudarX(x_); mudarY(y_); mudarAltura(alt); mudarLargura(larg); }

Exemplo 15.1 - Classe Rectangulo A classe perfeitamente funcional, mas ser que no necessita de um construtor? Reparem que para fazermos alguma operao (como saber a area, etc.) temos que ter as variveis definidas. Um construtor assegura que o programador no ir cometer esse erro bsico. Criar um construtor bastante fcil: Nome_da_Classe(); Se a classe se chamar Rectangulo o construtor dever ser: Rectangulo(); Exceptuando o facto de um construtor no retornar nenhum tipo de dados, tratado como uma funo normal. No exemplo acima, da classe Rectangulo, um construtor poderia ser:

http://agnor.gamedev-pt.net/gamedev/cpp.html
class Rectangulo { public: Rectangulo(int x_, int y_, int alt, int larg); //funes bsicas de alterar valores e retorno void mudarX(int a) { x = a; } void mudarY(int a) { y = a; } void mudarAltura(int a) { altura = a; } void mudarLargura(int a) { largura = a; } void mudarValores(int x_, int y_, int alt, int larg); int int int int obterX() { return x; } obterY() { return y; } obterAltura() { return altura; } obterLargura() { return largura; }

//funes de clculo int area() { return largura * altura; } int perimetro() { return (largura * 2) + (altura * 2); } private: int x, y; //coordenadas do canto superior esquerdo do rectangulo int altura, largura; //altura e largura do rectangulo }; Rectangulo::Rectangulo(int x_, int y_, int alt, int larg) { mudarValores(x_, y_, alt, larg); } void Rectangulo::mudarValores(int x_, int y_, int alt, int larg) { mudarX(x_); mudarY(y_); mudarAltura(alt); mudarLargura(larg); }

Exemplo 15.2 - Classe Rectangulo (verso com construtores)

Destrutores
Os destrutores fazem precisamente o contrrio dos construtores. Quando a classe destruda (depende do seu tempo de vida) ir executar o destrutor. Os destrutores so ptimos para desalojar memria dinmica (e assim evitar muitos esquecimentos). Tal como os construtores, os destrutores no retornam nenhum valor e so definidos pelo nome da classe, precedido por um til (~): ~Nome_da_Classe(); Vou s deixar um exemplo fcil:
#include <iostream> using namespace std;

http://agnor.gamedev-pt.net/gamedev/cpp.html
class Teste { public: Teste(); ~Teste(); }; Teste::Teste() { cout << "Iniciou o objecto" << endl; } Teste::~Teste() { cout << "O objecto foi destruido" << endl; } int main() { Teste *t = new Teste;

//tambm podemos iniciar objectos dinmicamente

cin.get(); cout << "Clique ENTER para destruir o objecto." << endl; delete t; cin.get(); return 0; }

Exemplo 15.3 - Testes com Destrutores Utilizei memria dinmica porque podemos destru-la quando quisermos, embora se utilizasse um bloco, teria o mesmo efeito.

Apontadores para classes


Podemos usar apontadores para classes (ou estruturas) da mesma maneira que utilizamos para uma varivel.
Class *teste;

//... (*teste).x = 3; (*teste).y = 1; No entanto, para simplificar mais o cdigo, foi criado um mtodo novo, especificamente para classes ou estruturas:
Class *teste;

//... teste->x = 3; teste->y = 1;

http://agnor.gamedev-pt.net/gamedev/cpp.html

Definindo operadores
Vejamos o seguinte pedao de cdigo:
int x, y, z;

//... z = x + y; No h nada de estranhar neste cdigo: bastante simples e comum. Vejam ento o seguinte:
Classe x, y, z;

//... z = x + y; O cdigo acima daria erro a compilar, mas totalmente legtimo querermos utilizar uma soma se recorrer a mtodos mais complexos. Teremos ento que utilizar a instruo operator na classe:
#include <iostream> using namespace std; class Ponto { public: int x, y; //as variaveis so pblicas para poupar trabalho

};

Ponto operator + (Ponto classe) //reparem: operator + { Ponto temp; //vamos retornar uma classe temporria... temp.x = x + classe.x; temp.y = y + classe.y; return temp; }

int main() { Ponto a, b, c; a.x = 10; a.y = 5; b.x = 10; b.y = 15; c = a + b; //se tudo correr bem, c.x 20 e c.y tambm 20

cout << "C.x = " << c.x << " e C.y = " << c.y << endl; cin.get(); return 0; }

Exemplo 15.4 - Classe Ponto (operator +)

http://agnor.gamedev-pt.net/gamedev/cpp.html Neste exemplo utilizamos a funo operator junto com o operador +, que trata da adio (operator +). H vrios operadores que se podem usar em conjunto com a instruo operator. Entre eles temos: +, -, *, /, [], new, delete, %, etc, e usariamo-los da mesma forma, por exemplo: Ponto operator - () ou Ponto operator new () ou Ponto operator [] ()

Apontador this
O apontador this um apontador muito especial, que representa o objecto em si. Vejam o exemplo seguinte:
#include <iostream> using namespace std; class Ponto { public: int x, y; //as variaveis so pblicas para poupar trabalho

};

Ponto& operator = (const Ponto classe) //funo para igualar objectos { x = classe.x; y = classe.y; return *this; //ao fazermos return *this estaremos a retornar //o prprio objecto, logo no precisamos de criar //um objecto temporrio }

int main() { Ponto a, b; a.x = 10; a.y = 5; b = a; cout << "A:\n\nX = " << a.x << "\nY = " << a.y << endl; cout << "\nB:\n\nX = " << b.x << "\nY = " << b.y << endl; cin.get(); return 0;

Exemplo 15.5 - Classe Ponto (operator =) A nica confuso que podero sentir na expresso Ponto& operator.... S precisam de saber que, quando precisarem de retornar o apontador this, tero que colocar o & frente do tipo da funo (ou seja, o nome da classe). H ainda outro uso (muito til) para o apontador this. Nos exemplos acima temos, muitas vezes, utilizado alguns nomes de variveis (x_ por exemplo) para evitar conflitos com os nomes de variveis que esto dentro da classe. Podemos resolver este problema atravs do apontador this:

http://agnor.gamedev-pt.net/gamedev/cpp.html
class Rectangulo { public: Rectangulo(int x, int y, int alt, int larg); //funes bsicas de alterar valores e retorno void mudarX(int x) { this->x = x; } //notem! o x do objecto ser igual //ao x da funo void mudarY(int y) { this->y = y; } void mudarAltura(int altura) { this->altura = altura; } void mudarLargura(int largura) { this->largura = largura; } void mudarValores(int x, int y, int alt, int larg); int int int int obterX() { return x; } obterY() { return y; } obterAltura() { return altura; } obterLargura() { return largura; }

//funes de clculo int area() { return largura * altura; } int perimetro() { return (largura * 2) + (altura * 2); } private: int x, y; //coordenadas do canto superior esquerdo do rectangulo int altura, largura; //altura e largura do rectangulo }; Rectangulo::Rectangulo(int x, int y, int alt, int larg) { mudarValores(x, y, alt, larg); } void Rectangulo::mudarValores(int x, int y, int alt, int larg) { mudarX(x); mudarY(y); mudarAltura(alt); mudarLargura(larg); }

Exemplo 15.6 - Classe Rectangulo (usando o apontador this) No se esqueam que os atributos de uma funo (o que est entre parentises () ) so locais e apenas existem nessa funo. Podemos ento fazer this->x = x; que significa a varivel x do objecto vai ser igual varivel x (que foi atribuida funo).

Headers
As classes so normalmente colocadas num tipo especial de ficheiros, os headers (*.h), para uma mais fcil reutilizao das mesmas. Vou pegar no exemplo da classe Rectngulo e coloc-la em dois ficheiros separados: rectangulo.h (o header, que contm a declarao da classe) e o rectangulo.cpp(que contm o cdigo com as definies dos mtodos da classe): rectangulo.h:

http://agnor.gamedev-pt.net/gamedev/cpp.html
#ifndef _RECTANGULO_H_ #define _RECTANGULO_H_ class Rectangulo { public: Rectangulo(int x, int y, int alt, int larg); //funes bsicas de alterar valores e retorno void mudarX(int x) { this->x = x; } //notem! o x do objecto ser igual //ao x da funo void mudarY(int y) { this->y = y; } void mudarAltura(int altura) { this->altura = altura; } void mudarLargura(int largura) { this->largura = largura; } void mudarValores(int x, int y, int alt, int larg); int int int int obterX() { return x; } obterY() { return y; } obterAltura() { return altura; } obterLargura() { return largura; }

//funes de clculo int area() { return largura * altura; } int perimetro() { return (largura * 2) + (altura * 2); } private: int x, y; //coordenadas do canto superior esquerdo do rectangulo int altura, largura; //altura e largura do rectangulo

};

#endif

Exemplo 15.7 - rectangulo.h rectangulo.cpp


#include "rectangulo.h" Rectangulo::Rectangulo(int x, int y, int alt, int larg) { mudarValores(x, y, alt, larg); } void Rectangulo::mudarValores(int x, int y, int alt, int larg) { mudarX(x); mudarY(y); mudarAltura(alt); mudarLargura(larg); }

Exemplo 15.7 - rectangulo.cpp S h 3 linhas que merecem explicao:

http://agnor.gamedev-pt.net/gamedev/cpp.html #ifndef _RECTANGULO_H_ #define _RECTANGULO_H_ #endif Ao fazermos #include "rectangulo.h" estaremos a chamar o contedo de rectangulo.h. Ora, no exemplo que dei estamos obrigados a cham-la pelo menos 2 vezes. Para evitar conflitos de cdigo somos obrigados a incluir estas instrues (do pr-processador, que ser dado em aulas futuras). Sigam o seguinte raciocnio: If Not Defined (ifndef ou Se no est definido) _NOME_QUALQUER_ Define (definir) _NOME_QUALQUER_ ...classe... End If (pra a condio) Ao dar o nome da classe temos de ter em conta que nunca iremos utilizar o mesmo nome numa varivel (ou no pr-processador), por isso normalmente d-se o nome: NOME_DA_CLASSE_H ou _NOME_DA_CLASSE_H_ Para acabar, um exemplo de como utilizar os dois ficheiros (rectangulo.h e rectangulo.cpp) num programa: main.cpp:
#include <iostream> #include "rectangulo.h" using namespace std; int main() { Rectangulo rect(10, 5, 20, 10); cout << "Area antes: " << rect.area() << endl; rect.mudarAltura(5); cout << "Area depois: " << rect.area() << endl; cin.get(); return 0;

Exemplo 15.7 - main.cpp Final da aula 15 de C++: Prxima aula -> C++ 16 - Relaes entre Classes Fazer o download do cdigo fonte dos exemplos da aula Fazer o download da aula em PDF (Brevemente) Ir para o topo da pgina

Aula 16 - Relaes entre classes


<!--

http://agnor.gamedev-pt.net/gamedev/cpp.html google_ad_client = "pub-9639791948153775"; google_ad_width = 336; google_ad_height = 280; google_ad_format = "336x280_as"; google_ad_type = "text"; google_ad_channel ="3703014365"; google_color_border = "FFFFFF"; google_color_bg = "FFFFFF"; google_color_link = "0000FF"; google_color_url = "000000"; google_color_text = "000000"; //-->Conceitos-Chave: - generalizao, relao entre classes, onde existe uma classe-me (geral) e outras mais especficas, que herdam os membros da classe-me (classes-filhas). Relao "is a" (" um") - protected, palavra-chave que actua na acessibilidade dos membros de uma classe. No podem ser acedidos fora desta classe ( semelhana dos membros privados), com a excepo do caso de associao, em que as classes-filhas podem aceder aos membros protegidos da classe me - agregao, relao entre classes, onde uma classe tem como membro um objecto de outra classe. Implica uma relao "has a" ("tem um"). - friend, uma classe que seja "friend" (amiga) de outra pode aceder aos seus membros privados - polimorfismo, a abilidade de objectos de diferentes tipos (classes) poderem responder a mtodos com o mesmo nome, cada um deles tendo um comportamento especfico para cada tipo (classe) (definio da Wikipedia Inglesa)

Relaes entre classes


Em grandes projectos (como um jogo) comea-se por planear o cdigo. Esta planificao feita ao nvel da escolha das classes e da escolha das relaes entre elas. O paradigma OOP (Programao Orientada a Objectos) prev dois grandes tipos de relaes entre classes: - Generalizao - Agregao Esta aula tentar explicar o uso e importncia destas relaes.

Generalizao (atravs da Herana)


Imaginemos que estamos a desenvolver um RPG e que existem diferentes raas que, embora com as suas caractersticas individuais, partilham entre si vrias caractersticas. Neste caso poderiamos criar uma classe geral, chamada "Ser", e vrias classes mais especficas. Ao criarmos uma generalizao estaremos a implicar uma relao "is a" (" um", por exemplo, Humano um Ser) Imaginem que esta a classe Ser:
class Ser { public: void mover(); void dormir();

//todos os seres (animais) se movem //todos dormem

void falar() { cout << "... Parece que nao fala" << endl; } /* Se uma determinada raa no falar aparecer esta mensagem... vero j a

http://agnor.gamedev-pt.net/gamedev/cpp.html
seguir o seu uso */

private: int hp; //Health Points ou Pontos de Sade };

Ok, sei que uma representao um pouco fraca, mas ando com falta de ideias :) O que importante nesta classe que ser ela a geral, atravs da qual todas as outras a seguir expostas vo ser generalizadas. Agora alguns exemplos possveis de classes generalizadas da classe Ser:
class Humano : public Ser //classe Humano, derivada da classe Ser { public: //mover e dormir j esto na geral void falar() { cout << "Chamaste?" << endl; } /* Como podem vr, embora j exista um mtodo "falar" na classe geral, este no afecta este mtodo */ void atacar(); private: int forca; // a forca do personagem. }; class Magico : public Ser { public: void falar() { cout << "Em que podem as forcas dos meus feiticos te ajudar?" << endl; } void lancarFeitico(); private: int mp; // Magic Points ou Pontos de Magia int magia; //a fora da magia da personagem }; class Orc : public Ser { public: void atacar(); private: int forca; // fora com que o Orc ataca. };

Vm como facil generalizar? A nica coisa que tm de fazer acrescentar duas palavras de cdigo: class ClasseGeneralizada : public ClasseGeral Vejam agora um exemplo do uso das classes acima (programa compilvel):

http://agnor.gamedev-pt.net/gamedev/cpp.html
#include <iostream> using namespace std; class Ser { public: void mover(); void dormir();

//todos os seres (animais) se movem //todos dormem

void falar() { cout << "... Parece que nao fala" << endl; } /* Se uma determinada raa no falar aparecer esta mensagem... vero j a seguir o seu uso */ private: int hp; //Health Points ou Pontos de Sade }; class Humano : public Ser //classe Humano, derivada da classe Ser { public: //mover e dormir j esto na geral void falar() { cout << "Chamaste?" << endl; } /* Como podem vr, embora j exista um mtodo "falar" na classe geral, este no afecta este mtodo */ void atacar(); private: int forca; // a forca do personagem. }; class Magico : public Ser { public: void falar() { cout << "Em que podem as forcas dos meus feiticos te ajudar?" << endl; } void lancarFeitico(); private: int mp; // Magic Points ou Pontos de Magia int magia; //a fora da magia da personagem }; class Orc : public Ser { public: void atacar(); private: int forca; // fora com que o Orc ataca. }; int main() { Humano hum;

http://agnor.gamedev-pt.net/gamedev/cpp.html
Magico mag; Orc orc; hum.falar(); mag.falar(); orc.falar(); } cin.get();

Exemplo 16.1 - Classe Ser e outras classes-filhas Nota: Cada classe tem o seu prprio construtor e destrutor, ou seja, uma classe generalizada no pode herdar o construtor da classe-me.

O tipo protected
Antes de avanar mais vou-vos falar sobre o tipo de acesso protected. Neste ponto das aulas j devem saber bem o que o tipo privado (private) e pblico (public) das classes. Muito bem, agora, com a introduo da herana, devem aprender o tipo protected. Basicamente: Os membros privados no podem ser acedidos por nenhum objecto, a no ser atravs da prpria classe. Os membros protegidos podem ser acedidos apenas pela prpria classe e pelas classes derivadas, atravs da herana. Os membros pblicos podem ser acedidos tanto dentro, como fora da classe. Assim, no exemplo acima, as classes derivadas da funo ser no poderiam aceder varivel hp. Podemos resolver facilmente essa questo:
class Ser { public: void mover(); void dormir();

//todos os seres (animais) se movem //todos dormem

void falar() { cout << "... Parece que nao fala" << endl; } /* Se uma determinada raa no falar aparecer esta mensagem... vero j a seguir o seu uso */ protected: int hp; //Health Points ou Pontos de Sade };

Agregao
A agregao implica uma relao "has a" (tem um). Por exemplo, um Humano tem roupa e duas armas (faca e espada).

http://agnor.gamedev-pt.net/gamedev/cpp.html
class Humano : public Ser //classe Humano, derivada da classe Ser { public: //mover e dormir j esto na geral void falar() { cout << "Chamaste?" << endl; } /* Como podem vr, embora j exista um mtodo "falar" na classe geral, este no afecta este mtodo */ void atacar(); private: int forca; // a forca do personagem. Roupa roupa; Arma espada; Arma faca; };

Generalizao vs Agregao
Em alguns casos, poder parecer difcil distinguir entre as duas relaes, o que leva ao uso desapropriado da herana. A herana deve-se usar apenas em casos bvios, para se evitar confuses futuras. Por exemplo, uma classe Carro no dever ser uma generalizao da classe Motor, s porque a classe Motor a classe mais importante (que contm a potncia, km/h...). Um carro certamente que no um motor, apenas tem um motor. Esta explicao poder parecer um bocado confusa, mas no futuro iro ver que a m distino entre estes dois tipos de relaes pode levar reescrita completa do cdigo (eu sei por experincia prpria)

Classes Friend
Em C++ possvel fazer com que uma classe aceda aos membros privados e protegidos de uma funo. Basta declar-la como friend (amiga).
#include <iostream> using namespace std; class UM { private: //para dizer a verdade, nem precisvamos deste private: int x; friend class DOIS; //a classe DOIS amiga da classe UM, por isso a classe //DOIS pode aceder aos membros privados da classe UM }; class DOIS { public: void setX(int x) void printX() private: UM classe; }; int main()

{ classe.x = x; } { cout << classe.x << endl; }

http://agnor.gamedev-pt.net/gamedev/cpp.html
{ DOIS t; t.setX(30); t.printX(); cin.get(); return 0; }

Exemplo 16.2 - Teste de uma classe "friend"

Polimorfismo
Polimorfismo pode-se definir como "a abilidade de objectos de diferentes tipos (classes) poderem responder a mtodos com o mesmo nome, cada um deles tendo um comportamento especfico para cada tipo (classe) (traduzido da definio da Wikipedia Inglesa) Mas que significa isto na prtica? J vimos que uma classe derivada partilha com a classe-me, os membros pblicos e protegidos da mesma. Mas no s isso: o tipo de apontador de uma classe derivada compatvel com o da classe me, ou seja, nos exemplos acima (classe Ser), poderamos fazer algo como: Magico jog1; Ser *jogador = &jog1; Como esto a ver, estamos a pegar no apontador para a classe geral (Ser) e a fazer com que aponte para uma classe generalizada (Magico). Ou seja, o jogador vai ser um magico. Do mesmo modo, poderia-se fazer: Ser *jogador = new Magico; O objecto jogador vai assim pertencer classe Magico. Isto bastante til quando queremos alterar o tipo de classes em runtime, ou seja, por aco do utilizador, enquanto o jogo corre. Tambm se pode utilizar isto em funes, por exemplo:
#include <iostream> using namespace std; class Ser { public: void mover(); void dormir();

//todos os seres (animais) se movem //todos dormem

void falar() { cout << "... Parece que nao fala" << endl; } /* Se uma determinada raa no falar aparecer esta mensagem... vero j a seguir o seu uso */ private: int hp; //Health Points ou Pontos de Sade }; class Humano : public Ser //classe Humano, derivada da classe Ser { public: //mover e dormir j esto na geral void falar() { cout << "Chamaste?" << endl; }

http://agnor.gamedev-pt.net/gamedev/cpp.html
/* Como podem vr, embora j exista um mtodo "falar" na classe geral, este no afecta este mtodo */ void atacar(); private: int forca; // a forca do personagem. }; class Magico : public Ser { public: void falar() { cout << "Em que podem as forcas dos meus feiticos te ajudar?" << endl; } void lancarFeitico(); private: int mp; // Magic Points ou Pontos de Magia int magia; //a fora da magia da personagem }; class Orc : public Ser { public: void atacar(); private: int forca; // fora com que o Orc ataca. }; void falar(Ser *pessoa); int main() { Humano hum; Magico mag; Orc orc; falar(&hum); falar(&mag); falar(&orc); } cin.get(); // bvio que temos de passar o endereo do objecto //pois queremos que seja processado o objecto em si... //funo falar. Notem que leva como atributo um //apontador para um objecto da classe Ser

void falar (Ser *pessoa) { pessoa->falar(); }

Exemplo 16.3 - Funo falar (sem funes virtuais)

http://agnor.gamedev-pt.net/gamedev/cpp.html Est portanto cumprido o primeiro requisito do polimorfismo. Um nico objecto pode assumir vrias classes. No entanto, ao fazermos jogador->falar() (no se esqueam que um apontador, e por isso precisa do '->' em vez do '.') no chamada o mtodo da classe especfica, mas sim o mtodo da classe geral (Ser). Isto faz com que, no exemplo acima, mostre trs vezes a expresso "... Parece que nao fala". Falta ento ser cumprido o segundo requisito do polimorfismo, que pode ser facilmente resolvido recorrendo a uma nica palavra-chava: virtual:
#include <iostream> using namespace std; class Ser { public: void mover(); void dormir();

//todos os seres (animais) se movem //todos dormem

virtual void falar() { cout << "... Parece que nao fala" << endl; } /* Se uma determinada raa no falar aparecer esta mensagem... vero j a seguir o seu uso */ private: int hp; //Health Points ou Pontos de Sade }; class Humano : public Ser //classe Humano, derivada da classe Ser { public: //mover e dormir j esto na geral void falar() { cout << "Chamaste?" << endl; } /* Como podem vr, embora j exista um mtodo "falar" na classe geral, este no afecta este mtodo */ void atacar(); private: int forca; // a forca do personagem. }; class Magico : public Ser { public: void falar() { cout << "Em que podem as forcas dos meus feiticos te ajudar?" << endl; } void lancarFeitico(); private: int mp; // Magic Points ou Pontos de Magia int magia; //a fora da magia da personagem }; class Orc : public Ser { public:

http://agnor.gamedev-pt.net/gamedev/cpp.html
void atacar(); private: int forca; // fora com que o Orc ataca. }; void falar(Ser *pessoa); int main() { Humano hum; Magico mag; Orc orc; falar(&hum); falar(&mag); falar(&orc); cin.get(); } void falar (Ser *pessoa) { pessoa->falar(); } // bvio que temos de passar o endereo do objecto //pois queremos que seja processado o objecto em si... //funo falar. Notem que leva como atributo um //apontador para um objecto da classe Ser

Exemplo 16.4 - Funo falar (com funes virtuais) A palavra chave virtual o que faz o mecanismo de polimorfismo funcionar. Ao definirmos o mtodo falar da classe-me (Ser) como virtual, este mtodo no ser chamado pelas classes-filhas (sendo chamado o mtodo especfico de cada uma). O polimorfismo muito importante em programao orientada a objectos, pois fornece-nos um meio de alterarmos o completo total de um objecto, dinamicamente. Final da aula 16 de C++: Prxima aula -> C++ 17 - Tcnicas Avanadas de C++ - Parte I Fazer o download do cdigo fonte dos exemplos da aula Fazer o download da aula em PDF (Brevemente) Ir para o topo da pgina

Aula 17 - Tcnicas Avanadas de C++ - Parte I


<!-google_ad_client = "pub-9639791948153775"; google_ad_width = 336; google_ad_height = 280; google_ad_format = "336x280_as"; google_ad_type = "text"; google_ad_channel ="3703014365";

http://agnor.gamedev-pt.net/gamedev/cpp.html google_color_border = "FFFFFF"; google_color_bg = "FFFFFF"; google_color_link = "0000FF"; google_color_url = "000000"; google_color_text = "000000"; //-->Conceitos-Chave: - overload de funes, funes com o mesmo identificador, mas com argumentos/tipo de retorno diferentes. - parmetros predefinidos, argumentos que assumem um determinado valor, quando o utilizador no o especifica - constantes, variveis que s assumem um valor (no podem ser alteradas), aquando a declarao da mesma. - membros estticos, membros de uma classe com o mesmo tempo de vida de uma varivel global, mas com o alcance de uma varivel local. So comuns a todos os objectos de uma classe - mtodos estticos, mtodos de uma classe que podem ser chamados sem criar um objecto. - apontadores para funes, apontadores que apontam para uma funo. Tm a particularidade de se poder alterar vontade (pode apontar para qualquer funo) em runtime.

Tcnicas avanadas de C++


Na verdade o objectivo das prximas aulas de ensinar algumas tcnicas bastante teis, que podem passar por algoritmos, criao de classes, instrues novas e bibliotecas novas (STL, por exemplo). No significam, por isso, que so complicadas, destinam-se apenas a ajudar a resolver alguns problemas, ou encontrar melhor solues para os vossos jogos.

Overload de funes
Em C++ podemos ter vrias funes com o mesmo identificador, mas com diferentes argumentos/cdigo. Por exemplo, imaginem uma funo que calcula a rea de um rectngulo:
#include <iostream> using namespace std; void area (int c, int l); void area (double c, double l); // uma funo com o mesmo identificador, mas na //realidade at so bastante diferentes int main() { area (2, 4); area (5.2, 1.3); cin.get(); return 0;

//ser chamada a funo int area //ser chamada a funo double area

void area (int c, int l) { cout << "Esta a ser usada a funcao int area" << endl; cout << "Area = " << (c * l) << endl; } void area (double c, double l)

http://agnor.gamedev-pt.net/gamedev/cpp.html
{ cout << "Esta a ser usada a funcao double area" << endl; cout << "Area = " << (c * l) << endl; }

Exemplo 17.1 - Funo rea - Overload de Funes Como vm, a diferena entre as duas, que provoca o overload (sobrecarregamento) das funes o tipo de argumentos. Tambm o nmero de argumentos de uma funo pode provocar o seu overload, por exemplo: int soma (int x, int y); int soma (int x, int y, int z); Isto torna-se bastante til na interface entre uma classe e o programador, por exemplo: int area (Rectangulo rect); int area (int comprimento, int largura); Dica: Normalmente o cdigo entre funes que esto "sobrecarregadas" no difere muito, sendo que apenas difere no tratamento dos dados (muda o tipo de variveis, ou acrescenta mais uma varivel, por exemplo), de modo a evitar confuses no cdigo.

Parmetros predefinidos
Uma funo pode apresentar parmetros opcionais, em que o programador pode ou no, consoante as suas necessidades, atribuir valores. Caso no atribua um valor ao parmetro, a este ser dado um valor predefinido, que foi escolhido anteriormente, na definio da funo. Imaginem a seguinte funo soma:
#include <iostream> using namespace std; int soma (int a, int b, int c = 0); interferir int main() { int x = soma (4, 3); int y = soma (3, 7, 6); cout << "X: " << x << "\nY: " << y << endl; cin.get(); return 0; // notem que na definio da funo no // colocar c = 0, s na declarao (acima) // c igual a 0, de modo a no // na operao soma

int soma (int a, int b, int c) preciso { return (a + b + c); }

http://agnor.gamedev-pt.net/gamedev/cpp.html

Exemplo 17.2 - Funo Soma - Parmetros Predefinidos Como vm muito til e podemos dar uma escolha quanto s variveis a usar. Isto pode resultar bem ao criar um motor de jogo, pois podemos dar-lhes a escolha de utilizar ou no argumentos na funo (se escolher no utilizar, o seu valor ficar a cargo dos programadores da funo). Notem tambm que s podem colocar os valores predefinidos ou na declarao ou na definio da funo, nunca nos ambos. Normalmente coloca-se na declarao, porque a que aparece nos ficheiros header. Resta dizer que, por razes bvias, s podem utilizar valores predefinidos nos ltimos parmetros da funo. Por exemplo: f(int x = 0, y, z = 0); No correcto.

Arrays como argumentos de funes


Como j tinhamos visto, passar um array a uma funo bastante fcil:
#include <iostream> using namespace std; int soma (int array[], int size); int main() { int array[5] = {2, 4, 5, 2, 1};

//cria um array de 5 inteiros

cout << "Soma: " << soma(array, 5) << endl; cin.get(); return 0; } int soma (int array[], int size) { int valor = 0; for (int i = 0; i < size; i++) //percorre o array, de 0 a 4 { valor += array[i]; //vai somando.... } } return valor;

Exemplo 17.3 - Soma dos Elementos de um array Quando um array passado como argumento a uma funo esta no ir criar uma cpia do mesmo na memria (como faz normalmente com qualquer varivel), mas sim criar um apontador para o seu primeiro elemento. Assim, ao alterarmos um array dentro de uma funo estaremos realmente a alterar esse array fora da funo (lembrem-se de referncias e apontadores). Resumindo, se passarmos um array a uma funo e alterarmos o array dentro da funo, depois

http://agnor.gamedev-pt.net/gamedev/cpp.html deste processamento o array continuar alterado (ao contrrio das variveis, que s podem ser alteradas atravs de referncias e apontadores).
#include <iostream> using namespace std; void duplicar (int array[], int size); int main() { int array[5] = {2, 4, 5, 2, 1}; cout << "Array normal: " << endl; for (int i = 0; i < 5; i++) { cout << "[" << i << "] - " << array[i] << endl; } cout << "\nArray apos duplicacao: " << endl; duplicar(array, 5); for (int i = 0; i < 5; i++) { cout << "[" << i << "] - " << array[i] << endl; } cin.get(); return 0; } void duplicar (int array[], int size) { for (int i = 0; i < size; i++) //percorre o array, de 0 a 4 { array[i] *= 2; //multiplica cada numero por 2 } }

//cria um array de 5 inteiros

Exemplo 17.4 - Duplicar os elementos de um Array Como vm no precisamos de recorrer a apontadores/referncias para alterar o valor atravs da funo. Alis, como tinha explicado, um array e um apontador so muito semelhantes. Assim, o exemplo abaixo praticamente igual ao de cima:
void duplicar (int *array, int size) { for (int i = 0; i < size; i++) //percorre o array, de 0 a 4 { *array *= 2; //multiplica cada numero por 2 array++; //move o endereo do apontador/array, para captar o valor seguinte } }

http://agnor.gamedev-pt.net/gamedev/cpp.html

Constantes
C++ aceita variveis constantes, ou seja, variveis que tm um valor fixo. Se tentarmos mudar o valor da varivel o compilador ir considerar como um erro e no deixar compilar. H vrias vantagens em considerar variveis como constantes, principalmente com apontadores e em mtodos de classes. Uma varivel constante define-se assim: const tipo_de_variavel nome_da_variavel = valor_constante; Por exemplo: const int x = 9; const float pi = 3.14; No se esqueam que tm sempre que atribuir um valor quando definem a varivel. O exemplo seguinte daria erro: const float pi; pi = 3.14; Uma vantagem de criar um apontador constante para uma varivel de fazer com que a varivel apontada no seja modificada (estaremos a criar uma varivel read-only, s para leitura):
#include <iostream> using namespace std; int main() { int x = 30; const int *pointer = &x; // *pointer = 2; <- Daria erro cout << *pointer << endl; cin.get(); return 0;

Exemplo 17.5 - Apontador Constante Poderemos tambm criar mtodos constantes dentro de classes. Estes tm a vantagem de no poderem modificar nenhuma varivel no objecto, o que previne alguns erros de programao.
class Monstro { public: void setID(int id) { this->id = id; } const int getID() { // id = 2; <- isto daria erro, uma vez que no podemos alterar o objecto return id; } private: int id; }

http://agnor.gamedev-pt.net/gamedev/cpp.html Resumindo, criar variveis/mtodos constantes serve, principalmente, para evitar que o programador cometa erros por distrao. , ento, til caso o cdigo seja distribuido por vrios programadores, de modo a que eles saibam quais as variveis que no podem alterar.

Membros estticos
Uma varivel esttica uma varivel nica, para todos os objectos de uma classe. Esta varivel tem o mesmo tempo de vida de uma varivel global, mas possui o mesmo alcance do que um membro de um objecto. Vejam abaixo um uso comum de membros estticos, para contagem do nmero de objectos de uma classe:
#include <iostream> using namespace std; class Monstro { public: static int number; // o nmero de monstros em todo o programa

Monstro(char *name) // construtor { this->name = name; number++; } private: char *name; }; int Monstro::number = 0; //temos que iniciar a varivel globalmente //a varivel esttica vai ser incrementada

int main() { Monstro orc("Orc"); Monstro spider("Spider"); Monstro goblin("Goblin"); cout << "Numero de Monstros: " << Monstro::number << endl; cin.get(); return 0; }

Exemplo 17.6 - Classe Monstro - Membros Estticos Como podem ver, so muito teis, uma vez que existem independentemente do objecto, mas continuam a fazer parte da classe. Reparem s na seguinte linha de cdigo: int Monstro::number = 0; Para podermos aceder a um membro esttico teremos sempre que inicializ-lo como uma varivel global.

http://agnor.gamedev-pt.net/gamedev/cpp.html

Mtodos estticos
Tambm podemos criar mtodos estticos. Estes tm a particularidade de poderem ser chamados sem termos criado um objecto da classe. Por exemplo, imaginem a seguinte classe Math:
#include <iostream> using namespace std; class Math { public: static static static static int int int int somar(int a, int b) subtrair(int a, int b) multiplicar(int a, int b) dividir(int a, int b) { { { { return return return return a+b; a-b; a*b; a/b; } } } }

};

int main() { int x = Math::somar(4, 5); int y = Math::dividir(20, 4); int z; Math m; z = m.subtrair(6, 2); normalmente // isto foi s para mostrar que podemos aceder // atravs do objecto a mtodos estticos. O mesmo // acontece para membros estticos cout << "X: " << x << ", Y: " << y << endl; cin.get(); return 0;

Exemplo 17.7 - Classe Math - Mtodos Estticos

Function Pointers (Apontadores para funes)


Function Pointers (acho que o termo correcto em portugus apontadores para funes :) so muito teis na programao. Aqui s vou mostrar um exemplo fcil. Por exemplo, imaginem que queramos criar uma calculadora completa, que oferecesse ao programador uma simples funo que, sem recorrer a operadores condicionais (if, else, switch) permitisse fazer as 4 operaes bsicas da matemtica (somar, subtrair, dividir e multiplicar). Os apontadores para funes permitiriam isso. Uma funo, tal como uma varivel, possui um endereo na memria. Podemos ento colocar um apontador para a mesma entre os argumentos de uma funo e cham-la. Por exemplo, poderamos fazer: int Vejam o exemplo abaixo, da tal calculadora:
#include <iostream> using namespace std; int somar(int a, int b) int subtrair(int a, int b) { { return a+b; } return a-b; }

http://agnor.gamedev-pt.net/gamedev/cpp.html
int multiplicar(int a, int b) int dividir(int a, int b) { { return a*b; } return a/b; }

int main() { int (*calculadora)(int a, int b); //criamos um apontador para uma funo calculadora = somar; //calculadora passa a apontar para a funo somar int x = (*calculadora)(4, 6); calculadora = multiplicar; //calculadora passa a apontar para a funo somar int y = (*calculadora)(4, 2); cout << "X: " << x << ", Y: " << y << endl; cin.get(); return 0;

Exemplo 17.8 - Funes de Calculadora - Apontadores para Funes Admito que possa parecer um pouco confuso, mas no nada de outro mundo. Seno vejamos: int (*calculadora)(int a, int b); - estamos a criar um apontador para funes. Este apontador em especfico consegue apontar apenas para funes que apresentem dois argumentos de tipo int (o nome no precisa de ser a ou b, como vamos ver frente) e que retornem variveis do tipo int. calculadora = somar; esta nem precisa de explicaes. Estamos a fazer com que o apontador calculadora aponte para a funo somar. int x = (*calculadora)(4, 6); - para podermos aceder funo apontada pelo apontador calculadora temos de usar o operador desreferncia (*). E, claro, introduzir os argumentos. Dica: Nas declaraes de uma funo no somos obrigados a especificar o nome dos argumentos (s o tipo de varivel), mas somos obrigados a especificar o nome na definio. Assim poderamos ter feito: int (*calculadora)(int, int); Isto no se aplica s a apontadores para funes, mas a todo o tipo de funes, desde que seja na sua definio: int f(int, int); por exemplo No foi assim to difcil, pois no? Agora vejamos um exemplo um pouco mais complicado, utilizando uma funo intermediria.
#include <iostream> using namespace std; int int int int somar(int a, int b) subtrair(int a, int b) multiplicar(int a, int b) dividir(int a, int b) { { { { return return return return a+b; a-b; a*b; a/b; } } } }

int calculadora(int a, int b, int (*operacao)(int, int));

http://agnor.gamedev-pt.net/gamedev/cpp.html
int main() { int x = calculadora(4, 6, somar); int y = calculadora(4, 2, multiplicar); cout << "X: " << x << ", Y: " << y << endl; cin.get(); return 0; } int calculadora(int a, int b, int (*operacao)(int, int)) { int resultado = operacao(a, b); } return resultado;

Exemplo 17.9 - Funo Calculadora - Apontadores para Funes int calculadora(int a, int b, int (*operacao)(int, int)); Esta declarao de funo totalmente normal... at chegarmos ao ltimo parmetro. Se repararem, sem o '*' este parmetro seria exactamente uma funo: int operacao (int, int). Com esta instruo estamos a dizer ao programa para aceitar as funes que possuam dois argumentos inteiros e que retornem um valor inteiro. int x = calculadora(4, 6, somar); Como podem vr estamos a passar a funo como se fosse uma varivel ( um apontador, na verdade). Final da aula 17 de C++: Prxima aula -> C++ 18 - Tcnicas Avanadas de C++ - Parte 2 Fazer o download do cdigo fonte dos exemplos da aula Fazer o download da aula em PDF (Brevemente) Ir para o topo da pgina

Aula 18 - Tcnicas Avanadas de C++ - Parte II


<!-google_ad_client = "pub-9639791948153775"; google_ad_width = 336; google_ad_height = 280; google_ad_format = "336x280_as"; google_ad_type = "text"; google_ad_channel ="3703014365"; google_color_border = "FFFFFF"; google_color_bg = "FFFFFF"; google_color_link = "0000FF"; google_color_url = "000000"; google_color_text = "000000";

http://agnor.gamedev-pt.net/gamedev/cpp.html //-->Conceitos-Chave: - STL, Standard Template Library, uma biblioteca que faz parte dos padres do C++ e que acrescenta muitas funcionalidades, como a biblioteca string - template, mecanismo do C++ que cria uma varivel genrica, que pode assumir qualquer tipo de varivel (incluindo classes criadas pelo programador) - namespace, permitem agrupar dentro delas variveis, funes ou classes, de modo a evitar confuses com variveis/funes/classes com o mesmo nome - biblioteca string, biblioteca que faz parte da STL e que engloba recursos para tratamento de strings

STL - Introduo
Nesta aula vou abordar STL (Standard Template Library). STL uma biblioteca criada para ajudar o programador, com vrias estruturas de dados e algoritmos. importante aprender a trabalhar com esta biblioteca, uma vez que o cdigo que contm muito til (aposto que a iro utilizar pelo menos uma vez) e faz parte dos standards do C++. Vocs j utilizaram esta biblioteca, pois a classe string uma das vrias presentes nela ( e como devem ter visto, muito til).

Templates em funes
A biblioteca chama-se STL, pois utiliza o mecanismo de templates do C++. Este mecanismo permite criar uma espcie de "varavel genrica", que poder operar com qualquer tipo de variveis. Na ltima aula aprendemos que poderamos utilizar diferentes funes com o mesmo nome, mas com diferentes tipos de variveis. Com templates podemos criar uma funo genrica, que poder operar com todos os tipos de variveis/classes. Por exemplo, seria ptimo se pudssemos criar apenas uma funo em alternativa s 3 seguintes: int somar (int a, int b); double somar (double a, double b); char somar (char a, char b); Assim, atravs do uso de templates, a tal funo genrica ficaria assim:
template <class Tipo> Tipo somar (Tipo a, Tipo b);

Devem ter reparado que a sintaxe bastante diferente do que estamos habituados a ver, mas vou tentar explicar tudo direitinho: Primeiro temos que ter em conta a sintaxe das templates: template <class identificador> declaracao_da_funcao; ou template <typename identificador> declaracao_da_funcao; No exemplo acima utilizei a primeira declarao, mas no h nenhuma diferena entre as duas (alis, o prximo exemplo vai seguir a segunda, para verem que igual). Podemos dar um nome qualquer ao identificador (no exemplo acima escolhi o nome "Tipo", que deve dar para a maior parte dos casos). Fica ento um exemplo de um programa que utilize os templates
#include <iostream> using namespace std; template <typename Tipo> Tipo somar (Tipo a, Tipo b) { return a + b; }

http://agnor.gamedev-pt.net/gamedev/cpp.html
int main() { cout << "Int - 2+3 - " << somar (2, 3) << endl; cout << "Double - 1.53+3.14 - " << somar (1.53, 3.14) << endl; cout << "Char - '1'+'2' - " << somar ('1', '2') << endl; cin.get(); return 0;

Exemplo 18.1 - Exemplo de Templates em Funes Nota: A soma de dois caracteres (tipo char) pode-vos parecer estranho. Se estiveram atentos s primeiras aulas, sabem que uma varivel do tipo char representada por um nmero (em binrio). Esse nmero , posteriormente, convertido num carcter (seguindo uma tabela). Por exemplo, ao seguir uma tabela ASCII, sabemos que o valor de '1' de 49 e o valor de '2' de 50. A soma dos dois igual a 99, que d o valor de 'c'. Tambm podemos criar um template que consiga trabalhar com dois tipos diferentes. Por exemplo, a funo diviso:
#include <iostream> using namespace std; template <class T, class U> T somar (T a, U b) { return a + b; } int main() { cout << "Double e Int - 3.43 + 2 - " << somar (3.43, 2) << endl; //notem que devemos colocar o double primeiro, pois como um numero decimal, //a funo dever retornar o tipo double. cin.get(); return 0; }

Exemplo 18.2 - Templates em Funes - Dois Tipos de Variveis Diferentes Normalmente o compilador consegue perceber quais os tipos de variveis a usar, mas no caso de no o conseguir, podemos arranjar isso facilmente, por exemplo: int x = somar <double, int> (a, b);

Templates em classes
Tambm se podem utilizar templates em classes. Como j devem ter percebido como funciona,

http://agnor.gamedev-pt.net/gamedev/cpp.html deixo s um exemplo completo:


#include <iostream> using namespace std; template <class T> class C_Output { public: //cria uma classe chamada C_Output

T getVar(); //retorna o tipo que for colocado no template void setVar(T var); void print (); private: T variavel; }; int main() { C_Output<double> x; C_Output<string> str; x.setVar(3.14); x.print(); str.setVar("Ola"); str.print(); cin.get(); return 0; } template <class T> T C_Output<T>::getVar() { return variavel; } template <class T> void C_Output<T>::setVar(T var) { variavel = var; } template <class T> void C_Output<T>::print() { cout << variavel << endl; }

// cria um objecto da classe C_Output // o tipo da template vai ser double //a template vai ser do tipo string

Exemplo 18.3 - Templates em Classes As primeiras linhas acho que se percebem, deixo s uma explicao para as definies dos mtodos da classe C_Output:
template <class T>

http://agnor.gamedev-pt.net/gamedev/cpp.html
T C_Output<T>::getVar() { return variavel; }

Se a funo no usasse o template e fosse do tipo int, ento ficaria algo como:
int C_Output::getVar() { return variavel; }

Como podem ver as alteraes nem so muitas. Adicionamos primeiro a instruo de que iramos utilizar um template ( template <class T> ), para a funo poder trabalhar com qualquer tipo de variveis. Depois colocamos o tipo de varivel que a funo retorna; como pode retornar qualquer tipo de varivel, escolhemos o tipo T, da template. Depois colocamos o identificador da classe (C_Ouput) e especificamos o tipo de varivel que o template iria assumir; como no sabemos ainda qual o tipo, ento poderemos colocar T. Acho que devem entender o resto :P Nota: Podem usar qualquer tipo de variveis em templates, incluindo classes criadas por vocs.

Namespaces
Desde a aula n 1 que usamos namespaces, mas s agora vou explicar para que servem. Basicamente, os namespaces servem para agrupar variveis/funes/classes dentro de um nome, de modo a evitar confuses quando trabalhamos com, por exemplo, outras bibliotecas. Isto torna-se muito til quando, por exemplo, querem criar um motor de jogo (ou game engine) e querem dar nomes simples s classes/funes/etc. que criam, sem que estas entrem em conflito com outras funes que, por acaso, tenham o mesmo nome. O exemplo mais simples:
#include <iostream> using namespace std; namespace dias_mes { int numero = 30; } namespace dias_semana { int numero = 7; } int main() { cout << dias_mes::numero << endl; cout << dias_semana::numero << endl; cin.get(); return 0;

//pode ser 31 ou 28 ou 29, mas isto s um exemplo

http://agnor.gamedev-pt.net/gamedev/cpp.html
}

Exemplo 18.4 - Exemplo de Namespaces E um exemplo mais prtico:


#include <iostream> using namespace std; namespace Engine_Grafica { void init() { cout << "Engine Grafica iniciada!" << endl; } } namespace Engine_Som { void init() { cout << "Engine de Som iniciada!" << endl; } } int main() { Engine_Grafica::init(); Engine_Som::init(); cin.get(); return 0;

Exemplo 18.5 - Exemplo de Namespaces 2

Using namespace
Ao fazermos using namespace ... estaremos a "pedir" ao compilador para automaticamente inserir a namespace quando necessrio. Desde a primeira aula tmos "pedido" ao compilador para automaticamente incluir a namespace std. Esta namespace refere-se biblioteca padro (standard) do C++, que inclui o cout, o endl, o cin, etc. Caso no colocassemos using namespace std; no inicio do programa, teramos que fazer o seguinte:
#include <iostream> //no estamos a colocar o using namespace std; namespace Engine_Grafica { void init() { std::cout << "Engine Grafica iniciada!" << std::endl; } }

http://agnor.gamedev-pt.net/gamedev/cpp.html
namespace Engine_Som { void init() { std::cout << "Engine de Som iniciada!" << std::endl; } } int main() { Engine_Grafica::init(); Engine_Som::init(); std::cin.get(); return 0;

Exemplo 18.6 - Exemplo de Using Namespace Outro exemplo:


#include <iostream> using namespace std; //usar a namespace std

namespace Engine_Grafica { void init() { cout << "Engine Grafica iniciada!" << endl; } } namespace Engine_Som { void init() { cout << "Engine de Som iniciada!" << endl; } } int main() { using namespace Engine_Grafica; //usar a namespace Engine_Grafica init(); //no precisamos de colocar aqui a namespace Engine_Som::init(); //mas precisamos, caso queiramos aceder Engine_Som cin.get(); return 0; }

Exemplo 18.7 - Exemplo de Using Namespace 2 Para acabar o assunto das namespaces: Quando utilizamos o using globalmente (onde declaramos

http://agnor.gamedev-pt.net/gamedev/cpp.html as variveis globais), ento este vlido para o programa todo. Se utilizarmos o using num bloco, este apenas vlido para esse mesmo bloco. Por exemplo:
#include <iostream> using namespace std; //incluir a namespace globalmente

namespace Engine_Grafica { void init() { cout << "Engine Grafica iniciada!" <<endl; } } namespace Engine_Som { void init() { cout << "Engine de Som iniciada!" << endl; } } int main() { { using namespace Engine_Grafica; //usar a namespace Engine_Grafica neste bloco init(); //no precisamos de colocar aqui a namespace } { using namespace Engine_Som; init(); //nem aqui :P } cin.get(); return 0; //usar a namespace Engine_Som neste bloco

Exemplo 18.8 - Exemplo de Using Namespace 3

STL
Depois desta longa introduo, vamos finalmente conhecer um pouco da STL. Na verdade, vocs j utilizaram um componente da STL: a classe string. Como a matria de STL mesmo muito extensa (h livros inteiros sobre ela), e, embora pretenda tentar explicar resumidamente o seu uso, deixo-vos aqui apenas explicada a classe string (desta vez mais aprofundado). Na prxima aula, pretendo explicar conceitos mais avanados, como iteradores e contentores, para poder explicar mais alguns componentes de STL

http://agnor.gamedev-pt.net/gamedev/cpp.html

Strings
Comecei a falar sobre a classe string na aula 12, no entanto s falei sobre como iniciar um objecto da classe string (e imprimi-la no ecr atravs do cout). Agora vou falar de alguns mtodos teis dentro da classe string.
#include <iostream> #include <string> using namespace std; int main() { string str1; string str2; string str3; str1 = "Bem vindo"; if (str2.empty()) // de esperar que esteja vazia... { cout << "A string 2 esta vazia!" << endl; } int tamanho = str1.size(); //retorna o comprimento da str1

cout << "A string 1 tem " << tamanho << " caracteres." << endl; cout << "Insira o seu nome: "; cin >> str2; str3 = str1 + " " + str2; // a str3 vai ser igual str1, mais um espao, mais a str2 cout << "\n\n" << str3 << endl; tamanho = str3.size(); str3.insert(tamanho, ", esta a gostar do programa?"); cout << str3 << endl; tamanho = str2.size(); //o tamanho do nome //insere no fim

cout << "\nInsira outro nome: "; cin >> str2; //utiliza a str2 para armazenar outro nome str3.replace(10, tamanho, str2); //substitui o nome. Comea na posiao 10 (depois de "Bem vindo ") e prolonga-se //durante o tamanho do nome (ou seja, substitui o nome :P) cout << "\n\n" << str3 << endl; ") str3.erase(0, 10); //apaga os primeiros 10 caracteres ( a frase "Bem vindo

cout << str3 << endl;

http://agnor.gamedev-pt.net/gamedev/cpp.html
int pos = str3.find("gostar"); //procura a primeira ocorrncia de "gostar" na str3 e retorna a posio do 1 caracter. cout << "\ngostar esta na posicao " << pos << endl; str1 = str3; //a str1 vai assumir o valor da str3

if (str1 == str3) // de esperar que sim { cout << "\nA str1 e str3 sao iguais!" << endl; } cin.get(); cin.get(); return 0; }

Exemplo 18.9 - Exemplo de vrios mtodos da biblioteca string Acabei por dar muita matria, mas vamos com calma.

string::empty()
Se a string estiver vazia, retorna true (1). Se no estiver vazia, retorna false, (0).

string::size()
Retorna o nmero de caracteres que a string possui.

string::operator +
Podemos juntar duas strings atravs do uso do operador soma (+). Acho que pelo exemplo vocs viram como funcionava.

string::insert()
Insere uma string dentro de outra string, a partir da posio que especificarmos. A sua definio : string& insert(size_type pos, const string& str); Em que pos a posio a partir da qual vai ser inserida a string e str a string a ser inserida. PS: O tipo de varivel size_type equivale ao unsigned int.

string::replace()
O mtodo replace() substitui uma substring (uma string dentro doutra string), por outra string e a sua definio esta: string& replace(size_type pos, size_type n, const string& str); Em que pos o comeo da substring que queremos apagar, n o nmero de caracteres que queremos substituir e str a string que queremos colocar.

http://agnor.gamedev-pt.net/gamedev/cpp.html

string::erase()
Apaga uma substring dentro da string. A definio : string& erase(size_type pos=0, size_type n=npos); Em que pos a posio a partir do qual queremos apagar (se no colocarmos nada a partir do primeiro caracter) e n o nmero de caracteres que queremos apagar (se no colocarmos nada apaga at ao fim da frase).

string::find()
size_type find (const string& str, size_type pos=0) const; size_type find (char ch, size_type pos=0) const; Procura pela primeira ocurrncia da substring str (ou o caracter ch), a partir da posio pos (que 0 se no colocarmos nada, desde o incio). Final da aula 18 de C++: Prxima aula -> C++ 19 - Tcnicas Avanadas de C++ - Parte 3 Fazer o download do cdigo fonte dos exemplos da aula Fazer o download da aula em PDF (Brevemente) Ir para o topo da pgina

Aula 19 - Tcnicas Avanadas de C++ - Parte III


<!-google_ad_client = "pub-9639791948153775"; google_ad_width = 336; google_ad_height = 280; google_ad_format = "336x280_as"; google_ad_type = "text"; google_ad_channel ="3703014365"; google_color_border = "FFFFFF"; google_color_bg = "FFFFFF"; google_color_link = "0000FF"; google_color_url = "000000"; google_color_text = "000000"; //-->Conceitos-Chave: - estrutura de dados, com o objectivo de proporcionar ao programador a forma mais eficiente de armazenar dados - vector, uma estrutura de dados da STL, semelhante a um array, mas que permite a expanso e diminuio da sua capacidade - lista ligada, uma estrutura de dados que permite a eficiente insero e eliminao de dados, atravs do uso de apontadores e memria dinmica

Estruturas de dados
Nesta aula irei focar o estudo sobre estruturas de dados. As estruturas de dados tm o objectivo de proporcionar ao programador a forma mais eficiente (em termos de velocidade, memria) de

http://agnor.gamedev-pt.net/gamedev/cpp.html armazenar dados. Estes dados podem ser o HP de uma personagem, ou as texturas de um nvel de jogo. Um programador de jogos precisa da maior velocidade e memria que conseguir obter e, por isso, saber implementar estruturas de dados fundamental. Felizmente, existe a STL que implementou de forma genrica grande parte das estruturas de dados mais teis. Com bastantes anos de desenvolvimento quase impossvel fazer melhor do que a STL para dados genricos. No entanto, a STL poder no ser a melhor soluo em determinados casos, mas na maior parte deles a melhor soluo disponvel.

Limitaes de um array
Vamos supor que precisamos de um array de uma determinada estrutura (Monster) que contenha todos os monstros no ecr. Como o nmero de monstros ao mesmo tempo pode variar ao longo do programa, podemos optar por armazenar espao para, digamos, 10 monstros (estamos a colocar este nmero como o mximo de monstros que poder aguentar o nosso array). Isso est implementado no seguinte cdigo:
#include <iostream> using namespace std; struct Monstro { int hp; int mp; }; int main() { const int MAX_MONSTROS_ECRA = 10; Monstro monstros_ecra[MAX_MONSTROS_ECRA]; } //...

Esta seria uma soluo razovel, se tivssemos a certeza que nunca iramos passar o limite dos 10 monstros no ecr. Imaginemos que fizemos alguns testes e que verificmos que num certo nvel do nosso jogo, podero estar at 1000 monstros no ecr. Poderamos definir a capacidade mxima do array para 1000. No entanto, este mtodo pode gerar uma enorme carga no programa. A estrutura Monster necessita de 8 bytes de memria (porque possui duas variveis do tipo int, de 4 bytes cada), ou seja o array iria necessitar de 8000 bytes, ou seja quase 8 KB (KiloBytes). Isto parece pouco, mas isso porque a nossa estrutura tem s 2 variveis. Se a nossa estrutura de dados ocupasse 1 KB, precisaramos quase 1 MB s para armazenar esta varivel. Este valor demasiado elevado para uma varivel, principalmente se tivermos em conta que s ir necessitar de tanto espao num determinado nvel, mas mesmo assim ir ocupar este espao durante todo o tempo de execuo do programa. Existem vrias solues para este problema. Primeiro iremos ver uma implementao muito simples (uma classe feita por mim) e outra implementao muito melhor (atravs do uso da classe vector da STL).

Classe BetterArray
Decidi criar uma classe que possibilita a adio (e deleco) de novos elementos num array, atravs do uso de apontadores e da memria dinmica. Alm disso, possui um contador, que tambm

http://agnor.gamedev-pt.net/gamedev/cpp.html poder facilitar na contagem dos elementos. Esta classe s funciona com variveis do tipo int, mas poderamos utilizar templates para se tornar numa classe genrica.
#include <iostream> using namespace std; class BetterArray { public: void addValue(int value); //adiciona um valor no fim do array void delEndValue(); //elimina o valor que est no fim do array int getValue(int index); //retorna o valor que est na posio index do array int getCount(); //retorna o nmero de elementos do array BetterArray(); ~BetterArray(); private: int *array; int count; //o apontador para o array //o nmero de elementos do array //construtor //destrutor

};

int main() { BetterArray teste; teste.addValue(3); (primeiro valor)

//cria um objecto de teste para a nossa classe // adicionado o valor '3' ao final do array

//esta uma forma simples de apresentar os dados dentro do array... for (int x = 0; x < teste.getCount(); x++) { cout << "Posicao: " << x << ", Valor: " << teste.getValue(x) << ", Count: " << teste.getCount() << endl; } cin.get(); teste.addValue(9); teste.addValue(27); //foram adicionados dois valores

for (int x = 0; x < teste.getCount(); x++) { cout << "Posicao: " << x << ", Valor: " << teste.getValue(x) << ", Count: " << teste.getCount() << endl; } cin.get(); teste.delEndValue(); //foi eliminado um valor do fim do array

for (int x = 0; x < teste.getCount(); x++) { cout << "Posicao: " << x << ", Valor: " << teste.getValue(x) << ", Count: " << teste.getCount() << endl; }

http://agnor.gamedev-pt.net/gamedev/cpp.html
cin.get(); return 0;

BetterArray::BetterArray() { array = NULL; //no incio o apontador para o array no aponta para nada count = 0; //numero de elementos igual a 0 } void BetterArray::addValue(int value) { int *tempArray = new int [count+1]; //cria um array na memria dinmica, com mais um elemento do que o antigo for (int x = 0; x < count; x++) { tempArray[x] = array[x]; //passa os contedos do array antigo para o novo } tempArray[count] = value; //o ltimo elemento do array novo alterado, com o novo valor count++; delete [] array; // eliminado o array antigo array = tempArray; //o apontador para o array passa a apontar para o novo array tempArray = NULL; //j no temos uso para este array } void BetterArray::delEndValue() { if (count > 1) //se houver mais que um elemento... { int *tempArray = new int [count-1]; //cria um novo array com menos um elemento do que o anterior for (int x = 0; x < count-1; x++) { tempArray[x] = array[x]; //passa todos os elementos (excepto o ltimo) para o novo array } count--; delete [] array; array = tempArray; tempArray = NULL; } else if (count == 1) //se s houver um elemento, ele eliminado... { delete [] array; array = NULL;

http://agnor.gamedev-pt.net/gamedev/cpp.html
count = 0; } }

int BetterArray::getValue(int index) { if (count > 0) //isto para prevenir erros do programador { if (index < count) { return array[index]; } } } int BetterArray::getCount() { return count; } BetterArray::~BetterArray() { if (array != NULL) //se o array ainda no tiver sido eliminado... { delete [] array; array = NULL; } }

Exemplo 19.1 - Classe BetterArray Esta classe necessita de conhecimentos razoveis de como funcionam apontadores e a memria dinmica. Aconselho-vos a reverem a aula 11 e a aula 14.

STL - Vector
A classe que desenvolvi apresenta bastantes problemas. Primeiro, porque s teve cerca de meia hora de desenvolvimento. Segundo, porque foi desenvolvida por um estudante "amador". Alm destes problemas, o mais visvel a criao de um array temporrio s para fazer a transio entre o array antigo e o novo, ou seja, durante uns instantes, iremos precisar do dobro da memria, j para no falar no tempo de processamento que precisamos para passar cada elemento para o novo array. Felizmente, existe a classe vector, que faz parte da STL e que tem a funo de introduzir uma nova estrutura de dados, semelhante ao array, mas muito mais dinmica. Podemos declarar um vector atravs da expresso seguinte:
#include <vector> vector <TIPO_DE_DADOS> identificador;

Como exemplo, vou aproveitar o main que fiz para a classe BetterArray:
#include <iostream> #include <vector> using namespace std; int main()

http://agnor.gamedev-pt.net/gamedev/cpp.html
{ vector <int> teste; teste.push_back(3); (primeiro valor) //cria um vector de teste, com o tipo int // adicionado o valor '3' ao final do array

//notem as diferenas for (int x = 0; x < teste.size(); x++) { cout << "Posicao: " << x << ", Valor: " << teste[x] << ", Count: " << teste.size() << endl; } cin.get(); teste.push_back(9); teste.push_back(27); //foram adicionados dois valores

for (int x = 0; x < teste.size(); x++) { cout << "Posicao: " << x << ", Valor: " << teste[x] << ", Count: " << teste.size() << endl; } cin.get(); teste.pop_back(); //foi eliminado um valor do fim do array

for (int x = 0; x < teste.size(); x++) { cout << "Posicao: " << x << ", Valor: " << teste[x] << ", Count: " << teste.size() << endl; } cin.get(); return 0; }

Exemplo 19.2 - Testes com a classe vector Vou explicar cada mtodo novo, um por um:

vector <int> teste;


Aqui estamos a declarar um vector. A classe vector faz valer o uso de templates para poder tratar qualquer tipo de varivel. Quando colocamos <int> no meio da declarao, estamos a dizer classe que pretendemos usar variveis inteiras dentro do vector.

push_back(valor) e pop_back()
A classe vector utiliza o conceito de estrutura de dados do tipo "pilha" (stack). Isto basicamente quer dizer que poderemos adicionar novos elementos no fim da pilha e retirar elementos tambm do fim da pilha: os ltimos a entrar so os primeiros a sair. O push adiciona elementos e o pop retira os elementos. Podem ver esse conceito ilustrado na seguinte figura (retirada da wikipedia):

http://agnor.gamedev-pt.net/gamedev/cpp.html

size()
A classe vector possui um contador, que nos diz o nmero de elementos do vector. Como podem ver, bastante til.

Outras situaes com a classe vector


Ainda falta falar de mais caractersticas da classe vector, para que possam substituir os vossos arrays em favor desta estrutura de dados. Felizmente, so conceitos bastante fceis de aprender. No exemplo seguinte veremos que utilizar a classe vector e utilizar um array pode ser praticamente igual:
#include <iostream> #include <vector> using namespace std; int main() { vector <char> nome; //isto algo estranho, porque uma string seria muito melhor nome.push_back('I'); nome.push_back('V'); nome.push_back('O'); cout << nome[0] << nome[1] << nome[2] << endl; nome[0] = 'M'; nome[1] = 'A'; nome[2] = 'R'; //podemos alterar cada elemento como num array normal

cout << nome[0] << nome[1] << nome[2] << endl; nome.resize(5); //podemos alterar a dimenso do array! //se no fizessemos resize(), isto daria erro... nome[4] = 'A'; //estou a introduzir os caracteres ao contrrio... nome[3] = 'I'; for (int x = 0; x < nome.size(); x++) { cout << nome[x]; } cout << endl; cin.get(); return 0; }

Exemplo 19.3 - Mais testes com a classe vector

http://agnor.gamedev-pt.net/gamedev/cpp.html Neste exemplo, bvia a vantagem do vector em relao ao array, mantendo a sua simplicidade de cdigo. Existe ainda outros mtodos, que nos permitem inserir elementos no meio de cada vector (em vez de ser s no final). No entanto, devido natureza dos vectores, estes mtodos so muito ineficientes, ou seja, se for mesmo necessrio vo ter que procurar outra alternativa.

Listas Ligadas
As listas ligadas apresentam uma vantagem enorme sobre os vectores: permitem a adio ou deleco de qualquer elemento da lista, sem perder em performance. Como nem tudo perfeito, apresentam uma enorme desvantagem em relao aos vectores: no possvel aceder a um ndice aleatrio da lista, sem perder em performance. Iremos j ver porqu ao analisar a natureza de uma lista ligada. Uma lista constituda por vrios ns. Cada n contm: uma varivel para o tipo de dados que pretendemos guardar (ex: int value) um apontador para o n seguinte (ex: Node* proximo) Nota: Existem vrios tipos de listas, nesta aula irei apresentar a mais simples, a lista simplesmente ligada, que apresenta apenas um apontador para o prximo elemento, sendo que o ltimo elemento liga-se a um valor nulo. Os outros tipos de listas incluem um apontador para o elemento anterior (listas duplamente ligadas) ou o ltimo elemento liga-se ao primeiro, formando um ciclo (lista circularmente ligada) Podem ver um esquema a ilustrar uma lista simplesmente ligada (novamente da wikipedia)

Para visualizarmos os conceitos que esto na base de uma lista ligada, antes de criar uma classe para a gesto da mesma, vou criar um exemplo de uma lista ligada " mo".
#include <iostream> using namespace std; class Node //cada n da nossa lista { public: int value; //o valor que fica armazenado Node* proximo; //um apontador para o prximo n (que est ligado a este) Node () { value = 0; proximo = NULL; } erros de inicializao }; int main() { Node *um = new Node(); Node *dois = new Node(); Node *tres = new Node(); um->value = 1; dois->value = 2; //um construtor para prevenir

//assim estamos a chamar o construtor de cada n

//agora atribuimos cada valor a cada n

http://agnor.gamedev-pt.net/gamedev/cpp.html
tres->value = 3; um->proximo = dois; //o n "um" liga-se ao n "dois" dois->proximo = tres; //o n "dois" liga-se ao n "trs" tres->proximo = NULL; //o n "trs" no se liga a nenhum, porque o ltimo da lista Node* temp = um; //para podermos percorrer a lista, ligamos um n temporrio ao primeiro da lista while (temp != NULL) //enquanto o valor temporrio no for nulo (no chega ao fim da fila) { cout << temp->value << endl; //mostra-nos o valor temp = temp->proximo; //temp assumo o valor do prximo n, percorrendo assim a lista } cin.get(); //esperamos um bocado...

//agora vamos "eliminar" o segundo valor um->proximo = tres; //vejam que simples! basta apontar o n "um" para o "n" trs e j est! delete dois; //agora tiramos o "dois" da memria porque j no precisamos dele dois = NULL; //isto para prevenir erros temp = um; //voltamos a fazer tudo de novo...

while (temp != NULL) //enquanto o valor temporrio no for nulo (no chega ao fim da fila) { cout << temp->value << endl; //mostra-nos o valor temp = temp->proximo; //temp assumo o valor do prximo n, percorrendo assim a lista } cin.get(); delete um, tres; return 0; } //no se esqueam de eliminar!

Exemplo 19.4 - Exemplo rudimentar de uma lista ligada Novamente, vou tentar explicar o que novo (se bem que nada daqui seja propriamente novo, a mecnica que nova). Comecemos por analisar a classe Node. Cada "Node" representa um n da lista, portanto uma lista um conjunto de ns. Cada n possui duas variveis: int value - Esta varivel serve para armazenar o valor de cada n ( a varivel "mais importante" para o utilizador) Node* prximo - Esta varivel contm toda a mecnica para que uma lista ligada funciona. um apontador para objectos da prpria classe, ou seja, serve para apontar para outro Node.

http://agnor.gamedev-pt.net/gamedev/cpp.html Assim, cada n armazena uma varivel que aponta para o elemento seguinte, permitindo o acesso a outros ns da lista. Nota: Notaram decerto na utlizao da expresso NULL. Normalmente utiliza-se esta expresso para identificar apontadores que no apontam para nenhuma varivel. De facto, o valor NULL faz exactamente o mesmo efeito que o valor 0(zero). Em vez de Node *proximo = NULL; poderamos fazer Node* proximo = 0;. Dica: A classe n apresenta ainda um construtor. Este construtor tem o papel de se certificar que as variveis so inicializadas com valores nulos. Se no definirmos as variveis, estas assumiro um valor aleatrio, o que poder originar conflitos mais tarde. Este construtor no essencial neste exemplo, porque eu defino as variveis antes de as utilizar, mas em projectos maiores esta pequena linha de cdigo pode dar uma ajuda enorme. Por exemplo, poderamos usar o seguinte cdigo:
if (node == NULL) { cout << "Erro" << endl; } else { cout << node->value << endl; }

Depois de criada a classe, declaramos trs apontadores (com os criativos nomes de "um", "dois" e "tres") e alojamos para cada um deles um objecto do tipo Node na memria dinmica. Neste ponto aconselhava-vos a reverem a aula 14, para relembrarem como funciona a memria dinmica.

Papel dos apontadores e da memria dinmica numa lista


As listas ligadas tm o propsito de facilitar a insero e eliminao de cada n. Como tal, bastante bvio o papel da memria dinmica e apontadores numa lista ligada. No exemplo acima, para inicializar a lista, segui os seguintes passos: Atribui os valores de cada n(value) Liguei o n "dois" ao n "um". Isto feito atravs da atribuio do objecto "dois" ao apontador "proximo", que est dentro do n "um". Assim, podemos dizer que o n que est a seguir ao n "um" o n "dois". Liguei o n "dois" ao n "tres", pelo mesmo processo que acima Defini como NULL o apontador "proximo" do n "tres". Isto significa que no existem mais elementos na lista, ou seja, "tres" o ltimo elemento da lista Para compreendermos melhor a importncia dos apontadores e memria dinmica, demonstrei o caso especfico da eliminao dos ns: Liguei o n "um" ao n "tres". Defini o apontador proximo do n "um" para apontar para o n "tres" (assim o n "tres" passa a ser o n seguinte ao n "um") Eliminamos o n "dois" da memria dinmica, pois este no se torna necessrio para o resto do programa (este passo no necessrio, pois o passo anterior j chega para eliminar o

http://agnor.gamedev-pt.net/gamedev/cpp.html elemento da lista. No entanto bastante aconselhvel este passo, pois assim estaremos a libertar memria) Podem ver a facilidade com que eliminamos um elemento numa lista ligada: basta alterar um apontador no n anterior ao elemento que pretendemos eliminar. Os outros elementos continuam a apontar para os ns seguintes, independentemente da sua localizao.

Percorrer a lista
aqui que se apresenta a desvantagem de uma lista ligada. Num array, cada elemento est organizado na memria: o elemento seguinte est sempre na posio seguinte da memria. Numa lista ligada, cada elemento poder estar disposto em qualquer lugar da memria, dez mil lugares frente ou a um lugar atrs do elemento seguinte. Podero ver esse conceito ilustrado nas tabelas seguintes: Array Endereo 1200 1201 1202 1203 1204 Valor 1 2 3 4 5 Lista Ligada Endereo 1200 1201 1202 1203 1204 1205 1206 1207 1208 Valor 4 --- 2 --- 5 3 --- --- 1 Prximo (Aponta para) 1204 --- 1205 --- NULL 1200 --- --- 1202 Nota: Os "buracos" (---) em alguns endereos na lista ligada significam endereos que so ocupados por outras variveis e serve para ilustrar a "desordem" de uma lista. Num programa, esses "buracos" tambm existiriam num array (embora depois ou antes de todo o array e nunca entre cada elemento do array). Esta nota s para no ficarem com a ideia que as listas ocupam mais memria de que um array (na verdade ocupam, pois possuem mais uma varivel que um array: um apontador. No entanto este aumento desprezvel). Como tal, muito mais fcil (e eficiente) aceder a um elemento de um array do que um elemento de uma lista. Isto porque, se quisermos aceder quarta posio de um array fazemos array[3] (ou array+3). Com esta instruo, vai ser procurado o 3 elemento direita do primeiro. Para acedermos ao quarto elemento de uma lista teramos que fazer: head->proximo->proximo->proximo, em que head o primeiro elemento da lista. At aqui no perdemos muito em eficincia, mas se quisermos consultar o x elemento de uma lista, o caso muda de figura. Enquanto isso num array seria to simples como array[x], numa lista teramos que recorrer a algo como:
int getValue(int x, Node* head) { Node* temp = head; for (int i = 0; i < x; i++) { temp = temp->proximo; } return temp->value; }

O simples uso do for faz com que isto fique muito mais ineficiente do que um simples array[3];

http://agnor.gamedev-pt.net/gamedev/cpp.html

Classe Lista
Como esta aula j foi muito longa (e porque o cdigo para uma Lista um pouco grande), decidi colocar a classe lista junto com o cdigo fonte desta aula, em vez de ocupar ainda mais espao nesta pgina. Penso que seja fcil de entender, pelo menos se perceberam o cdigo acima (e est muito comentado). Mesmo cobrindo tantos aspectos destas simples estruturas de dados, isso ainda no chega. Na prxima aula irei introduzir o conceito de iterador e irei mostrar a classe List, da STL. Espero tambm poder introduzir a estrutura de dados "rvore binria", assim como alguns algoritmos simples de procura. Final da aula 19 de C++: Prxima aula -> C++ 20 - Tcnicas Avanadas de C++ - Parte 4 Fazer o download do cdigo fonte dos exemplos da aula Fazer o download da aula em PDF (Brevemente) Ir para o topo da pgina

Aula 20 - Tcnicas Avanadas de C++ - Parte IV


<!-google_ad_client = "pub-9639791948153775"; google_ad_width = 336; google_ad_height = 280; google_ad_format = "336x280_as"; google_ad_type = "text"; google_ad_channel ="3703014365"; google_color_border = "FFFFFF"; google_color_bg = "FFFFFF"; google_color_link = "0000FF"; google_color_url = "000000"; google_color_text = "000000"; //-->Conceitos-Chave: - iterador, uma varivel que permite percorrer os elementos de um contentor, de forma abstracta e genrica - list, uma estrutura de dados da STL, que possui uma mecnica idntica a uma lista duplamente ligada - pr-processador, um componente do C++ que processa o texto recebido e inclui os seus resultados no prprio ficheiro

Iteradores
Antes de avanar para a classe list da STL importante saber trabalhar com iteradores. At agora temos usado o operador de indexao ('[]') para obter os valores das variveis dentro dos vectores, como fazamos com os arrays. A STL desencoraja esta forma de aceder aos elementos dos seus contentores (um contentor um objecto que tem a funo de alojar outros objectos, como a classe vector e list da STL). Encoraja sim a utilizao dos iteradores, que so muito semelhantes aos apontadores. Na aula 14 analisamos as semelhanas entre um apontador e um array:
#include <iostream>

http://agnor.gamedev-pt.net/gamedev/cpp.html
using namespace std; int main() { int *array_pointer = new int[5];

//cria um novo array na memria dinmica

int *array_begin = array_pointer; /* Criamos um apontador e depois atribuimos-lhe o endereo do array que criamos anteriormente. No se esqueam que o array_pointer aponta para o primeiro elemento das 5 variveis que criamos na memria dinmica. Assim, a varivel array_begin est a apontar para o primeiro elemento deste array, ou seja, sinaliza o comeo do mesmo. */ int *array_end = array_pointer+5; //usando a mesma lgica, o array_end aponta para o 5 elemento do array (ltimo) int *array_iterator; //este o nosso iterador, o apontador que ir percorrer o array /* Esta parte est explicada abaixo (fora do cdigo) */ for (array_iterator = array_begin; array_iterator != array_end; array_iterator++) { *array_iterator = 10; //s serve para encher o array com o valor 10 } for (array_iterator = array_begin; array_iterator != array_end; array_iterator++) { cout << *array_iterator << endl; //mostra os valores } cin.get(); delete [] array_pointer; } return 0; //elimina o array da memria dinmica

Exemplo 20.1 - Exemplo primitivo de um iterador Ufa, admito que este cdigo no seja muito fcil de compreender (para alm de haver outras solues muito mais fceis de implementar), mas necessrio para poderem perceber como funcionam os iteradores dentro da STL. Toda a mecnica est volta das operaes com o endereo com apontadores, por isso revejam a aula 14. Comearei para explicar o que precisamos para utilizar um iterador: um apontador para o incio do "contentor" (neste caso o array) um apontador para o final do "contentor" um apontador que percorra o "contentor" do incio ao fim (o iterador) No exemplo acima usmos esses componentes e implementmo-los atravs de um for. A primeira instruo dada ao for (array_iterator = array_begin) corresponde inicializao, ou

http://agnor.gamedev-pt.net/gamedev/cpp.html seja, estamos a "dizer" ao iterador em que posio na memria dever comear para percorrer o contentor. Na segunda instruo, o teste condio (array_iterator != array_end), pedimos ao computador para, enquanto o array_iterator for igual ao array_end (ou seja, enquanto o iterador no chegar ao final) processar o bloco de instrues (*array_iterator = 10) e para executar a terceira instruo, a instruo de incremento (array_iterator++), que faz com que o iterador passe a apontar para o elemento seguinte. Foi o melhor que consegui explicar esta mecnica, mas qualquer dvida e contactem-me

Iterador num vector


Para aplicar os iteradores "vida real" vou mostrar o mesmo exemplo, mas usando vectores.
#include <iostream> #include <vector> using namespace std; int main() { vector <int> meu_array; vector <int>::iterator meu_iterador; //ok, esta notao estranha, mas faz sentido ;) meu_array.push_back(10); //vamos aproveitar as facilidades do vector! meu_array.push_back(20); meu_array.push_back(30); meu_array.push_back(20); meu_array.push_back(10); for (meu_iterador = meu_array.begin(); meu_iterador != meu_array.end(); meu_iterador++) { cout << *meu_iterador << endl; } cin.get(); } return 0;

Exemplo 20.2 - Exemplo de um iterador na STL (classe vector)

Porque que os iteradores so importantes?


Numa classe como a vector, os iteradores no so muito importantes, porque podemos usar o operador '[]'. No entanto, em classes como a classe list (que iremos analisar de seguida), no poderemos aceder aos seus elementos de forma aleatria (com o []), porque se trata de uma lista ligada (ver a aula anterior). A STL apresenta outro tipo de contentores que no consegue aceder aos seus elementos aleatoriamente e, por isso, colocaram a hiptese dos iteradores em todos os seus contentores. Os iteradores so a forma "oficial" da STL para percorrermos os contentores, porque a STL foi feita para ser genrica e abstracta, ou seja, o programador no tem que se preocupar em usar diferentes formas de aceder a cada contentor da STL, porque os iteradores abrangem todas

http://agnor.gamedev-pt.net/gamedev/cpp.html essas formas. Tambm muitos mtodos dentro da STL tiram partido dos iteradores, por exemplo, dentro da classe vector poderemos utilizar o seguinte cdigo para eliminar os 2 primeiros elementos de um array: meu_array.erase(meu_array.begin(), meu_array.begin()+3); Outra coisa que importante assinalar que os iteradores diferem ligeiramente de contentor para contentor. Por exemplo, enquanto com o vector possvel fazer (teste.begin()+2), com a list isso no possvel ( apenas possvel incrementar(++) e decrementar(--)), portanto no podemos reutilizar um iterador de um vector com uma lista.

Classe list
Se j trabalharam com a classe vector e entenderam pelo menos o bsico dos iteradores, ento vai ser muito fcil trabalhar com as listas. Uma das vantagens da STL que trabalhar os contentores, em termos de sintaxe e organizao, so muito semelhantes, diferendo apenas naquilo em que mesmo necessrio. Desta forma, a escolha de um contentor no se prende com a facilidade de utilizao do mesmo, mas sim com a adequao do mesmo ao nosso trabalho. por isso que a STL to boa :D.
#include <iostream> #include <list> using namespace std; int main() { list <int> minha_lista; list <int>::iterator meu_iterador; minha_lista.push_back(20); //inserimos um elemento no final da lista (isto igual ao vector) minha_lista.push_back(30); minha_lista.push_front(0); //inserimos um elemento no incio da lista sem nenhum esforo para o programador e para o computador minha_lista.insert(++minha_lista.begin(), 10); //inserimos um elemento na posio 1 da lista (entre o 0 e o 20) //isto j seria impossvel num vector, sem gastar muitos recursos h mquina for (meu_iterador = minha_lista.begin(); meu_iterador != minha_lista.end(); meu_iterador++) { cout << *meu_iterador << endl; } cin.get(); } return 0;

Exemplo 20.3 - Exemplo simples com a classe list da STL Penso que o cdigo bastante simples de perceber e evidencia logo as diferenas entre o vector e a list. Nota:

http://agnor.gamedev-pt.net/gamedev/cpp.html De certeza que j me viram utilizar o operador de incrementao (++) antes e depois de cada varivel, por exemplo i++ ou ++i. H uma pequena diferena entre as duas e que por acaso at importante neste exemplo (na parte da ++minha_lista.begin()). Fazer i++ faz com que seja executado em primeiro lugar a instruo em que o i++ est inserido e s depois que incrementa a varivel, enquanto fazer ++i faz com que primeiro incremente a varivel e s depois execute a instruo em que est inserido o ++i. Com um exemplo fcil de perceber: int i = 3; cout << i++; // o valor apresentado vai ser '3' cout << i; // o valor apresentado vai ser '4' cout << ++i; // o valor apresentado vai ser '5' Isto vem a propsito da instruo ++minha_lista.begin(), que eu acidentalmente escrevi minha_lista.begin()++ e que, por isso, no fez nenhum efeito (experimentem utiliz-la deste modo)

Aceder aos elementos de uma lista


Como j expliquei, no possvel fazer minha_lista.begin()+2 para aceder ao 3 elemento de uma lista (no se esqueam que minha_lista.begin() o primeiro elemento e por isso, ao adicionarmos 2, ele passa para o 3 e no para o 2!). No entanto possvel fazer incrementos a um iterador at chegar a esse valor. Claro que isto demora mais tempo do que o acesso aleatrio dos vectores, mas j expliquei as vantagens e desvantagens das listas na aula anterior. O contentor list apresenta a mecnica de uma lista duplamente ligada, por isso permite que percorramos os seus elementos para a frente (iterador_lista++) ou para trs (iterador_lista--). Fiquem com este exemplo bastante simples:
#include <iostream> #include <list> using namespace std; int main() { list <int> minha_lista; list <int>::iterator meu_iterador; int e; //usado para a escolha do utilizador minha_lista.push_back(10); minha_lista.push_back(20); minha_lista.push_back(30); minha_lista.push_back(40); minha_lista.push_back(50); minha_lista.push_back(60); meu_iterador = minha_lista.begin(); cout << "Deseja aceder a que elemento da lista? [0-5]: [ ]\b\b"; //o \b o carcter especial de retrocesso, ou seja, posiciona o cursor 2 caracteres antes de onde suposto //d um efeito mais agradvel :) cin >> e; for (int x = 0; x < e; x++) {

http://agnor.gamedev-pt.net/gamedev/cpp.html
meu_iterador++; } cout << "Valor: " << *meu_iterador << endl; cin.get(); cin.get(); return 0; }

Exemplo 20.4 - Aceder "aleatoriamente" aos valores de uma lista

O pr-processador em C++
O pr-processador em C++ faz com que um determinado texto seja processado e inserido no documento. algo bastante simples de utilizar e que era usado frequentemente em C, mas agora j se encontra algo desactualizado. No entanto, bastantes programadores ainda o usam e importante conhec-lo. Todos os comandos do pr-processador incluem antes um '#'.

#include
Este o comando mais usado em C++ e faz coisas incrveis. Basicamente copia todo o cdigo de um determinado ficheiro para o ficheiro em que esta instruo est presente, o que faz com que o cdigo fique muito mais lindo e organizado. Pode ser utilizado de duas formas: #include <ficheiro.h> para ficheiros do sistema, como iostream, etc. #include "ficheiro.h" para ficheiros criados por vocs.

#define
O #define substitui "palavras por nmeros", actuando como uma constante. Por exemplo: #define PI 3.14159 Substitui todas as "palavras" PI dentro do cdigo (menos as que esto dentro das strings) pelo valor 3.14159. Ainda bastante utilizado, mas desaconselhado, porque em C++ existe o tipo const, que funciona muito melhor. Tambm possvel utilizar os defines como uma funo (chama-se a isso uma macro), por exemplo: #define soma(a,b) a+b Novamente, declarar as funes como inline tem o mesmo efeito, e muito melhor ( inline int soma (int a, int b) { return a+b; } ) Dica: Declarar uma classe como inline faz com que todas as chamadas a essa funo sejam substitudas pelo cdigo da mesma. Por exemplo, com a funo soma acima, o cdigo soma(3,7) seria substitudo por 3+7. Com isto h um ganho na velocidade de processamento, mas uma perda no

http://agnor.gamedev-pt.net/gamedev/cpp.html tamanho do programa. Funes pequenas (como a funo soma) so aconselhadas para serem declaradas como inline, mas funes mais complexas no!

#ifdef, #ifndef, #endif


Estas so teis em headers e em casos especficos (como para debug e assim). O #include no perfeito, uma das suas limitaes no verificar se um determinado ficheiro j foi incluido no programa, de modo a evitar que este seja includo mais que uma vez. O #ifndef permite-nos artificialmente verificar isso: #ifndef FICHEIRO_JA_FOI_INCLUIDO //se ainda no foi definido isto (ou seja, se o ficheiro ainda no foi includo) #define FICHEIRO_JA_FOI_INCLUIDO // cdigo aqui #endif Outra coisa interessante por exemplo uma verificao do sistema operativo: #ifdef WINDOWS #include "headersparawindows #endif #ifdef LINUX #include "headersparalinux #endif Isto poderia ser utilizado para outros casos, como um modo de debug, onde nos bastara escrever #define DEBUG_MODE e o programa recompilava para nos oferecer instrues detalhadas de como cada elemento do jogo se est a comportar.

E agora?
As aulas tericas de C++ deste site j terminaram! Para os acompanhantes do website, podem ficar descansados, ainda esto previstas mais 5 aulas prticas, que iro mostrar como construir (bem) um jogo. O jogo continuar a ser em modo de texto, mas penso que iro ficar contentes com o resultado! No entanto, ainda preciso muito para ser um "mestre" em C++ (o que nem eu, de longe, sou). H bastante informao na Internet e em livros de boas prticas em C++, assim como de mais algoritmos, estruturas de dados e de muito C++ avanado. No entanto, penso que as bases j esto dadas, e o resto vir como "acrscimos" vossa capacidade. Deixo-vos alguns websites e livros para material de "self-study" (em Ingls a sua maioria, infelizmente):

Livros
Programao em C++ - Conceitos Bsicos e Algoritmos, vrios autores - Livro em Portugus que serve de introduo a C++ (FCA, FNAC, Bertrand) Effective C++, Scott Meyers - 55 dicas para melhorar a vossa forma de programar em C++ (Amazon.co.uk, Amazon.com ) More Effective C++, Scott Meyers - A continuao do anterior, com mais 35 dicas (Amazon.co.uk, Amazon.com ) Effective STL, Scott Meyers - 50 dicas para melhorar a vossa forma de programar com a STL (Amazon.co.uk, Amazon.com ) C++ for Game Programmers, Mike Dickheiser - Livro que mostra ao programador com

http://agnor.gamedev-pt.net/gamedev/cpp.html experincia em C++ como utiliz-la para programar jogos (Amazon.co.uk, Amazon.com ) Beginning C++ Game Programming, Michael Dawson - Ensina C++ ao iniciante, recorrendo a exemplos de jogos (Amazon.co.uk, Amazon.com ) Design Patterns: Elements of Reusable Object-Oriented Software, vrios autores - Este livro ensina-nos como implementar as melhores formas de abordar certos problemas, atravs da POO (Amazon.co.uk, Amazon.com )

Websites
Tutorial de C++ do Pedro Santos C++ Language Tutorial CProgramming.com SGI - STL Programmer's Guide C++ Reference

E por ltimo, mas no menos importante, websites com bastantes recursos (inclundo frums) que vos vo ajudar bastante (ajudaram-me muito e tenho uma dvida especial com eles): Gamedev.net (Ingls) Gamedev-PT (Portugal) PDJ (Brasil) Unidev (Brasil)

Final da aula 20 de C++: Prxima aula -> C++ P1 - Fazendo um jogo do princpio ao fim - Parte 1 Fazer o download do cdigo fonte dos exemplos da aula Fazer o download da aula em PDF (Brevemente) Ir para o topo da pgina

Potrebbero piacerti anche