Capitulo 06 - Funções e uma Introdução a Recursão
A melhor maneira de desenvolver e manter um programa grande é construí-lo a partir de pequenas e simples partes ou componentes, chamamos esta técnica de Dividir Para Conquistar, introduzimos funções como partes do programa, como já visto no Capítulo 3. Neste capitulo vamos estudar as funções como mais profundidade, veremos como declarar e utilizar funções para facilitar o projeto, a implementação, a operação e a manutenção de grandes programas.
Exemplo 01 , 02 e 03:
Na figura 6.3 de NotasFuncaoLivro.h, nesse programa dentro da classe NotasFuncaoLivro declaramos os protótipos da função-membro que depois serão definidas no NotasFuncaoLivro.cpp
//Figura 6.3: NotasFuncaoLivro.h
#include <string> //o construtor inicializa o nome do curso
using std::string;
//definicao da classe NotasFuncaoLivro
class NotasFuncaoLivro
{
public:
NotasFuncaoLivro(string); //o construtor inicializa o nome do curso
void setNomeCurso(string); //funcao para configurar o nome do curso
string getNomeCurso(); //funcao para recuperar nome do curso
void telaMensagem(); //exibe mensagem de boas vindas
void inputNotas(); //insere tres notas fornecidas pelo usuario
void telaNotasRelatorio(); //exibe um relatorio baseado nas notas
int maximo(int, int, int); //determina o maximo de 3 valores
private:
string nomeCurso; //nome do curso para essa NotasFuncaoLivro
int estudanteMaximo; //maxima de tres notas
};
Na proxima figura do exemplo declaramos uma NotasFuncaoLivro onde serão declaradas todas as funções-membros para o calculo de tres notas
//Figura 6.4.NotasFuncaoLivro.cpp
#include <iostream>
#include <string>
#include "NotasFuncaoLivro.h" //inclue a definicao de classe NotasFuncaoLivro
using std::cout;
using std::cin;
using std::endl;
/*
construtor inicializa nomeCurso com string fornecido como argumento;
inicializa estudanteMaximo como 0
*/
NotasFuncaoLivro::NotasFuncaoLivro(string nome)
{
setNomeCurso(nome); //valida e armazena NomeCurso
estudanteMaximo = 0; //esse valor sera substituido pela nota maxima
}
//funcao para configurar o nome do curso; limita o nome a 25 ou menos caracteres
void NotasFuncaoLivro::setNomeCurso(string nome)
{
if(nome.length() <= 25) //se o nome tiver 25 ou menos caracteres
nomeCurso = nome; //armazena o nome do curso no objeto
else
{
//configura nomeCurso como os primeiros 25 caracteres do nome de parametro
nomeCurso = nome.substr(0.25); //seleciona os primeiros 25 caracteres
cout << "Nome\"" << nome << "\" excede limite maximo (25).\n"
<< "Limite nomeCurso dos 1ºs 25 caracteres.\n" << endl;
} //fim do if...else
} //fim da funcao setNomeCurso
//funcao para recuperar o nome do curso
string NotasFuncaoLivro::getNomeCurso()
{
return nomeCurso;
} //fim da funcao getNomeCurso
//exibe uma mensagem do boas vindas para o usuario de NotasLivro
void NotasFuncaoLivro::telaMe}nsagem()
{
/*
esse instrucao chama getNomeCurso para obter o
nome do curso que esse NotasLivro representa
*/
cout << "Bem vindo a notas livro de\n" << getNomeCurso() << "!\n" << endl;
} //fim da funcao telaMensagem()
//insere numero arbitrario de notas fornecidas pelo usuario; atualizando o contador de notas
void NotasFuncaoLivro::inputNotas()
{
int nota1; //primeira nota inserida pelo usuario
int nota2; //segunda nota inserida pelo usuario
int nota3; //terceira nota inserida pelo usuario
cout << "Entre com tres numero inteiros: ";
cin >> nota1 >> nota2 >> nota3;
//armazena maxima no membro estudanteMaximo
estudanteMaximo = maximo(nota1, nota2, nota3);
} //fim da funcao inputNotas
//retorna o maximo dos seus tres parametros inteiros
int NotasFuncaoLivro::maximo(int x, int y, int z)
{
int maximoValor = x; //supoe que x e o maior valor inicial
//determina se y e maior que maximoValor
if(y > maximoValor)
maximoValor = y; //torna y o novo maximoValor
//determina se z e o maior que maximoValor
if(z > maximoValor)
maximoValor = z; //torna z o novo maximoValor
return maximoValor;
} //fim da funcao maximo
//exibe um relatorio baseado nas notas inseridas pelo usuario
void NotasFuncaoLivro::telaNotasRelatorio()
{
//gera saida de notas maximas entre as notas inseridas
cout << "Maximo de notas inseridas foi: " << estudanteMaximo << endl;
} //fim da funcao telaNotaRelatorio
Figura 6.5 do programa NotasFuncaoLivroMain.cpp onde cria o objeto e insere notas e exibe relatorio de notas
//figura 6.5 NotasFuncaoLivroMain.cpp
#include "NotasFuncaoLivro.cpp"
int main()
{
//cria objeto NotasLivro
NotasFuncaoLivro minhaNotasFuncaoLivro("C++ Como Programar");
minhaNotasFuncaoLivro.telaMensagem(); //exibe a mensagem de boas vindas
minhaNotasFuncaoLivro.inputNotas(); //le as notas fornecidas pelo usuário
minhaNotasFuncaoLivro.telaNotasRelatorio(); //exibe relatório baseado em notas
return 0; //indica terminacao bem sucedida
}
Cria o objeto NotasFuncaoLivro, insere as notas e exibe relatório de notas e na tela o resultado sera assim:
No próximo programa exemplo da figura 6.8 FuncaoRand usaremos a função para simular 20 lançamentos de um dado de seis lados e imprimir o valor de cada lançamento. O prototipo de função para a função rand está em <cstdlib>. Para produzir inteiros no intervalo de 0 a 5, utilizamos o operador módulo (%) com rand como voces verão no programa a seguir:
//figura 6.8: FuncaoRand.cpp
#include <iostream>
#include <iomanip>
#include <cstdlib>
using std::cout;
using std::endl;
using std::setw;
using std::rand;
int main()
{
//itera 20 vezes
for(int cont = 1; cont <= 20; cont++)
{
//escolhe um numero aleatorio de 1 a 6 e o envia para saida
cout << setw(10) << (1 + rand() % 6);
//se o comntador for divisivel por 5, inicia uma nova linha de saida
if(cont % 5 == 0)
cout << endl;
} //fim do for
return 0; //indica terminacao bem sucedida
}
executando o programa ficará assim na tela:
No programa da figura 6.9: FuncaoRand2.cpp o programa ira lança um dado de seis dados
6.000.000 vezes, usando uma variavel inteira chamada frequencia que ira ler a contagem de dados lançados e a variavel face que iura armazenar o valor lançado recentemente usando um for e dentro do for um switch para incrementar a variavel frequencia como um contador da quantidade de vezes que o dado foi lançado.
//figura 6.9: FuncaoRand2.cpp
#include <iostream>
#include <iomanip>
#include <cstdlib>
using std::cout;
using std::endl;
using std::setw;
using std::rand;
int main()
{
int frequencia1 = 0; //contagem de 1s lancados
int frequencia2 = 0; //contagem de 2s lancados
int frequencia3 = 0; //contagem de 3s lancados
int frequencia4 = 0; //contagem de 4s lancados
int frequencia5 = 0; //contagem de 5s lancados
int frequencia6 = 0; //contagem de 6s lancados
int face; //armazena o valor lancado mais recentemente
//itera 20 vezes
for(int lista = 1; lista <= 6000000; lista++)
{
face = 1 + rand() % 6; //numero aleatorio de 1 a 6
//determina valor de lancamento de 1 a 6 e incrementa o contador apropriado
switch(face)
{
case 1:
++frequencia1; //incrementa o contador de 1s
break;
case 2:
++frequencia2; //incrementa o contador de 2s
break;
case 3:
++frequencia3; //incrementa o contador de 3s
break;
case 4:
++frequencia4; //incrementa o contador de 4s
break;
case 5:
++frequencia5; //incrementa o contador de 5s
break;
case 6:
++frequencia6; //incrementa o contador de 6s
break;
default: //valor invalido
cout << "Programa nunca deve chegar aqui!";
} //fim do switch
} //fim do for
cout << "Face" << setw(13) << "Frequencia" << endl; //cabecalho de saida
cout << " 1" << setw(13) << frequencia1
<< "\n 2" << setw(13) << frequencia2
<< "\n 3" << setw(13) << frequencia3
<< "\n 4" << setw(13) << frequencia4
<< "\n 5" << setw(13) << frequencia5
<< "\n 6" << setw(13) << frequencia6 << endl;
return 0; //indica terminacao bem sucedida
} //fim do main
ao executar o programa sera mostrado na tela a contagem de dados que foi lançada:
Proximo programa da figura 6.10 FuncaoSRand usaremos a funcao srand para a contagem de sementes que serão inseridas pelo usuário ao digitar
//figura 6.10: FuncaoSRand.cpp
#include <iostream>
#include <cstdlib> //contem os prototipos para funcoes srand e rand
#include <iomanip>
using std::cout;
using std::cin;
using std::endl;
using std::rand;
using std::srand;
using std::setw;
int main()
{
unsigned semente; //armazena a semente inserida pelo usuario
cout << "Enter semente: ";
cin >> semente;
srand(semente); //semeia o gerador de numeros aleatorios
//itera 10 vezes
for(int cont = 1; cont <= 10; cont++)
{
//escolhe um numero aleatorio de 1 a 6 e o envia para a saida
cout << setw(10) << (1 + rand() % 6);
//se o contador for divisivel por 5, inicia uma nova linha de saida
if(cont % 5 == 0)
cout << endl;
} //fim do for
return 0; //indica terminaco bem sucedida
}
ao executar aparecera na tela:
Agora no proximo programa da figura 6.11 vamos mostrar uma simulação de jogo de dados onde usaremos time para mostrar o status quando cada vez o jogador lançar os dados.
//figura 6.11: JogoDeDados.cpp
#include <iostream>
#include <ctime>
#include <cstdlib>
using std::cout;
using std::endl;
using std::rand;
using std::srand;
int rolarDados(); //lanca o dado, calcula e exibe a soma
int main()
{
//enumeracao com constantes que representam os status do jogo
enum Posicao{CONTINUA, GANHOU, PERDEU}; //todas as maiusculas em constantes
int meusPontos; //pontos se nao ganhar ou perder na primeira rolagem
Posicao jogoPosicao; //pdoe conter CONTINUAR, GANHOU ou PERDEU
//torna aleatorio o gerador de numeros aleatorios utilizando a hora atual
srand(time(0));
int somaDoDado = rolarDados(); //primeira rolagem de dados
//determina status e pontuaao do jogo (se necessario) com base no primeiro lancamento de dados
switch(somaDoDado)
{
case 7: //ganha cok 7 no primeiro lancamento
case 11:
jogoPosicao = GANHOU;
break;
case 2: //perde com 2 no primiero lancamento
case 3: //perde com 3 no primeiro lancamento
case 12: //perde com 12 no primiro lancamento
jogoPosicao = PERDEU;
break;
default: //nao ganhou nem perdeu, portanto registra a pontuacao
jogoPosicao = CONTINUA; //jogo nao terminou
meusPontos = somaDoDado; //informa a pontuacao
cout << "Ponto foi = " << meusPontos << endl;
break;
} //fim do switch
//enquanto o jogo nao estiver completo
while(jogoPosicao == CONTINUA) //nem GANHOU nem PERDEU
{
somaDoDado = rolarDados(); //lanca os dados novamente
//determina o status do jogo
if(somaDoDado == meusPontos) //vitoria por pontuacao
jogoPosicao = GANHOU;
else
if(somaDoDado == 7) //perde obtendo 7 antes de antingir pontuacao
jogoPosicao = PERDEU;
} //fim do while
//exibe uma mensagem que ganhou ou perdeu
if(jogoPosicao == GANHOU)
cout << "Jogador Ganhou" << endl;
else
cout << "jogador Perdeu" << endl;
return 0; //indica terminacao bem-sucedida
} //fim do main
//lanca dados, calcula a soma e exibe os resultados
int rolarDados()
{
//seleciona valores aleatorios do dado
int dado1 = 1 + rand() % 6; //primneiro lanchamento de dado
int dado2 = 1 + rand() % 6; //segundo lancamento do dado
int soma = dado1 + dado2; //calcula a soma dos valores do dado
//exibe os resultados desse lancamento
cout << "Jogador rolou dado " << dado1 << " + " << dado2
<< " = " << soma << endl;
return soma; //fim da funcao rolarDado
} //fim da funcao rolarDado
Na tela abaixo sera mostrado na dela dessa maneira:
No Programa da figura 6.12 veremos um exemplo de escopo, por exemplo quando declaramos uma variavel local em um bloco, ela pode ser referenciada apenas nesse bloco e nos blocos aninhados dentro desse bloco. Veremos 4 tipos de escopos para um identificador: escopo de função, escopo de arquivo e escopo de protótipo de função, mais adiante veremos escopo de classe e escopo de namespace .
//figura 6.12: FuncaoEscopo.cpp
#include <iostream>
using std::cout;
using std::endl;
void useLocal(void); //prototipo de funcao
void useStaticLocal(void); //prototipo de funcao
void useGlobal(void); //prototipo de funcao
int x = 1; //variavel global
int main()
{
int x = 5; //variavel local para main
cout << "Local x principal no escopo externo foi: " << x << endl;
{ //inicia novo escopo
int x = 7; //oculta x no escopo externo
cout << "Local x principal no escopo interno foi: " << x << endl;
} //fim do novo escopo
cout << "Local x principal no escopo externo foi: " << x << endl;
useLocal(); //useLocal tem uma variavel local x
useStaticLocal(); //useStaticLocal tem x estatico local
useGlobal(); //useGlobal utiliza x global
useLocal(); //useLocal reinicializa seu x local
useStaticLocal(); //x estatico local retem seu valor anterior
useGlobal(); //x global também retem seu valor
cout << "\nLocal x principal e: " << x << endl;
return 0; //indica terminacao bem sucedida
}
//useLocal reinicializa a variavel local x durante cada chamada
void useLocal(void)
{
int x = 25; //inicializa toda vez que useLocal e chamada
cout << "\nLocal x e: " << x << " entra com useLocal" << endl;
x++;
cout << "Local x e: " << x << " entra com useLocal" << endl;
} //fim da funcao useLocal
/**
useStaticLocal inicializa a variavel estaica local x somente
na primeira vez em que a funcao e chamada; o valor de x e salvo
entre as chamadas a essa funcao
**/
void useStaticLocal(void)
{
static int x = 50; //incializada na primeira vez em que useStaticLocal e chamada
cout << "\nLocal estatico x e: " << x << " a entra useStaticLocal" << endl;
x++;
cout << "\nLocal estico x e: " << x << " a existir useStaticLocal" << endl;
} //fim da funcao useStaticLocal
//useGlobal modifica a variavel global x durante cada chamada
void useGlobal(void)
{
cout << "\nGlobal x e: " << x << " a entrar useGlobal" << endl;
x *= 10;
cout << "Global x e: " << x << " a existir userGlobal" << endl;
} //fim da funcao useGlobal
Ao executar o programa ficara assim na tela:
No próximo programa da figura 6.13 iremos mostrar uma função quadrado utilizada para demonstrar a pilha de chamadas de função e os arquivos de ativação.
//figura 6.13: FuncaoQuadrado.cpp
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
int quadrado(int); //protoipo para funcao quadrado
int main()
{
int a = 10; //valor para quadrado (variavel automatica local em main)
cout << a << " Quadrado: " << quadrado(a) << endl; //exibe o quadrado em um int
return 0; //indica terminacao bem-sucedia
} //fim do main
//retorna o quadrado de um inteiro
int quadrado(int x)
{
return x * x; //calcula quadrado e retorna o resultado
}
ao executar o programa ficara assim na tela:
No programa da figura 6.18: utilizaremos uma função inline para calcular o volume de um cubo.
//figura 6.18: FuncaoInline.cpp
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
/**
Definicao da funcao inline cube. A definicao de funcao aparece antes
de a funcao ser chamada, entao um prototipo de funcao nao e necessario.
A peimeira linha da definicao atua como o prototipo.
**/
inline double cubo(const double lado)
{
return lado * lado * lado; //calcula o cubo
} //fim da funcao cubo
int main()
{
double ladoValor; //armazena o valor do lado inserido pelo usuario
cout << "digite o comprimento do cubo: ";
cin >> ladoValor; //le o valor fornecido pelo usuario
//calcula o cubo de ladoValor e exibe o resultado
cout << "Volume do cubo de lado "
<< ladoValor << " = " << cubo(ladoValor) << endl;
return 0; //indica terminacao bem-sucedida
} //fim de main
No proximo programa da figura 6.24 veremos a função sobrecarregada calculando a função de um quadrado de inteiro e um quadrado de double.
//figura 6.24: FuncoesSobrecarregadas.cpp
#include <iostream>
using std::cout;
using std::endl;
//funcao quadrado para valores int
int quadrado(int x)
{
cout << "Quadrado de inteiro " << x << " = ";
return x * x;
} //fim da funcao quadrado com argumento int
//funcao quadrado para valores double
double quadrado(double y)
{
cout << "Quadrado de double " << y << " = ";
return y * y;
} //fim da funcao quadrado com argumentos double
int main()
{
cout << quadrado(7); //chama versao int
cout << endl;
cout << quadrado(7.5); //chama versao double
cout << endl;
return 0; //indica terminaçao bem sucedida
} //fim de main
ao executar aparecera da seguinte forma na tela:
No programa da figura 6.26 veremos templates de funções em que a logica e as operações forem identicas para cada tipo de dados, sobrecarga pode ser realizada de forma compacta e conveniente utilizando templates de função, onde o programador escreve em uma unica definição de template de função. C++ gera automaticamente especificações de template da função separadas para tratar cada tipo de chamada de maneira adequada.
//figura 6.26: Maximo.h
template <class T> //ou template<typename T>
T maximo(T valor1, T valor2, T valor3)
{
T maximoValor = valor1; //pressupoe que valor1 e maximo
//determinba se valor2 e maior que maximoValor
if(valor2 > maximoValor)
maximoValor = valor2;
//determina se valor3 e maior que maximoValor
if(valor3 > maximoValor)
maximoValor = valor3;
return maximoValor;
} //fim do template de funcao maximo
//figura 6.27: MaximoMain.cpp
#include <iostream>
#include "Maximo.h" //inclui a definicao do template de funcao maximo
using std::cout;
using std::cin;
using std::endl;
int main()
{
//demonstra maximo com valores int
int int1, int2, int3;
cout << "Entre com tres valores de inteiros: ";
cin >> int1 >> int2 >> int3;
//invoca a versao int de maximo
cout << "O valor maximo de inteiro = "
<< maximo(int1, int2, int3);
//demonstra maximo com valores double
double double1, double2, double3;
cout << "\n\nEntre com tres valores double: ";
cin >> double1 >> double2 >> double3;
//invoca a versao double de maximo
cout << "O maximo valor de double = " << maximo(double1, double2, double3);
//demonstra maximo com valores de char
char char1, char2, char3;
cout << "\n\nEntre com tres caracteres: ";
cin >> char1 >> char2 >> char3;
//invoca versao char de maximo
cout << "O maximo valor de caracteres = "
<< maximo(char1, char2, char3);
return 0; //indica terminacao bem-sucedida
} //fim de main
ao compliar e executar o programa:
No proximo programa da figura: 6.29 iremos fazer o calculo de uma função fatorial recursiva
//figura 6.29: FuncFatorialRecursiva.cpp
#include <iostream>
#include <iomanip>
using std::cout;
using std::endl;
using std::setw;
unsigned long fatorial(unsigned long); //prototipo de funcao
int main()
{
//calcula o fatorial de 0 a 10
for(int contador = 0; contador <= 10; contador++)
cout << setw(2) << contador << "! = " << fatorial(contador) << endl;
return 0; //indica terminacao bem-sucedida
} //fim do main
//definicao recursiva da funcao fatorial
unsigned long fatorial(unsigned long numero)
{
if(numero <= 1) //testa caso basico
return 1; //casos basicos: 0! = 1 e 1! = 1
else //passo de recursao
return numero * fatorial(numero - 1);
} //fim da funcao fatorial
ao executar na tela ficara dessa maneira:
//figura 6.30:FuncFibonacciRecursiva.cpp
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
unsigned long fibonacci(unsigned long); //prototipo de funcao
int main()
{
//calcula os valores de fibonacci de 0 a 10
for(int contador = 0; contador <= 10; contador++)
cout << "fibonacci(" << contador << " ) = "
<< fibonacci(contador) << endl;
//exibe valores fibonacci mais alto
cout << "fibonacci(20) = " << fibonacci(20) << endl;
cout << "fibonacci(30) = " << fibonacci(30) << endl;
cout << "fibonacci(35) = " << fibonacci(35) << endl;
return 0; //indica terminacao be-sucedida
} //fim do main
//funcao fibonaci recursiva
unsigned long fibonacci(unsigned long numero)
{
if((numero == 0) || (numero == 1)) //casos basicos
return numero;
else //passo de recursao
return fibonacci(numero - 1) + fibonacci(numero - 2);
} //fim da funcao fibonacci
compliando e executando o resultado sera este:
//figura 6.32: FuncFatorialIterativa.cpp
#include <iostream>
#include <iomanip>
using std::cout;
using std::endl;
using std::setw;
unsigned long fatorial(unsigned long); //prototipo de funcao
int main()
{
//calcula o fatorial de 0 a 10
for(int contador = 0; contador <= 10; contador++)
cout << setw(2) << contador << "! = " << fatorial(contador) << endl;
return 0;
} //fim de main
//funcao fatorial iterativa
unsigned long fatorial(unsigned long numero)
{
unsigned long resultado = 1;
//declaracao iterativa da funcao fatorial
for(unsigned long i = numero; i >= 1; i--)
resultado *= i;
return resultado;
} //fim da funcao fatorial
compilando e executando ficara assim:
via terminal do linux:
Aqui terminamos mais um capitulo onde se aprendeu mais sobre os detalhes das declarações de função.
a experiencia mostra que a melhor maneira de desenvolver e manter um programa grande é construí-lo a partir de partes pequenas e simples ou módulos. Essa técnica se chama dividir para conquistar
até a proxima
Exemplo 01 , 02 e 03:
Na figura 6.3 de NotasFuncaoLivro.h, nesse programa dentro da classe NotasFuncaoLivro declaramos os protótipos da função-membro que depois serão definidas no NotasFuncaoLivro.cpp
//Figura 6.3: NotasFuncaoLivro.h
#include <string> //o construtor inicializa o nome do curso
using std::string;
//definicao da classe NotasFuncaoLivro
class NotasFuncaoLivro
{
public:
NotasFuncaoLivro(string); //o construtor inicializa o nome do curso
void setNomeCurso(string); //funcao para configurar o nome do curso
string getNomeCurso(); //funcao para recuperar nome do curso
void telaMensagem(); //exibe mensagem de boas vindas
void inputNotas(); //insere tres notas fornecidas pelo usuario
void telaNotasRelatorio(); //exibe um relatorio baseado nas notas
int maximo(int, int, int); //determina o maximo de 3 valores
private:
string nomeCurso; //nome do curso para essa NotasFuncaoLivro
int estudanteMaximo; //maxima de tres notas
};
Na proxima figura do exemplo declaramos uma NotasFuncaoLivro onde serão declaradas todas as funções-membros para o calculo de tres notas
//Figura 6.4.NotasFuncaoLivro.cpp
#include <iostream>
#include <string>
#include "NotasFuncaoLivro.h" //inclue a definicao de classe NotasFuncaoLivro
using std::cout;
using std::cin;
using std::endl;
/*
construtor inicializa nomeCurso com string fornecido como argumento;
inicializa estudanteMaximo como 0
*/
NotasFuncaoLivro::NotasFuncaoLivro(string nome)
{
setNomeCurso(nome); //valida e armazena NomeCurso
estudanteMaximo = 0; //esse valor sera substituido pela nota maxima
}
//funcao para configurar o nome do curso; limita o nome a 25 ou menos caracteres
void NotasFuncaoLivro::setNomeCurso(string nome)
{
if(nome.length() <= 25) //se o nome tiver 25 ou menos caracteres
nomeCurso = nome; //armazena o nome do curso no objeto
else
{
//configura nomeCurso como os primeiros 25 caracteres do nome de parametro
nomeCurso = nome.substr(0.25); //seleciona os primeiros 25 caracteres
cout << "Nome\"" << nome << "\" excede limite maximo (25).\n"
<< "Limite nomeCurso dos 1ºs 25 caracteres.\n" << endl;
} //fim do if...else
} //fim da funcao setNomeCurso
//funcao para recuperar o nome do curso
string NotasFuncaoLivro::getNomeCurso()
{
return nomeCurso;
} //fim da funcao getNomeCurso
//exibe uma mensagem do boas vindas para o usuario de NotasLivro
void NotasFuncaoLivro::telaMe}nsagem()
{
/*
esse instrucao chama getNomeCurso para obter o
nome do curso que esse NotasLivro representa
*/
cout << "Bem vindo a notas livro de\n" << getNomeCurso() << "!\n" << endl;
} //fim da funcao telaMensagem()
//insere numero arbitrario de notas fornecidas pelo usuario; atualizando o contador de notas
void NotasFuncaoLivro::inputNotas()
{
int nota1; //primeira nota inserida pelo usuario
int nota2; //segunda nota inserida pelo usuario
int nota3; //terceira nota inserida pelo usuario
cout << "Entre com tres numero inteiros: ";
cin >> nota1 >> nota2 >> nota3;
//armazena maxima no membro estudanteMaximo
estudanteMaximo = maximo(nota1, nota2, nota3);
} //fim da funcao inputNotas
//retorna o maximo dos seus tres parametros inteiros
int NotasFuncaoLivro::maximo(int x, int y, int z)
{
int maximoValor = x; //supoe que x e o maior valor inicial
//determina se y e maior que maximoValor
if(y > maximoValor)
maximoValor = y; //torna y o novo maximoValor
//determina se z e o maior que maximoValor
if(z > maximoValor)
maximoValor = z; //torna z o novo maximoValor
return maximoValor;
} //fim da funcao maximo
//exibe um relatorio baseado nas notas inseridas pelo usuario
void NotasFuncaoLivro::telaNotasRelatorio()
{
//gera saida de notas maximas entre as notas inseridas
cout << "Maximo de notas inseridas foi: " << estudanteMaximo << endl;
} //fim da funcao telaNotaRelatorio
Figura 6.5 do programa NotasFuncaoLivroMain.cpp onde cria o objeto e insere notas e exibe relatorio de notas
//figura 6.5 NotasFuncaoLivroMain.cpp
#include "NotasFuncaoLivro.cpp"
int main()
{
//cria objeto NotasLivro
NotasFuncaoLivro minhaNotasFuncaoLivro("C++ Como Programar");
minhaNotasFuncaoLivro.telaMensagem(); //exibe a mensagem de boas vindas
minhaNotasFuncaoLivro.inputNotas(); //le as notas fornecidas pelo usuário
minhaNotasFuncaoLivro.telaNotasRelatorio(); //exibe relatório baseado em notas
return 0; //indica terminacao bem sucedida
}
Cria o objeto NotasFuncaoLivro, insere as notas e exibe relatório de notas e na tela o resultado sera assim:
No próximo programa exemplo da figura 6.8 FuncaoRand usaremos a função para simular 20 lançamentos de um dado de seis lados e imprimir o valor de cada lançamento. O prototipo de função para a função rand está em <cstdlib>. Para produzir inteiros no intervalo de 0 a 5, utilizamos o operador módulo (%) com rand como voces verão no programa a seguir:
//figura 6.8: FuncaoRand.cpp
#include <iostream>
#include <iomanip>
#include <cstdlib>
using std::cout;
using std::endl;
using std::setw;
using std::rand;
int main()
{
//itera 20 vezes
for(int cont = 1; cont <= 20; cont++)
{
//escolhe um numero aleatorio de 1 a 6 e o envia para saida
cout << setw(10) << (1 + rand() % 6);
//se o comntador for divisivel por 5, inicia uma nova linha de saida
if(cont % 5 == 0)
cout << endl;
} //fim do for
return 0; //indica terminacao bem sucedida
}
executando o programa ficará assim na tela:
No programa da figura 6.9: FuncaoRand2.cpp o programa ira lança um dado de seis dados
6.000.000 vezes, usando uma variavel inteira chamada frequencia que ira ler a contagem de dados lançados e a variavel face que iura armazenar o valor lançado recentemente usando um for e dentro do for um switch para incrementar a variavel frequencia como um contador da quantidade de vezes que o dado foi lançado.
//figura 6.9: FuncaoRand2.cpp
#include <iostream>
#include <iomanip>
#include <cstdlib>
using std::cout;
using std::endl;
using std::setw;
using std::rand;
int main()
{
int frequencia1 = 0; //contagem de 1s lancados
int frequencia2 = 0; //contagem de 2s lancados
int frequencia3 = 0; //contagem de 3s lancados
int frequencia4 = 0; //contagem de 4s lancados
int frequencia5 = 0; //contagem de 5s lancados
int frequencia6 = 0; //contagem de 6s lancados
int face; //armazena o valor lancado mais recentemente
//itera 20 vezes
for(int lista = 1; lista <= 6000000; lista++)
{
face = 1 + rand() % 6; //numero aleatorio de 1 a 6
//determina valor de lancamento de 1 a 6 e incrementa o contador apropriado
switch(face)
{
case 1:
++frequencia1; //incrementa o contador de 1s
break;
case 2:
++frequencia2; //incrementa o contador de 2s
break;
case 3:
++frequencia3; //incrementa o contador de 3s
break;
case 4:
++frequencia4; //incrementa o contador de 4s
break;
case 5:
++frequencia5; //incrementa o contador de 5s
break;
case 6:
++frequencia6; //incrementa o contador de 6s
break;
default: //valor invalido
cout << "Programa nunca deve chegar aqui!";
} //fim do switch
} //fim do for
cout << "Face" << setw(13) << "Frequencia" << endl; //cabecalho de saida
cout << " 1" << setw(13) << frequencia1
<< "\n 2" << setw(13) << frequencia2
<< "\n 3" << setw(13) << frequencia3
<< "\n 4" << setw(13) << frequencia4
<< "\n 5" << setw(13) << frequencia5
<< "\n 6" << setw(13) << frequencia6 << endl;
return 0; //indica terminacao bem sucedida
} //fim do main
ao executar o programa sera mostrado na tela a contagem de dados que foi lançada:
Proximo programa da figura 6.10 FuncaoSRand usaremos a funcao srand para a contagem de sementes que serão inseridas pelo usuário ao digitar
//figura 6.10: FuncaoSRand.cpp
#include <iostream>
#include <cstdlib> //contem os prototipos para funcoes srand e rand
#include <iomanip>
using std::cout;
using std::cin;
using std::endl;
using std::rand;
using std::srand;
using std::setw;
int main()
{
unsigned semente; //armazena a semente inserida pelo usuario
cout << "Enter semente: ";
cin >> semente;
srand(semente); //semeia o gerador de numeros aleatorios
//itera 10 vezes
for(int cont = 1; cont <= 10; cont++)
{
//escolhe um numero aleatorio de 1 a 6 e o envia para a saida
cout << setw(10) << (1 + rand() % 6);
//se o contador for divisivel por 5, inicia uma nova linha de saida
if(cont % 5 == 0)
cout << endl;
} //fim do for
return 0; //indica terminaco bem sucedida
}
ao executar aparecera na tela:
Agora no proximo programa da figura 6.11 vamos mostrar uma simulação de jogo de dados onde usaremos time para mostrar o status quando cada vez o jogador lançar os dados.
//figura 6.11: JogoDeDados.cpp
#include <iostream>
#include <ctime>
#include <cstdlib>
using std::cout;
using std::endl;
using std::rand;
using std::srand;
int rolarDados(); //lanca o dado, calcula e exibe a soma
int main()
{
//enumeracao com constantes que representam os status do jogo
enum Posicao{CONTINUA, GANHOU, PERDEU}; //todas as maiusculas em constantes
int meusPontos; //pontos se nao ganhar ou perder na primeira rolagem
Posicao jogoPosicao; //pdoe conter CONTINUAR, GANHOU ou PERDEU
//torna aleatorio o gerador de numeros aleatorios utilizando a hora atual
srand(time(0));
int somaDoDado = rolarDados(); //primeira rolagem de dados
//determina status e pontuaao do jogo (se necessario) com base no primeiro lancamento de dados
switch(somaDoDado)
{
case 7: //ganha cok 7 no primeiro lancamento
case 11:
jogoPosicao = GANHOU;
break;
case 2: //perde com 2 no primiero lancamento
case 3: //perde com 3 no primeiro lancamento
case 12: //perde com 12 no primiro lancamento
jogoPosicao = PERDEU;
break;
default: //nao ganhou nem perdeu, portanto registra a pontuacao
jogoPosicao = CONTINUA; //jogo nao terminou
meusPontos = somaDoDado; //informa a pontuacao
cout << "Ponto foi = " << meusPontos << endl;
break;
} //fim do switch
//enquanto o jogo nao estiver completo
while(jogoPosicao == CONTINUA) //nem GANHOU nem PERDEU
{
somaDoDado = rolarDados(); //lanca os dados novamente
//determina o status do jogo
if(somaDoDado == meusPontos) //vitoria por pontuacao
jogoPosicao = GANHOU;
else
if(somaDoDado == 7) //perde obtendo 7 antes de antingir pontuacao
jogoPosicao = PERDEU;
} //fim do while
//exibe uma mensagem que ganhou ou perdeu
if(jogoPosicao == GANHOU)
cout << "Jogador Ganhou" << endl;
else
cout << "jogador Perdeu" << endl;
return 0; //indica terminacao bem-sucedida
} //fim do main
//lanca dados, calcula a soma e exibe os resultados
int rolarDados()
{
//seleciona valores aleatorios do dado
int dado1 = 1 + rand() % 6; //primneiro lanchamento de dado
int dado2 = 1 + rand() % 6; //segundo lancamento do dado
int soma = dado1 + dado2; //calcula a soma dos valores do dado
//exibe os resultados desse lancamento
cout << "Jogador rolou dado " << dado1 << " + " << dado2
<< " = " << soma << endl;
return soma; //fim da funcao rolarDado
} //fim da funcao rolarDado
Na tela abaixo sera mostrado na dela dessa maneira:
No Programa da figura 6.12 veremos um exemplo de escopo, por exemplo quando declaramos uma variavel local em um bloco, ela pode ser referenciada apenas nesse bloco e nos blocos aninhados dentro desse bloco. Veremos 4 tipos de escopos para um identificador: escopo de função, escopo de arquivo e escopo de protótipo de função, mais adiante veremos escopo de classe e escopo de namespace .
//figura 6.12: FuncaoEscopo.cpp
#include <iostream>
using std::cout;
using std::endl;
void useLocal(void); //prototipo de funcao
void useStaticLocal(void); //prototipo de funcao
void useGlobal(void); //prototipo de funcao
int x = 1; //variavel global
int main()
{
int x = 5; //variavel local para main
cout << "Local x principal no escopo externo foi: " << x << endl;
{ //inicia novo escopo
int x = 7; //oculta x no escopo externo
cout << "Local x principal no escopo interno foi: " << x << endl;
} //fim do novo escopo
cout << "Local x principal no escopo externo foi: " << x << endl;
useLocal(); //useLocal tem uma variavel local x
useStaticLocal(); //useStaticLocal tem x estatico local
useGlobal(); //useGlobal utiliza x global
useLocal(); //useLocal reinicializa seu x local
useStaticLocal(); //x estatico local retem seu valor anterior
useGlobal(); //x global também retem seu valor
cout << "\nLocal x principal e: " << x << endl;
return 0; //indica terminacao bem sucedida
}
//useLocal reinicializa a variavel local x durante cada chamada
void useLocal(void)
{
int x = 25; //inicializa toda vez que useLocal e chamada
cout << "\nLocal x e: " << x << " entra com useLocal" << endl;
x++;
cout << "Local x e: " << x << " entra com useLocal" << endl;
} //fim da funcao useLocal
/**
useStaticLocal inicializa a variavel estaica local x somente
na primeira vez em que a funcao e chamada; o valor de x e salvo
entre as chamadas a essa funcao
**/
void useStaticLocal(void)
{
static int x = 50; //incializada na primeira vez em que useStaticLocal e chamada
cout << "\nLocal estatico x e: " << x << " a entra useStaticLocal" << endl;
x++;
cout << "\nLocal estico x e: " << x << " a existir useStaticLocal" << endl;
} //fim da funcao useStaticLocal
//useGlobal modifica a variavel global x durante cada chamada
void useGlobal(void)
{
cout << "\nGlobal x e: " << x << " a entrar useGlobal" << endl;
x *= 10;
cout << "Global x e: " << x << " a existir userGlobal" << endl;
} //fim da funcao useGlobal
Ao executar o programa ficara assim na tela:
No próximo programa da figura 6.13 iremos mostrar uma função quadrado utilizada para demonstrar a pilha de chamadas de função e os arquivos de ativação.
//figura 6.13: FuncaoQuadrado.cpp
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
int quadrado(int); //protoipo para funcao quadrado
int main()
{
int a = 10; //valor para quadrado (variavel automatica local em main)
cout << a << " Quadrado: " << quadrado(a) << endl; //exibe o quadrado em um int
return 0; //indica terminacao bem-sucedia
} //fim do main
//retorna o quadrado de um inteiro
int quadrado(int x)
{
return x * x; //calcula quadrado e retorna o resultado
}
ao executar o programa ficara assim na tela:
No programa da figura 6.18: utilizaremos uma função inline para calcular o volume de um cubo.
//figura 6.18: FuncaoInline.cpp
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
/**
Definicao da funcao inline cube. A definicao de funcao aparece antes
de a funcao ser chamada, entao um prototipo de funcao nao e necessario.
A peimeira linha da definicao atua como o prototipo.
**/
inline double cubo(const double lado)
{
return lado * lado * lado; //calcula o cubo
} //fim da funcao cubo
int main()
{
double ladoValor; //armazena o valor do lado inserido pelo usuario
cout << "digite o comprimento do cubo: ";
cin >> ladoValor; //le o valor fornecido pelo usuario
//calcula o cubo de ladoValor e exibe o resultado
cout << "Volume do cubo de lado "
<< ladoValor << " = " << cubo(ladoValor) << endl;
return 0; //indica terminacao bem-sucedida
} //fim de main
ao executar ficara assim na tela:
Exemplo do programa figura 6.19 vamos fazer comparação de passagem por valor e a passagem por referencia
//figura 6.19: FuncaoPasReferencia.cpp
#include <iostream>
using std::cout;
using std::endl;
int quadradoPorValor(int); //prototipo de funcao (passagem por valor)
void quadradoPorReferencia(int &); //prototipo de funcao (passagem por referencia)
int main()
{
int x = 2; //valor para quadrado utilizando quadradoPorValor
int z = 4; //valor para quadrado utilizando quadradoPorReferencia
//demonstra quatradoPorValor
cout << "x = " << x << " antes quadradoPorValor\n";
cout << "Valor retorno por quadradoPorValor: "
<< quadradoPorValor(x) << endl;
cout << "x = " << z << " depois quadradoPorValor\n" << endl;
//demonstra quadradoPorReferencia
cout << "z = " << z << " antes quadradoPorReferencia" << endl;
quadradoPorReferencia(z);
cout << "z = " << z << " depois quadradoPorReferencia" << endl;
return 0; //indica terminacao bem-sucedida
}
/**
quadradoPorValor multiplica um numero por ele proprio, armazena o
resultado em numero e retorna o novo valor em numero
**/
int quadradoPorValor(int numero)
{
return numero *= numero; //argumento do chamador nao modificado
} //fim da funcao quadradoPorValor
/**
quadradoPorReferencia multiplica numeroRef por si mesmo e armazena o resultado
na variavel a qual numeroRef se refere na funcao main
**/
void quadradoPorReferencia(int &numeroRef)
{
numeroRef *= numeroRef; //argumento do chamador modificou
} //fim da funcao quadradoPorReferencia
executando ficara assim:
//figura 6.20: RefInicializadas1.cpp
#include <iostream>
using std::cout;
using std::endl;
int main()
{
int x = 3;
int &y = x; //referencia (e um alias para) x
y = 7; //realmente modifica x
cout << "x = " << x << endl << "y = " << y << endl;
return 0; //indica termincao bem-sucedida
} //fim do main
executando:
//figura 6.21: ReferenciasInicializadas2.cpp
#include <iostream>
using std::cout;
using std::endl;
int main()
{
int x = 3;
int &y; //Erro: y deve ser inicializado
cout << "x = " << x << endl << "y = " << y << endl;
y = 7;
cout << "x = " << x << endl << "y = " << y << endl;
return 0; //indica terminacao bem-sucedida
}
ao executar ira ocorrer um erro informando que y deve ser inicializado
Proximo programa apresentaremos o escopo unitario, é possivel declarar variaveis locais e globais do mesmo nome, C++ fornece operador unitario de resolução de escopo (::) para acessar uma variavel global quando uma variavel local do mesmo nome estiver no escopo.
//figura 6.23: OperadorUnario.cpp
#include <iostream>
using std::cout;
using std::endl;
int numero = 7; //variavel global chamada numero
int main()
{
double numero = 10.5; //variavel local chamada numero
//exibe valores de variaveis locais e globais
cout << "Local valor double do numero = " << numero
<< "\nGlobal inteiro do numero = " << ::numero << endl;
return 0; //indica terminacao bem sucedida
} //fim do main
ao executar:
No proximo programa da figura 6.24 veremos a função sobrecarregada calculando a função de um quadrado de inteiro e um quadrado de double.
//figura 6.24: FuncoesSobrecarregadas.cpp
#include <iostream>
using std::cout;
using std::endl;
//funcao quadrado para valores int
int quadrado(int x)
{
cout << "Quadrado de inteiro " << x << " = ";
return x * x;
} //fim da funcao quadrado com argumento int
//funcao quadrado para valores double
double quadrado(double y)
{
cout << "Quadrado de double " << y << " = ";
return y * y;
} //fim da funcao quadrado com argumentos double
int main()
{
cout << quadrado(7); //chama versao int
cout << endl;
cout << quadrado(7.5); //chama versao double
cout << endl;
return 0; //indica terminaçao bem sucedida
} //fim de main
ao executar aparecera da seguinte forma na tela:
No programa da figura 6.26 veremos templates de funções em que a logica e as operações forem identicas para cada tipo de dados, sobrecarga pode ser realizada de forma compacta e conveniente utilizando templates de função, onde o programador escreve em uma unica definição de template de função. C++ gera automaticamente especificações de template da função separadas para tratar cada tipo de chamada de maneira adequada.
//figura 6.26: Maximo.h
template <class T> //ou template<typename T>
T maximo(T valor1, T valor2, T valor3)
{
T maximoValor = valor1; //pressupoe que valor1 e maximo
//determinba se valor2 e maior que maximoValor
if(valor2 > maximoValor)
maximoValor = valor2;
//determina se valor3 e maior que maximoValor
if(valor3 > maximoValor)
maximoValor = valor3;
return maximoValor;
} //fim do template de funcao maximo
//figura 6.27: MaximoMain.cpp
#include <iostream>
#include "Maximo.h" //inclui a definicao do template de funcao maximo
using std::cout;
using std::cin;
using std::endl;
int main()
{
//demonstra maximo com valores int
int int1, int2, int3;
cout << "Entre com tres valores de inteiros: ";
cin >> int1 >> int2 >> int3;
//invoca a versao int de maximo
cout << "O valor maximo de inteiro = "
<< maximo(int1, int2, int3);
//demonstra maximo com valores double
double double1, double2, double3;
cout << "\n\nEntre com tres valores double: ";
cin >> double1 >> double2 >> double3;
//invoca a versao double de maximo
cout << "O maximo valor de double = " << maximo(double1, double2, double3);
//demonstra maximo com valores de char
char char1, char2, char3;
cout << "\n\nEntre com tres caracteres: ";
cin >> char1 >> char2 >> char3;
//invoca versao char de maximo
cout << "O maximo valor de caracteres = "
<< maximo(char1, char2, char3);
return 0; //indica terminacao bem-sucedida
} //fim de main
ao compliar e executar o programa:
No proximo programa da figura: 6.29 iremos fazer o calculo de uma função fatorial recursiva
//figura 6.29: FuncFatorialRecursiva.cpp
#include <iostream>
#include <iomanip>
using std::cout;
using std::endl;
using std::setw;
unsigned long fatorial(unsigned long); //prototipo de funcao
int main()
{
//calcula o fatorial de 0 a 10
for(int contador = 0; contador <= 10; contador++)
cout << setw(2) << contador << "! = " << fatorial(contador) << endl;
return 0; //indica terminacao bem-sucedida
} //fim do main
//definicao recursiva da funcao fatorial
unsigned long fatorial(unsigned long numero)
{
if(numero <= 1) //testa caso basico
return 1; //casos basicos: 0! = 1 e 1! = 1
else //passo de recursao
return numero * fatorial(numero - 1);
} //fim da funcao fatorial
ao executar na tela ficara dessa maneira:
//figura 6.30:FuncFibonacciRecursiva.cpp
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
unsigned long fibonacci(unsigned long); //prototipo de funcao
int main()
{
//calcula os valores de fibonacci de 0 a 10
for(int contador = 0; contador <= 10; contador++)
cout << "fibonacci(" << contador << " ) = "
<< fibonacci(contador) << endl;
//exibe valores fibonacci mais alto
cout << "fibonacci(20) = " << fibonacci(20) << endl;
cout << "fibonacci(30) = " << fibonacci(30) << endl;
cout << "fibonacci(35) = " << fibonacci(35) << endl;
return 0; //indica terminacao be-sucedida
} //fim do main
//funcao fibonaci recursiva
unsigned long fibonacci(unsigned long numero)
{
if((numero == 0) || (numero == 1)) //casos basicos
return numero;
else //passo de recursao
return fibonacci(numero - 1) + fibonacci(numero - 2);
} //fim da funcao fibonacci
compliando e executando o resultado sera este:
Tanto a iteração como recursão se baseiam em uma estrutura de controle: a iteração utiliza uma estrutura de repetição e a recursão utiliza uma estrutura de seleção, mas ambas envolvem repetição.
No programa a seguir da figura 6.32 veremos como funciona onde será calculado a função fatorial iterativa.
//figura 6.32: FuncFatorialIterativa.cpp
#include <iostream>
#include <iomanip>
using std::cout;
using std::endl;
using std::setw;
unsigned long fatorial(unsigned long); //prototipo de funcao
int main()
{
//calcula o fatorial de 0 a 10
for(int contador = 0; contador <= 10; contador++)
cout << setw(2) << contador << "! = " << fatorial(contador) << endl;
return 0;
} //fim de main
//funcao fatorial iterativa
unsigned long fatorial(unsigned long numero)
{
unsigned long resultado = 1;
//declaracao iterativa da funcao fatorial
for(unsigned long i = numero; i >= 1; i--)
resultado *= i;
return resultado;
} //fim da funcao fatorial
compilando e executando ficara assim:
via terminal do linux:
Aqui terminamos mais um capitulo onde se aprendeu mais sobre os detalhes das declarações de função.
a experiencia mostra que a melhor maneira de desenvolver e manter um programa grande é construí-lo a partir de partes pequenas e simples ou módulos. Essa técnica se chama dividir para conquistar
até a proxima
Comentários
Postar um comentário