Resumo
Até aqui, cada programa do curso foi um único bloco, main, no qual tudo se escreve onde se usa. Esta aula ensina a dar nome a uma parte de um programa e a usá-la sem olhar para o seu interior: a função. Estudam-se a declaração, que anuncia ao compilador o nome, o tipo de retorno e os parâmetros; a definição, que acrescenta o corpo; e a chamada, que transfere o controle para esse corpo e recebe o valor devolvido. Distingue-se o que o compilador verifica ao compilar (que cada chamada concorde com uma declaração) do que ocorre ao executar (o salto para a definição e o regresso). Explica-se por que chegar ao final de uma função que deve devolver um valor sem um return é comportamento indefinido. Segue-se a execução com a pilha de chamadas, que guarda um quadro para cada chamada em curso. E especifica-se cada função com um contrato, sua pré-condição e sua pós-condição, que diz o que a função exige de quem a chama e o que garante em troca.
Objetivos de aprendizagem
- Declarar, definir e chamar funções com parâmetros e valor de retorno, e indicar em um programa qual parte é a declaração e qual a definição.
- Seguir com um diagrama da pilha de chamadas a execução de um programa com funções que se chamam entre si.
- Especificar uma função com sua pré-condição e sua pós-condição, e escrever uma chamada que viole a pré-condição.
- Explicar por que uma função que não devolve valor em algum caminho é comportamento indefinido, e reconhecer o aviso do compilador correspondente.
Por que funções
Os programas da unidade anterior resolviam cada problema dentro de main, e isso bastou enquanto os problemas eram pequenos. Ora, assim que um programa cresce, aparecem três dificuldades. A primeira é a repetição: se o mesmo cálculo é necessário em três lugares, escreve-se três vezes, e um erro nele se corrige três vezes (ou se esquece de corrigi-lo em uma delas). A segunda é a leitura: um bloco de cinquenta linhas não diz o que faz, mas como o faz, e o leitor deve reconstruir a intenção a partir do mecanismo. A terceira é o teste: se tudo está misturado, não há maneira de verificar uma parte sem executar o resto.
Uma função é um fragmento de programa com nome, que recebe dados, chamados parâmetros, e entrega um resultado, chamado valor de retorno. A matemática conhece a ideia há séculos: a distância entre dois pontos do plano é uma função de suas quatro coordenadas, , e quem calcula o perímetro de um triângulo não repete a fórmula três vezes, mas a nomeia e a aplica três vezes. Em C++ escreve-se o mesmo.
O programa lê as coordenadas dos três vértices de um triângulo e escreve seu perímetro, que é a soma dos comprimentos de seus três lados.
#include <cmath>#include <iostream>#include <print>// Distância entre os pontos (x1, y1) e (x2, y2).double distance(double x1, double y1, double x2, double y2){ const double dx{x2 - x1}; const double dy{y2 - y1}; return std::sqrt(dx * dx + dy * dy);}int main(){ double ax{}; double ay{}; double bx{}; double by{}; double cx{}; double cy{}; std::cin >> ax >> ay >> bx >> by >> cx >> cy; const double perimeter{distance(ax, ay, bx, by) + distance(bx, by, cx, cy) + distance(cx, cy, ax, ay)}; std::println("Perímetro: {}", perimeter);}0 0 3 0 0 4Perímetro: 12Os lados do triângulo de vértices , e medem 3, 5 e 4, e sua soma é 12.
A função distance escreve-se uma vez e usa-se três; main lê-se como a definição do perímetro, “a soma de três distâncias”; e distance pode ser testada sozinha, com um par de pontos cuja distância se conhece. Ganham-se assim as três coisas que faltavam. O ensinamento geral, que vale em qualquer linguagem, é que uma função nomeia uma ideia: quem a usa pensa no que ela faz, não em como o faz. Essa separação entre o uso e a realização chama-se abstração procedural, e é o tema de toda a unidade.
Carregando o conteúdo…