Ajude nosso projeto a se manter online.

Apostila C++ Progressivo

Já imaginou ter o melhor, maior e mais completo material sobre a linguagem de programação C++ ?
Agora já dá.

É a bíblia C++ Progressivo
E-Book C++ Progressivo

Quais as vantagens da
Apostila C++ Progressivo ?

São várias! Veja:
  • Todo conteúdo do site
  • Conteúdo extra (incluindo questões resolvidas e códigos comentados)
  • Poder ler o conteúdo offline
  • Não precisa de internet pra estudar
  • Nada de propagandas chatas
  • Tutoriais bem organizados, separados e bonitinhos
  • Pode ler no computador, celular, tablet...
  • Pode estudar em casa, na faculdade, no ônibus, na praia, no show do Iron Maiden...
  • Serve como referência e para posterior consulta, caso esqueça algo
  • DE LONGE, o melhor presente que alguém pode dar pra outra pessoa: conhecimento
  • E o mais bacana:
    Você nos ajuda e incentiva a criar cada vez mais conteúdo de graça, de qualidade, melhorando o ensino da computação no Brasil. Simbora desenvolver a tecnologia nesse país ?
Fazer download da apostila C++ Progressivo

A apostila (e-book em PDF), custa apenas R$ 14,99.
Você pode adquirir pelo PagSeguro:

Pague com PagSeguro - é rápido, grátis e seguro!


E pelo PayPal:
 


C++ Progressivo download

Apostila de C++ completa

Tutorial completo de C++


MEGA PACK:
 Todas Apostilas

Já imaginou ter em um pendrive ou na memória de seu celular  TUDO que você precisa para aprender computação, em todas as áreas, da melhor maneira, mais completa e voltada para iniciantes?

Estudar Java, a linguagem mais importante do mercado de trabalho, que vai te permitir criar aplicativos para Android.

Linguagem C, a linguagem que 'Deus' usou para criar o Universo? Aprender a língua que são feitos sistemas operacionais e entrar mais a fundo nas entranhas dos bits de seu computador?

E HTML + CSS, para aprender criar sites ?
Una isso ao JavaScript, linguagem para executar scripts e programas no navegador dos clientes?

De quebra, aprender Python, a linguagem mais simples e fácil de aprender, que com pouco código você criar coisas fantásticas e extremamente poderosas?

É nosso mega pack, todas apostilas:

Apostila Java ProgressivoApostila C Progressivo


Apostila JavaScript ProgressivoApostila HTML + CSS Progressivo


Fazer download da apostila C++ Progressivo
Apostila Python Progressivo




Preço: R$ 49,99
Pague com PagSeguro - é rápido, grátis e seguro!

 Via PayPal:
 

Pessoal, dá cerca de 7 reais por apostila.

Se não for o melhor e mais barato investimento da sua vida, entre em contato pois eu te estorno seu dinheiro, sem problemas.

Lista de Exercícios de Funções em C++ (Resolvidos e comentados)

Chegamos ao final de mais uma seção de nosso curso de C++, a de funções.
Nos exercícios abaixo, você deve usar todos seus conhecimentos aprendidos até aqui, como o básico, de laços, loopings, testes condicionais e, claro, de função.

Use e abuse das funções. Crie muitas funções.
Cada função deve fazer uma única coisa, da maneira mais simples e direta possível.

Faça com que elas sejam facilmente acopladas, ou seja, deve receber e retornar informações, sempre que possível. Isso permite que você possa usar os códigos de suas funções posteriormente.

Lembre-se: um programa grande nada mais é que uma série de programinhas pequenos.
Suas funções devem ser esses programinhas pequenos, fazendo funcionalidades específicas, ok?

Exercícios de Função em C++

Crie um jogo de par ou ímpar. Você deve escolher 0 para par ou 1 para ímpar, em seguida fornece um número. O computador gera um número de 1 até 10, soma os valores e diz quem ganhou.

Crie um dado em C++. Role os dados: ou seja, seu programa deve sortear um número aleatório de 1 até 6.

Vamos estudar probabilidade? Faça com que o dado anterior seja lançado 100 vezes, mil vezes e 1 milhão de vezes. A cada vez que ele rodar, você deve armazenar o valor que ele forneceu, ao final, você mostra quantas vezes cada número foi sorteado. Bate com os resultados da estatística ?

Crie um jogo onde o computador sorteia um número de 1 até 10, e você tenta adivinhar qual é.

Vamos incrementar o jogo anterior? Faça com que o programa diga dizer quantas tentativas você levou para acertar.

Vamos realmente fazer um jogo legal e interessante? Faça com o que o computador sorteie um número de 1 até 100. A cada vez que você chutar, ele deve dizer se você chutou abaixo do valor real, acima ou se acertou. Ao final, diz o número de tentativas que você teve e se bateu o record ou não. Ah, ao final de cada rodada, o programa pergunta se você quer jogar novamente ou não, exibindo o record atual.

Números Aleatórios em C++: Como gerar com rand() e srand()

Neste tutorial de nossa apostila C++ Progressivo, vamos aprender como gerar números ou qualquer intervalo de números aleatórios, ou randômicos.

Números aleatórios com a Função rand()

Em muuuuuitos programas, será necessário termos números aleatórios.
Por exemplo, para sortear uma música no seu player, para escolher um vídeo aleatório do Youtube, para fazer um sorteio com seguidores do Instagram, para escolher um local no mapa do game que você criou em C++, e etc etc etc.

A primeira maneira que temos de fazer isso, é usando a função rand(), da biblioteca cstdlib.
Ele vai gerar um número entre 0 e a constante RAND_MAX.

Primeiro, vamos ver o valor desse RAND_MAX, que pode variar de máquina para máquina:
#include <iostream>
#include <cstdlib>
using namespace std;

int main()
{
    cout<<"Intervalo: 0 - "<<RAND_MAX<<endl;

    return 0;
}
Na minha máquina o resultado do programa anterior foi 2147483647.
E no seu PC?

Agora vamos gerar um número aleatório:
#include <iostream>
#include <cstdlib>
using namespace std;

int main()
{
    cout<<rand()<<endl;

    return 0;
}
Agora vamos gerar 6 números aleatórios:
#include <iostream>
#include <cstdlib>
using namespace std;

int main()
{
    int i;

    for(i=0 ; i<6 ; i++)
        cout<<rand()<<" ";

    return 0;
}
Notou algo?
Feche seu programa. Abra de novo...notou algo?

Sim, os números aleatórios se repetem! Mas, calma, vamos ver como resolver isso.

A função srand() e as sementes (seed) randômicas

Na verdade verdadeira, aquele que vem do coração, não existe número puramente aleatório. Existe toda uma ciência, e estudos e mais estudos e pesquisas em cima disso.

Basicamente, alguma regra vai ter que ser usada para gerar esses números, que na verdade são pseudoaleatórios. Porém, existe uma maneira de contornar isso.

É fornecendo números, nós mesmos, para que o C++ pegue esses valores e gere números diferentes, a partir deles. Para isso, vamos usar a função srand(), que aceita um inteiro como parâmetro (um unsigned int, na verdade).

Por exemplo, faça:
#include <iostream>
#include <cstdlib>
using namespace std;

int main()
{
    srand(2112);
    cout<<rand()<<endl;

    return 0;
}
Veja que agora o valor da rand() mudou, não era mais aqueles que ficavam repetindo.
Agora vai gerar outros 'aleatórios', pois fornecemos 2112 como semente. Mas se você fechar e abrir o programa, vai notar que vai aparecer o mesmo 'aleatório'.

Tente isso agora:
#include <iostream>
#include <cstdlib>
using namespace std;

int main()
{
    int i;

    for(i=1 ; i<=10 ; i++){
        srand(i);
        cout<<rand()<<endl;
    }

    return 0;
}
Agora deu tudo diferente, pois a cada iteração a semente que alimentou a srand() era diferente.
Mas mesmo assim, se você fechar e abrir de novo, vai dar tudo igual de novo, que saco...

A função time() da biblioteca ctime

Veja como os programadores são geniais.

Existe uma função, da biblioteca ctime, a time(), que quando invocada retorna o número de segundos desde 00:00 de 1 de Janeiro de 1970. A sacada é usar ela como geradora de sementes, pra srand().

Veja:
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;

int main()
{
    unsigned seed = time(0);

    srand(seed);
    cout<<rand()<<endl;

    return 0;
}
Abra e feche...várias vezes...sempre diferente agora, o número sorteado!
Afinal, a cada segundo o retorno da time(0) é diferente, gerando sementes diferentes pra srand(), que altera a rand(), que nos fornece números aleatórios diferentes! PIMBA!

Escolhendo intervalos de valores
1443561896
1944127442
107792574
1300800110
...
Que diachos de valores são esses? Muito grandes...raramente vamos querer gerar números desse tamanho. Queremos aleatórios que sejam 0 ou 1...de 1 até 6...de 1 até 60...entre 0 e 100...coisa assim, concorda?

Isso é facilmente resolvido com o operador resto da divisão: %

Por exemplo, para:
  • Gerar aleatórios que sejam 0 ou 1
Basta fazer: rand()%2
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;

int main()
{
    unsigned seed = time(0);

    srand(seed);
    cout<<rand()%2<<endl;

    return 0;
}
  • Gerar aleatórios de 1 até 10
Usando rand() % 10: ele vai gerar os números: 0, 1, 2, 3, 4, 5, 6, 7, 8 ou 9
Então, basta somar 1, e temos números de 1 até 10.
Gerando números de 1 até 10:
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;

int main()
{
    unsigned seed = time(0);

    srand(seed);
    cout<<1+rand()%10<<endl;

    return 0;
}
Bacana, né?

A função exit() do C++

Neste tutorial de nosso curso C++ Progressivo, vamos conhecer e aprender a usar a função exit().

A função exit()

De todos os programas que desenvolvemos ao longo de nosso curso, todos eles terminavam após o comando return da função main().

Quando invocamos uma função, ela salva em memória o local de onde ela foi invocada, para voltar para aquele estágio, após terminar sua execução. Assim, sempre os programas voltavam pra função main(), mesmo a gente tendo invocado milhões de outras funções.

Porém, seria interessa se pudéssemos sair, interromper ou terminar a qualquer momento, nossos programas, não concorda?

Isso é possível, basta chamar a função exit().
Ela é bem simples.

Primeiro, inclua a biblioteca: cstdlib
A função está definida dentro dessa biblioteca, por isso precisamos adicionar pra usar.

Depois, basta passar um inteiro como argumento e invocar a função, veja o código:
#include <iostream>
#include <cstdlib>
using namespace std;

int main()
{
    cout<<"A main() começou..."<<endl;
    cout<<"Chamando a exit()..."<<endl;
    exit(0);
    cout<<"Depois da exit()"<<endl;

    return 0;
}
Note que o último cout nem aparece na tela:
Curso de C++ online grátis

Você pode colocar esse exit(0) em qualquer local do programa, mesmo dentro de outra função qualquer, vai interromper e terminar na hora o programa, naquele momento e naquele local.

Argumentos da função exit()

A função exit tem como parâmetro um número inteiro, apenas.
O argumento que devemos fornecer é o que vai ser retornado para o sistema operacional que executou o seu programa em C++.

Esse argumento é muito importante para avisar para quem chamou determinado programa se ele foi executado e encerrou corretamente. No futuro, você vai programar softwares que chamam outros programas, e precisa se comunicar com eles.

Uma dessas maneiras é através do argumento da exit().
Por exemplo, o 0 é o símbolo universal para: "Tudo ok, terminou tudo certo!"

Por isso que sempre usamos: return 0;, na função main(), entendeu agora?
Quando alguém te chamar de um zero, não se ofenda, em programação isso é um elogio.

Existem até duas constantes bastante usadas, para simbolizar:

  1. sucesso: EXIT_SUCCESS
  2. problema: EXIT_FAILURE


Use assim: exit(EXIT_SUCCESS) ou exit(EXIT_FAILURE), caso o programa tenha se encerrado da maneira correta ou com algum problema.

Se seu programa jogo terminar por problema na memória, faça: exit(1), então 1 simboliza problema na memória.
Se a internet tiver caído e terminado a partida, o programa se encerra com exit(2), onde 2 simboliza problemas com internet.

E por aí vai...você vai decidir o que cada número do erro significa, para poder saber o que está ocorrendo com determinada aplicação. Deixe o número 0 para simbolizar sucesso, que tudo deu certo na execução do programa.

O número 2112 é o número supremo do universo, respeite e não use ele.
Devemos apenas reverenciar o valor 2112.

MDC em C++ - Como calcular o Máximo Divisor Comum

Vamos aprender como calcular o MDC de um número, ou seja, seu máximo divisor comum, usando recursão em C++. Primeiro, vamos entender o que é MDC.

O que é MDC ?

Todo número natural pode ser divido por outros, resultando em números naturais.
Por exemplo, o 8 pode ser dividido por:
8/1 = 8
8/2 = 4
8/4 = 2
8/8 = 1

O 11, que é um primo, pode ser dividido por:
11/1  = 11
11/11 = 1

Todo número natural tem, pelo menos, dois divisores: o 1 e ele mesmo.
Então, dois números naturais quaisquer, tem sempre algum divisor em comum, nem que seja apenas o 1.

É aí que entra o MDC, o máximo, queremos calcular o maior divisor comum, o maior divisor desses dois números.

Como calcular o MDC

Vamos calcular os divisores de 18:
18/1 = 18
18/2 = 9
18/3 = 6
18/6 = 3
18/9 = 2
18/18 = 1

Agora os divisores de 15:
15/1 = 15
15/3 = 5
15/5 = 3
15/15 = 1

1 e 3 são os números que se repetem, os divisores em comum. E qual o maior deles?
Pimba, é o 3!

Como calcular o MDC com C++ e recursão

O que vamos fazer é simples...vamos pegar o número maior e calcular o resto da divisão pelo menor.
Se der 0, acabou, o menor é o MDC.

Se não der 0, continuamos com mais alguns cálculos, até o resto da divisão do primeiro pelo segundo ser 0, mas pegamos duas coisas: o menor número e o resto da divisão do maior pelo menor.

Então, fazemos a recursividade, agora passando como argumentos o menor número e o resto da divisão do maior pelo menor.

Nosso código fica assim:

#include <iostream>
using namespace std;

int mdc(int num1, int num2)
{
    if(num1%num2 == 0)
        return num2;
    else
        return mdc(num2, num1%num2);
}

int main()
{
    int num1, num2;

    cout<<"Numeros (maior e menor): ";
    cin>> num1 >> num2;

    cout<<"MDC: "<<mdc(num1, num2)<<endl;
}
Para entender, matematicamente, a lógica anterior, você deve estudar o Algoritmo de Euclides.

Função Recursiva em C++

Neste tutorial de C++, vamos aprender a famosa e importante arte da recursividade, e você vai entender a piadinha de programadores: "Para saber recursão, tem que saber recursão"

Função Recursiva

Nos programadores que fizemos no decorrer de nossos tutoriais, fizemos com que, várias vezes, uma função fosse chamada dentro da outra. Recursão tem a ver com invocar uma função.

Mas ela chama uma função em especial. A função recursiva nada mais é a função que chama ela mesma.

Vamos criar uma função que exibe uma mensagem na tela e depois invoca ela mesma:
#include <iostream>
using namespace std;

void recur()
{
    cout<<"Progressive C++ course"<<endl;
    recur();
}

int main()
{
    recur();
    return 0;
}
Acontece o seguinte:
Recursividade em C++

E é bem simples de entender...invocamos a recur(), ela exibe uma mensagem na tela e ... chama ela novamente, que ao ser chamada, exibe uma mensagem na tela...depois chama ela novamente, que exibe uma mensagem...e assim vai, indefinidamente, para o infinito e além.

Pra parar, tive que dar um Control+C, senão ficava rodando pra sempre.

Como usar recursão com funções

Desse jeito, as funções recursivas não são tão úteis.
Para aprender como usar elas da maneira correta, precisamos de uma espécie de contador, assim como fizemos com os loopings.

Vamos fazer com que a recur() receba um inteiro, e só vai chamar ela mesmo se esse inteiro for maior que 0:
#include <iostream>
using namespace std;

void recur(int counter)
{
    if(counter>0){
        cout<<"Curso C++ Progressivo"<<endl;
        recur(counter-1);
    }
}

int main()
{
    recur(5);
    return 0;
}
Se o número recebido for maior que 0, exibimos a mensagem e chamamos novamente a recur(), porém, vamos passar um argumento menor, subtraído de 1, pois essa função já executou uma vez.

Assim, se você fizer recur(5), ela vai rodar a função 5 vezes apenas:
  1. Primeiro chamamos recur(5), exibiu a mensagem e chamou recur(4).
  2. recur(4) exibe a mensagem e chama recur(3).
  3. recur(3) exibe a mensagem e chama recur(2).
  4. recur(2) exibe a mensagem e chama recur(1)
  5. recur(1) exibe a mensagem e chama recur(0).
Quando chamamos recur(0), nada é feito e nenhuma função é mais invocada, encerrando a recursão.

Recursividade com funções em C++

recur(0) é o caso base, onde ela deve parar.
Vamos praticar e ver como aplicar a técnica da recursividade com funções, em C++?

Somatório com recursão

Vamos chamar de sum(n) o somatório do valor n.

Por exemplo:
sum(5) =  5 + 4 + 3 + 2 + 1

Mas sum(4) = 4 + 3 + 2 + 1

Ou seja: sum(5) = 5 + sum(4)

Podemos generalizar fazendo:
sum(n) = n + sum(n-1)

Veja que tem uma recursão aí. A sum() está chamando a sum(), com um argumento decrementado em 1, mas está. Quando o argumento for 1, ele deve retornar 1 (pois somatório de 1 é 1) e parar de invocar a função de somatório.

Nosso código fica:
#include <iostream>
using namespace std;

int sum(int num)
{
    if(num==1)
        return 1;
    else
        return num+sum(num-1);
}

int main()
{
    int num;

    cout<<"Somatório de: ";
    cin>> num;

    cout<<"Igual a: "<<sum(num)<<endl;
}
sum(1) é o caso base, onde resolvemos as coisas manualmente, sem usar recursão, apenar retornando 1.
Bacana. né?

Fatorial com recursão

Vamos chamar de fat(n) o fatorial do valor n.
fat(n) = n * (n-1) * (n-2) * ... 3 * 2 * 1

Ou seja:
fat(n) = n * fat(n-1)

Concorda?
Temos aí uma lógica com recursividade. A função fat() chamando a fat().
Ela deve chamar até chegar no argumento 1, e fatorial de 1 é 1.

Veja como fica nosso código:
#include <iostream>
using namespace std;

int fat(int num)
{
    if(num==1)
        return 1;
    else
        return num*fat(num-1);
}

int main()
{
    int num;

    cout<<"Fatorial de: ";
    cin>> num;

    cout<<"Igual a: "<<fat(num)<<endl;
}

fat(1) é o caso base, onde não invocamos a recursividade, e sim retornamos diretamente um valor.

Sequência de Fibonacci com recursividade

Por fim, nosso bom e velho Fibonacci.
Relembre aqui o que é a série de Fibonacci.

Basicamente, os dois primeiros termos são 0 e 1. São nossos casos base.
O terceiro termo, em diante, é a soma dos dois anteriores. Ou seja:
F(1) = 0
F(2) = 1
F(3) = F(2) + F(1) = 1 + 0 = 1
F(4) = F(3) + F(2) = 1 + 1 = 2
F(5) = F(4) + F(3) = 2 + 1 = 3
F(6) = F(5) + F(4) = 3 + 2 = 5
F(7) = F(6) + F(5) = 5 + 3 = 8
...

Ou seja, a fórmula para achar o termo 'n' é:
F(n) = F(n-1) + F(n-2)
Você concorda ?

Quando o argumento de nossa função receber o valor 2, ou seja, quando quisermos saber o valor de F(2), a função deve retornar 1. E quando quisermos saber o valor de F(1), a função deve retornar 1.
Não devemos calcular usando a fórmula da recursividade, pois seria calculado:
F(2) = F(1) + F(0)
F(1) = F(0) + F(-1)

E não existem se deve calcular F(0) quando mais F(1).
Assim, nosso código fica:
#include <iostream>
using namespace std;

int fibo(int num)
{
    if(num==1)
        return 0;
    else
        if(num==2)
            return 1;
        else
            return fibo(num-1)+fibo(num-2);
}

int main()
{
    int num;

    cout<<"Termo: ";
    cin>> num;

    cout<<"Igual a: "<<fibo(num)<<endl;
}
Teste. Calcule o termo 19 da sequência, ele é 2584. Deu certo?

Recursão x Iteração

Recursão é uma ferramenta que pode salvar nossa vida, como programador, muitas vezes, pois a ideia por trás do 'uma função chamar ela mesma' é bem simples, útil e pode ser empregada nos mais diversos tipos de problemas que sejam repetitivos, que sigam determinados padrões, como os exemplos acima vistos.

Mas é importante salientar que tudo que é feito com recursão, é possível fazer sem.
Mais especificamente, tudo que é possível fazer com recursão, você pode usar iteração, com loopings.

Quando invocamos uma função, muita coisa ocorre por debaixo dos panos. Muita memória é alocada para os parâmetros e argumentos, o endereço e o código da função são alocados, armazenados e acessados em locais pré-definidos na memória, o local onde ela foi invocada é salvo também, para voltar pra lá quando terminar a execução, e por ai vai.

Isso resulta em uma coisa: recursão é mais lento que iteração. de um modo geral.
Então, por que usar recursão? Simples, alguns problemas, de lógica repetitiva, são beeeem mais simples de serem resolvidos usando recursão.

Embora seja mais lenta e menos eficiente, você pode compensar isso resolvendo/criando um algoritmo em menos tempo, usando recursão. Você pode facilmente descobrir a solução de um problema aplicando recursividade, e as vezes iteração pode ser mais complicado de programar.

O segredo da recursividade é que ela transforma um problema em um problema menor, mas similar.
Em vez de resolver func(n), você só precisa resolver para func(n-1), depois func(n-2)....func(3)...func(2)...e geralmente pra resolver coisas com argumentos pequenos, nós sabemos resolver facilmente. Recursividade faz isso: transforma um problema em um probleminha, com a exata mesma lógica.

Voltaremos a usar recursão para calcular, por exemplo, caracteres na seção de strings e também com listas.

Exercício de C++

Crie uma função para calcular o fatorial de um número, usando recursão. Escolha um número bem grande, que leve alguns segundos de sua máquina. Veja quanto tempo demorou pra fazer a operação.
Agora crie outra função para calcular o mesmo fatorial, mas usando iteração (Fatorial com laços em C++), calcule o mesmo número. Anote o tempo.

Agora compartilhe com a gente, nos comentários: que número calculou e quanto tempo cada função levou pra calcular?

Sobrecarga de Funções: Parâmetros e Argumentos diferentes

Neste tutorial de nossa apostila de C++, vamos aprender o que é sobrecarga de funções, para que servem e como usar esta importante técnica de programação.

Tamanhos de Parâmetros e Argumentos em Funções no C++

No tutorial sobre Argumentos Padrão, vimos que é possível enviar uma quantidade variada de argumentos para uma função, desde que ela esteja usando parâmetros de referência.

Por exemplo, o código abaixo é de uma função que calcula uma média aritmética:
#include <iostream>
using namespace std;

float average(float a, float b, float c, float d = 0.0)
{
    return (a+b+c+d)/4;
}

int main()
{
    cout<<"Media de 3 numeros: "<<average(10, 9, 7)<<endl;
    cout<<"Media de 4 numeros: "<<average(10, 9, 7, 6)<<endl;

    return 0;
}
Ela pode receber 3 ou 4 argumentos. Se enviar apenas 3, o 4 argumento é o padrão, de valor 0.
Porém, note um erro.

Mesmo que enviemos apenas 3 argumentos, a média aritmética é calculada como se houvessem 4 notas.

Seria interessante se, caso eu enviasse 3 argumentos, ela retornasse:
(a+b+c)/3

E caso eu enviasse 4 argumentos, ela retornasse:
(a+b+c+d)/4

E isso é possível, com sobrecarga de funções.

Sobrecarga de Funções em C++

Sobrecarga, ou overloading, é a técnica que permite que tenhamos funções com mesmo nome, desde que seus parâmetros sejam diferentes.

Veja como ficaria o exemplo do programa que calcula as médias de 3 ou 4 notas:
#include <iostream>
using namespace std;

float average(float a, float b, float c)
{
    return (a+b+c)/3;
}

float average(float a, float b, float c, float d)
{
    return (a+b+c+d)/4;
}

int main()
{
    cout<<"Media de 3 numeros: "<<average(10, 9, 7)<<endl;
    cout<<"Media de 4 numeros: "<<average(10, 9, 7, 6)<<endl;

    return 0;
}
Note que invocamos a função average(), a única diferença é que na primeira chamada passamos 3 argumentos, e na segunda chamada da função passamos 4 argumentos.

Como o C++ é maroto e inteligente, ele sabe qual função rodar, corretamente.
Ele é tão esperto que, mesmo que exista o mesmo número de parâmetros/argumentos, ele consegue diferenciar através do tipo de dado que estamos usando.

Veja:
#include <iostream>
using namespace std;

double average(double a, double b, double c)
{
    cout<<"Media de 3 double   : ";
    return (a+b+c)/3;
}

int average(int a, int b, int c)
{
    cout<<"Media de 3 inteiros : ";
    return (a+b+c)/3;
}

int main()
{
    cout<<average(10.0, 9.0, 7.0)<<endl;
    cout<<average(10, 9, 7)<<endl;

    return 0;
}
Quando passamos variáveis do tipo double, ele chama a double average()
Quando passamos variáveis do tipo int, ele chama a int average()

O C++ consegue diferenciar pois as assinaturas de cada função são diferentes (seja no número de parâmetros ou no tipo que vai trabalhar).

Aliás, até se as funções tiverem o mesmo nome, o mesmo número de parâmetros e os mesmos tipos de dados, podemos fazer sobrecarga de funções, desde que a ordem dos parâmetros seja diferente:
#include <iostream>
using namespace std;

void func(int a, double b)
{
    cout<<"Primeiro é int  : "<<a<<endl;
    cout<<"Segundo é double: "<<b<<endl;
}

void func(double b, int a)
{
    cout<<"Primeiro é double: "<<b<<endl;
    cout<<"Segundo é int    : "<<a<<endl;
}

int main()
{
    func(1, 2.5);
    cout<<endl;
    func(2.5, 1);

    return 0;
}
No exemplo assim temos: func(int, double)
E também: func(double, int)

Basta que a assinatura de uma função para outra seja diferente, para podermos usar sobrecarga, onde assinatura é um conjunto de dados: nome da função, tipo de dados, número de dados e ordem das informações.

No que se refere as boas práticas de programação, você deve usar sobrecarga de funções sempre que precisar usar funções com mesmo propósito e mesma lógica, mas para número e/ou tipos e/ou ordem de dados diferentes.

Parâmetros e Variáveis de Referência de Funções em C++

Neste tutorial de nosso curso de C++, vamos aprender a passagem de argumentos por referência, em funções.

Passagem por Valor

Já aprendemos como enviar informações para funções, através dos argumentos e parâmetros.
E vimos que esta passagem é chamada passagem por valor, pois só passamos o valor para a função.

Se enviamos uma variável pra uma função, e dentro dessa função essa variável é alterada, ela não é alterada fora da função. Teste o seguinte código, que eleva um número ao quadrado:
#include <iostream>
using namespace std;

void square(int num);

int main()
{
    int number = 6;

    cout<<"Antes  : num = "<<number<<endl;
    square(number);
    cout<<"Depois : num = "<<number<<endl;

    return 0;
}

void square(int num)
{
    num = num*num;
    cout<<"Durante: num = "<<num<<endl;
}
Quando invocamos a função: square(number), estamos na verdade, passando uma cópia do valor da variável number.

Dentro da função, a variável num vai receber uma cópia do valor de number. Ou seja, ela não vai ter acesso a variável original number, somente ao seu valor! Por isso, passagem por valor.

Parâmetro de Referência: &

Seja a declaração de variável:

  • int num = 6;


O que estamos fazendo aí é alocando, reservando, um espaço na memória do seu computador.
Assim, quando usamos 'num', o C++ entende que devemos ir no endereço para onde essa variável aponta e pegar o número que está dentro daquele local da memória.

Como vimos, quando passamos essa variável normal para uma função que espera uma variável normal, ela pega apenas uma cópia de seu valor, e não mexe no conteúdo original.

Porém, existe outro tipo especial de variável, a variável de referência.
Ela é especial, pois se passarmos uma variável para uma função e a função quiser obter a variável de referência, através de um parâmetro de referência, ela vai ter acesso ao endereço da memória (a referência), onde esta variável está originalmente armazenada.

Ou seja: vamos ter acesso, de verdade, a variável, e não somente a sua cópia.

Para pegarmos a referência de uma variável, basta usarmos o operador & antes do nome da variável, no parâmetro da função! É o parâmetro de referência. Tanto no protótipo quanto na declaração da função.

Assim, o exemplo de código anterior, fica:
#include <iostream>
using namespace std;

void square(int &);

int main()
{
    int number = 6;

    cout<<"Antes  : num = "<<number<<endl;
    square(number);
    cout<<"Depois : num = "<<number<<endl;

    return 0;
}

void square(int &num)
{
    num = num*num;
    cout<<"Durante: num = "<<num<<endl;
}
Veja agora o resultado:
Variável de referência em C++ : &

De fato, a função conseguiu mudar o valor da variável, pois essa passagem de argumento para o parâmetro foi via parâmetro de referência.

O que acontece aqui é que o parâmetro não vai capturar o valor do argumento, mas sim sua referência, para onde ele está apontando na memória. Falando em apontar para um endereço, estudaremos mais sobre esse assunto nas seções de ponteiros e arrays (vetores) em C++, onde estudaremos sobre passagem por referência, usando ponteiros.

Mais sobre parâmetros de referência em C++

Alguns programadores também preferem declarar o protótipo assim:

  • square (int&);

Você também pode usar assim no protótipo:

  • square(int &num);
  • square(int& num);


Também pode, o importante é que o & esteja tanto no protótipo quanto na declaração da função, ok?

Lembrando que se seu parâmetro é de referência, ele só pode trabalhar com variável de referência.
Seria um erro se você usar um argumento que não é uma variável, como um literal, uma expressão ou uma constante, por exemplo:

  • square(10); // tem que usar square(number);
  • square(number+1); // é uma expressão, evite
Quando fazemos: square(int &num)
Leia-se: "num é uma referência para um inteiro", ou seja, ele está referenciando, apontando, indicando um local da memória em que está armazenado um inteiro. Como você tem o local da variável original, você consegue mudar esse valor.

Exercício de passagem de valor e referência

Crie um programa que pede um inteiro ao usuário. Em seguida, ele deve transformar esse valor em seu cubo. Faça isso usando uma função que recebe passagem por valor e outra que usa parâmetro e variável de referência. Deixe bem claro que uma altera o valor somente dentro da função (valor) e a outra altera o valor original da variável (referência). 

Cole nos comentários, sua solução.

Argumentos Padrão e Omissão de Argumentos

Neste tutorial de C++, vamos aprender o que é um argumento padrão, para que serve e como usar, bem como omitir um argumento numa chamada de uma função.

Argumento Padrão em C++

Já aprendemos como enviar informações para funções, através do uso de parâmetros e argumentos.
Vamos supor que queiramos somar dois números, a e b, a função seria:
float sum2(float a, float b)
{
    return a+b;
}
Agora vamos supor que queiramos calcular a soma de três variáveis, teríamos que fazer uma função assim:
float sum3(float a, float b, float c)
{
    return a+b+c;
}
Note que teríamos que usar outra função, com outro nome, pro mesmo propósito: somar os argumentos. Não é algo muito inteligente, concorda?
Seria legal se uma mesma função somasse 2 ou 3 argumentos, o tanto que o usuário quiser.

Para somar dois números, seria interessante fazer: sum(1,2);
Para somar três números, faríamos: sum(1,2,3);

É aí que entra o conceito de argumento padrão.
Basta declararmos o protótipo da função assima:

  • float sum(float a, float b, float c = 0.0);

E seu escopo:
float sum(float a, float b, float c = 0.0)
{
    return a+b+c;
}
O que ocorre é o seguinte:
O valor padrão de c é 0.0

Caso você faça: sum(1,2, 3), o valor de c será 3.
Caso faça: suma (1,2), você não estará definindo valor para c, logo ele vai assumir o valor padrão, que é 0. Entendeu? Argumento com valor padrão, caso você não forneça esse valor.

Teste:
#include <iostream>
using namespace std;

float sum(float a, float b, float c = 0.0)
{
    return a+b+c;
}

int main()
{
    cout<<sum(1,2)<<endl;
    cout<<sum(1,2,3)<<endl;

    return 0;
}
Funciona pra 2 ou 3 variáveis, a gosto do freguês!

Omissão de argumentos

O código anterior funciona para somar 2 ou 3 números.
Para somarmos 2, 3 ou 4 números, poderíamos fazer:
float sum(float a, float b, float c = 0.0, float d = 0.0)
{
    return a+b+c+d;
}
Agora você pode fazer:
sum(1,2);
sum(1,2,3);
sum(1,2,3,4);

No primeiro caso, omitimos o argumento c e o d.
No segundo exemplo, omitimos o argumento d.
No último exemplo, não omitimos nenhum argumento.

Ou seja, argumentos padrões são automaticamente substituídos, quando informamos os argumentos.

Regras no uso de argumentos padrão

Quando informamos e passamos argumentos para uma função, eles são copiados da esquerda pra direita.

Por exemplo: sum(1,2,3)
O 1 vai pro 'a', o 2 pro 'b' e o valor 3 vai pro parâmetro 'c'. O valor do argumento 'd', então, é o argumento padrão, que definimos como 0.

Outra regra é que, uma vez que usemos um argumento padrão em um parâmetro, todos os outros parâmetros subsequentes deverão também ter argumentos padrão também. Por exemplo, o protótipo de função a seguir é válido:

  • float volume(float base, float height=1, float width=1);


'height' é um argumento padrão, e o seguinte também.

Já o seguinte protótipo de função é inválido:

  • float volume(float height=1, float base, float width=1);


Como o primeiro argumento é padrão, todos os outros devem ser, e o 'base' é um parâmetro normal, que deve ser necessariamente fornecido pela chamada da função.

Outro ponto é que os parâmetros com argumentos padrão devem ser declarados na primeira ocorrência da declaração da função. Ou seja, se você usar um protótipo de uma função e depois em outro lugar vai definir o escopo da sua função, os argumentos padrão devem ser definidos já no protótipo, que vai vir antes. Por exemplo, você pode inclusive abreviar assim:

Protótipo: double area( double = 1.0, float 2.0);
Definição da função: double area (double length, float witdh) { return length*width; }

Assim, recapitulando, seja a função:
double area (double length = 1.0, float witdh = 2.0) 
{ 
   return length*width; 
} 
Se fizermos as seguintes chamadas de função:

  1. area() - serão usados os valores 1.0 e 2.0 para calcular a área, respectivamente, ou seja, estamos usando os dois argumentos padrão.
  2. area(3) - serão usados os valores 3 e 2.0 para calcular a área, ou seja, o primeiro argumento padrão foi substituído por 3
  3. area(3,6) - serão usados os valores 3 e 6 para calcular a área, ou seja, os dois argumentos padrão foram substituídos.
Vamos ver isso na prática? Teste o seguinte código:

#include <iostream>
using namespace std;

void area(float = 1.0, float = 1.0);

int main()
{
    cout << "Nenhum argumento passado:"<<endl;
    area();

    cout << "\nPrimeiro argumento passado:"<<endl;
    area(2.0);

    cout << "\nAmbos argumentos passados:"<<endl;
    area(2.0, 3.0);

    return 0;
}

void area(float length, float width)
{
    cout << "Area: " << length * width << endl;
}

Deu tudo certo? Sim? Então vamos seguir em nossos tutoriais de C++.