C++ From Scratch

Fonte: TecPorto
Revisão em 17h37min de 3 de junho de 2018 por João (discussão | contribs) (→‎Introdução)
Saltar para a navegação Saltar para a pesquisa

Atenção: esta página está sob constantes alterações.

Introdução

Hades dá-lhe as boas vindas ao mundo do C++.

Programar é difícil? Na realidade, não. Da mesma forma que um gestor dá instruções aos seus subordinados para que uma empresa funcione, um programador dá instruções ao computador. Este conjunto de instruções que partilham um contexto e que estão encadeadas para atingir um determinado objectivo são um programa. As instruções dadas ao computador não são muito diferentes das que um gestor daria. A diferença é apenas na sua apresentação, no seu aspecto. Da mesma forma que nós podemos pedir a alguém "se isto acontecer, então faz aquilo", o mesmo pode ser pedido a um computador.

E o que é um programador? A julgar pela definição no dicionário, um programador é um deus - porque os programadores não transformam matéria para conseguir a sua obra prima. Um programa é simultaneamente arte e ciência. E aquilo que o programador produz tem origem unicamente na sua mente. E é um engenheiro. Porquê? A engenharia é a ciência que se dedica a arranjar novas formas de fazermos menos. De termos que nos esforçar menos por sermos mais eficientes. De termos novas ferramentas que facilitem o nosso trabalho. De termos a vida facilitada naquilo que é complicado, chato e incómodo para podermos passar mais tempo naquilo que mais gostamos e com quem mais gostamos.

É preciso nunca esquecer que um computador não comete erros. Não existem erros informáticos. Existem erros humanos. Sempre que ouvirem "foi um erro do computador", já sabem que é mentira. Os computadores fazem exactamente aquilo que lhes é dito. O problema é saber como o dizer. O software não se avaria. Se o software tem erros, são erros de origem que acabam por se manifestar eventualmente. Quer dizer que o programa foi concebido com essa falha, que pode ter sido acidental, pode ter sido uma limitação imposta por decisão consciente durante o desenvolvimento, ou um defeito propositadamente criado, independentemente do motivo.

As falhas acidentais ocorrem por distracções, faltas de cuidado ou situações imprevistas. As falhas por limitação política ocorrem porque, a certa altura, se decidiu que uma determinada funcionalidade não seria viável ou necessária tão cedo, porque - erroneamente - se chegou à conclusão que determinados limites não seriam atingidos e por isso não seria necessário contemplá-los ou porque os prazos não davam para tudo e era necessário cortar. E as adicionadas de forma propositada têm, frequentemente, propósitos menos honráveis como, por exemplo, deixar o software vulnerável para que possa ser explorado.

Portanto, é fácil concluir que está nas nossas mãos, enquanto criadores, garantir a qualidade do produto. Não é erro do computador. É erro nosso. Quando um programa falha a um utilizador, não foi uma falha do computador. Foi uma falha nossa.

(NOTA: os computadores são máquinas e, como qualquer outra máquina, têm um tempo de vida limitado, por muito longo que esse tempo de vida possa ser se for de qualidade, bem tratado e estimado. Por outro lado, eventos como picos electromagnéticos e radiação cósmica, como por exemplo, a proveniente de tempestades solares, podem induzir erros nos computadores. Mas esses erros e essas avarias são invariavelmente de extremos, ou catastróficas ou suficientemente discretas para se tornarem imperceptíveis e são eventos com um índice de raridade tal que não explicam a frequência com que a justificação "foi erro informático" surge. Diversas auditorias comprovam que, salvo raríssimas excepções, as situações que frequentemente originam tal justificação se devem, na realidade, a erros de introdução de dados, configurações incorrectas ou manuseamento impróprio dos sistemas em questão.)

TODO: Inserir referência às origens do C++

Conceitos básicos

Antes de se prosseguir, é necessário ter em consideração alguns conceitos básicos cujo conhecimento lhe irão dar uma maior facilidade a aprender a programar, a dominar o seu equipamento e a criar programas mais eficientes, estáveis e seguros. Se está a estudar este documento, alguns destes conceitos já deviam estar bem sabidos, mas pela minha experiência, temo que seja melhor relembrar.

Uma pequena introdução teórica

O sistema operativo

Para que o seu computador possa realizar trabalho, não basta existir. O hardware, por si só, não faz nada. Antes de poder realmente usar o seu computador para ser produtivo, o mesmo tem que ter um sistema operativo instalado. Este pode vir já de fábrica com o computador ou ser instalado por si, à sua escolha. Mas tem que lá estar. Sem o sistema operativo, o computador não tem a camada base necessária para que os programas possam funcionar. O sistema operativo é responsável por fornecer uma camada de abstracção aos programas, que disfarce os componentes de uma forma tal que, independentemente do hardware, todos os programas vejam os recursos da mesma forma e tenham acesso às mesmas funcionalidades. O próprio sistema operativo, apesar de não ser sempre encarado directamente como tal, é também um programa, apenas mais complexo, mais poderoso e com mais controlo sobre o hardware do seu computador.

No fundo, as principais responsabilidades do sistema operativo são gerir os programas em execução - os processos - e a memória do computador. E, adicionalmente, através dos controladores de dispositivo - ou drivers - apresentar o hardware disponível ao programa de uma forma que seja mais útil e genérica.

A memória

TODO: falar do espaço de endereçamento físico e virtual

A bus do computador

O processo

Quando um programa está em execução, é chamado de processo. Um processo é uma unidade básica de execução que é controlada pelo sistema operativo do computador.

Programar

Então, e como se programa um computador? Ora, tal como nós, programadores, existimos para facilitar a vida ao utilizador final que vai usar o nosso programa, também outros programadores nos facilitam a vida a nós. Como? Desenvolvendo ferramentas que tornam mais fácil a tarefa de dar instruções a um computador.

Hoje em dia até é possível uma pessoa falar para um computador, dar-lhe uma instrução em voz e o computador executar. Mas para isso acontecer, é necessário que haja um programa que captura o que é dito, trate, interprete e depois execute essa instrução. E esse programa foi feito usando uma linguagem de programação. Uma linguagem de programação é um meio de um programador "falar" com o computador e lhe dar instruções. Ora, acontece que há vários níveis de linguagens de programação.

Programar é um processo extremamente complexo, que não envolve apenas escrever instruções, envolve várias fases, desde o planeamento até à preparação final do programa. O computador não entende Português, Inglês ou Francês. O computador entende sinais. O hardware só consegue processar sinais eléctricos - ou luminosos - que entende como sendo zeros ou uns. E esses zeros ou uns em conjunto causam reacções nos vários componentes do computador. Esses zeros e uns compõem as instruções que o computador recebe no seu nível mais baixo, mais próximo do hardware. E dar os comandos em voz, ou com o rato, ou com o teclado a um computador, é o nível mais alto. No que toca a computadores e a linguagens de programação, quanto mais alto o nível, mais próximo se está do utilizador. Quanto mais baixo, mais próximo se está do hardware.

O compilador

O programador não produz logo zeros e uns que o computador entende. Ele escreve instruções, num formato que é igualmente fácil de entender para o ser humano e computacionalmente fácil de tratar pela máquina. Para o programa ser, mais tarde, executado pela máquina, essas instruções têm que ser processadas e passadas de algo que inicialmente é mais orientado para o ser humano para algo que seja mais orientado para o computador entender. A essa transformação chama-se compilação. A compilação pode ser um processo mais ou menos complexo dependendo da linguagem de programação, das ferramentas usadas e da complexidade e dimensão do próprio projecto. Dessas ferramentas, a mais importante de referir agora é o Compilador. É, também, um programa. É o programa responsável por interpretar o que o humano escreveu e traduzir para que o computador entenda. É a analogia perfeita, pensem no compilador como sendo um intérprete, um tradutor. Da mesma forma que um intérprete das Nações Unidas ou da União Europeia pode traduzir Português para Inglês, Francês para Alemão, Espanhol para Klingon, também o compilador traduz de humano para binário.

Para C++, como para muitas outras linguagens, há vários compiladores diferentes, produzidos por instituições diferentes. A linguagem é padronizada por uma instituição chamada ISO (International Standards Organization) mas pode haver leves diferenças entre os compiladores, geralmente em funcionalidades altamente específicas. Alguns compiladores apresentam extensões à linguagem base padrão. É preciso ter cuidado quando se usa a documentação específica dos compiladores e confirmar sempre com o padrão o que é original e o que é específico. Neste livro irá ser evitado o uso de qualquer extensão não-standard. Quando alguma extensão for usada, tal situação será identificada devidamente.

Convém conhecer alguns dos compiladores mais populares, entre eles (sem nenhuma ordem em particular):

Nome Instituição Licença Notas
CLang LLVM Aberta
ICC Intel Corporation Comercial/Gratuita para projectos de código aberto
G++ (Gnu Compiler Collection) GNU Open source (GPL3)
Visual C++ Microsoft Corporation Comercial Faz parte do conjunto de ferramentas Microsoft Visual Studio, mas também é disponibilizada uma versão reduzida e gratuita chamada Visual C++ Express

A programação estruturada

O paradigma de "programação estruturada" tem este nome porque o código é estruturado em blocos lógicos chamados funções. Em código bem organizado, as funções serão blocos de código isolados. Serão como caixas negras, que recebem dados e devolvem resultados.

Para analogia, pense-se numa função como sendo uma pessoa. Imaginemos o caso de um juiz de um jogo de xadrez, a quem podemos perguntar se uma determinada jogada é válida. Naturalmente, o juiz, saberá as regras todas e, para produzir uma resposta, necessita de dados concretos. Essa resposta, neste caso, será apenas "sim" ou "não", "válida" ou "inválida", "verdadeiro", ou "falso". Isso é o chamado "valor de retorno" de uma função. E os dados que o juiz precisa para decidir a legalidade da jogada, quais são? Neste caso, seria a identificação da peça (algo que identificasse qual o tipo de peça e o jogador a quem pertencia), a localização actual da peça no tabuleiro e a localização pretendida da peça. Só tendo estes dados é que o juiz pode tomar uma decisão.

Já sabemos o que é preciso e o que é esperado - é altura de pensar no algoritmo. Tipicamente, é importante começar do mais genérico para o mais específico. Nunca damos muita importância a isso, mas se formos analisar o nosso próprio pensamento, quando temos nós que tomar decisões, é o mesmo que fazemos. O nosso pensamento (e o processo de funcionamento dos computadores) funciona como uma árvore, com várias ramificações, com vários caminhos possíveis. E nós vamos eliminando caminhos durante o processo de decisão. Cada caminho possível diferente, cada ramo, corresponde a uma condição específica do processo de decisão. O nosso objectivo, no final, é ficar com um resultado - uma folha. Para podermos decidir de forma eficiente, é necessário que, em cada condição, se possa eliminar o máximo de outros ramos do processo de decisão, para se diminuir o número de avaliações a fazer. Daí ser tão importante começar do mais genérico para o mais específico.

Fôssemos nós o juiz do jogo, a primeira coisa que iríamos avaliar era a quem pertence a peça, para sabermos de que lado contemplar a decisão. De seguida, iríamos avaliar qual a peça, para sabermos que conjunto de regras aplicar, porque cada peça se move de forma diferente no tabuleiro. E, finalmente, iríamos avaliar se a localização de destino da peça é válida, comparando a posição de destino com a de origem e verificando se corresponde a alguma das possíveis variações. Por exemplo, se fosse um bispo, iríamos determinar se a jogada correspondia a uma movimentação na diagonal (ou seja, teria que se movimentar igual número de casas em ambos os eixos, algo facilmente determinável pela comparação dos valores absolutos das diferenças de posição num eixo e no outro).

Em programação, o processo é o mesmo. Ao criarmos a nossa função para avaliar se uma jogada é válida, fazemo-lo de forma a que o programa siga o mesmo processo, ainda que a disposição visual do código não o demonstre de forma tão directa. Assim, também é importante planear os algoritmos cuidadosamente, especialmente quando são muito complexos e, se possível, construir fluxogramas que representem o algoritmo. Com algoritmos muito complexos é, por vezes, boa ideia parti-los em blocos e esses blocos em blocos mais pequenos, recursivamente, em vários diagramas cada vez mais simples. Isto permite gerir melhor a implementação. É a aplicação do método "Jack o Estripador" - "vamos por partes". A implementação pode, depois, ser feita com base nos blocos mais pequenos, construídos, analisados e testados um a um, que depois vão sendo integrados. A complexidade diminui, porque em vez de um grande algoritmo complexo tem-se vários pequenos algoritmos simples, a detecção de erros torna-se mais eficaz e tem-se maiores garantias da validade formal da implementação.

Funções

No seu uso prático, uma função tem essencialmente dois grandes componentes, a declaração e o corpo ou implementação. A declaração é uma descrição formal da função. É a sua assinatura. Indica o que é que a função pode devolver (o tipo de dados), o seu nome, e o que é que ela precisa de receber para trabalhar (os parâmetros ou argumentos). Voltando à analogia do juiz de xadrez, então o tipo de dados seria, neste caso, um booleano (bool), que só devolve verdadeiro (true) correspondendo a uma jogada válida ou falso (false) correspondendo a uma jogada inválida. O nome poderia ser o nome do juiz ou até, simplesmente, "juiz", e os argumentos seriam os dados necessários para o juiz avaliar (o jogador, o tipo de peça, a posição original e a posição de destino).

Vamos analisar como seria a declaração da função em pseudo-código:

booleano juiz(jogador, tipo de peça, posição original, posição de destino);

Partindo os seus elementos para fazer a correspondência com os três componentes da declaração, temos "booleano" como sendo o tipo de valor de retorno (o resultado), temos "juiz", como sendo o nome da função e, dentro de parêntesis, uma lista separada por vírgulas dos parâmetros "jogador", "peça", "posição original" e "posição de destino".

Agora é altura de pensar na segunda parte da função, a implementação - o algoritmo.

// TODO

As classes e os objectos

A programação orientada a objectos é um paradigma mais avançado do que a programação estruturada. Com as classes e os objectos podemos criar os nossos programas com uma lógica que se aproxima ainda mais à forma como nós próprios visualizamos os conceitos mundanos que conhecemos e como abordamos o dia a dia. Já alguma vez esteve a ver um filme estrangeiro e, de repente, no meio de todo o diálogo numa língua que desconhece, ouviu umas palavras na sua própria língua mas, inesperadamente, ficou confuso, não identificou logo a língua e ficou uns momentos a pensar "mas que língua é esta?"? Ora, quando chegar à secção que fala sobre objectos não se assuste. Depois de estar alguns capítulos a abordar a programação estruturada, poderá, inicialmente, achar a programação orientada a objectos mais confusa. Mas não se iluda. Muito pelo contrário, a programação orientada a objectos aproxima-se ainda mais da sua linguagem do dia a dia. Portanto, é mais simples, apesar de bastante mais poderosa.

Com a programação orientada a objectos pode descrever no seu próprio programa uma abstracção de um objecto real, identificar as suas propriedades ou atributos e aplicar-lhe acções - os chamados métodos. Por exemplo, um carro tem atributos como a cor, o peso, o comprimento, a cilindrada, a largura, o tipo de combustível. O ser humano também tem atributos como a altura, o peso, a cor dos olhos, a cor do cabelo, a idade. São características. E depois cada um tem também as suas acções, ou métodos. No caso do carro, os métodos poderiam ser "avança em frente", "vira à esquerda", "desliga o motor", "liga o motor". No caso do humano, os exemplos poderiam ser "anda", "salta", "corre", "respira", "come".

O C++

Símbolos

// TODO

Estruturas básicas

Tal como o gestor dá instruções aos seus funcionários, "faz isto", "vai buscar aquilo", "se encontrares isto, então faz aquilo", "enquanto houver isto, faz aquilo", também o programador pode dar instruções ao computador. As instruções são, em tudo, semelhantes às do gestor. Mas como o computador é uma máquina, e como uma máquina não fala directamente com humanos, a forma de dar as instruções é levemente diferente. A apresentação dessas instruções tem um aspecto um pouco mais matemático e mais fácil de ser processado pelo computador, mantendo legibilidade facilidade de compreensão pelo ser humano.

Variáveis

Pense, inicialmente, numa variável como uma caixa de correio. Uma caixa de correio tem um nome (o nome do morador) e um endereço (uma rua, um número de polícia, um andar e uma porta). Uma variável também tem um nome e um endereço. Uma caixa de correio é um espaço onde pode ser colocado conteúdo. Seguindo a mesma analogia, a uma variável também é possível dar conteúdo. Uma variável, no entanto, é uma localização - um endereço - da memória do computador onde se pode colocar informação, da mesma forma que uma caixa de correio é um espaço onde pode ser colocada uma carta. Pense, então, na carta, como a informação a ser colocada na variável - o valor.

Em matemática existe algo semelhante às variáveis - as incógnitas. A diferença é que as incógnitas podem ter qualquer valor matemático de qualquer conjunto numérico. Nas variáveis de um programa, os valores e os tipos disponíveis diferem um pouco.

As variáveis, para além do nome e do endereço, têm também um tipo. O tipo define que conteúdo podem ter.

Existem os seguintes tipos básicos de variáveis, os chamados P.O.D. (Plain Old Data):


Tipo Descrição Tamanho Intervalo de valores Notas
bool Booleano; apenas tem dois valores possíveis, verdadeiro ou falso. dependente da arquitectura true ou false O resultado de qualquer operador comparativo é um booleano.
char Caractere; é um tipo numérico básico correspondente a exactamente um byte. 8 bits (1 byte) -128 a 127
int Inteiro; dependendo da arquitectura, 16 bits (2 bytes), 32 bits (4 bytes) ou 64 bits (8 bytes) xxxxx
float Vírgula flutuante de precisão simples xxxxx xxxxx
double Vírgula flutuante de precisão dupla xxxxx xxxxx

Para se usar uma variável, ela tem que, primeiro, ser declarada. Declarar uma variável é indicar ao compilador que ela tem que existir. Ao declarar uma variável estamos a dar-lhe um nome e, quando o programa é transformado pelo compilador de um texto num ficheiro binário executável, o compilador trata de preparar tudo de forma a que o espaço para essa variável seja criado na memória do programa, quando a mesma for necessária. É de reparar que foi mencionado "quando for necessária", porque uma variável também tem um tempo de vida. Uma variável tem um início e um fim. Geralmente é criada e inicializada quando é necessária e destruída quando essa necessidade termina.

Manipulação de variáveis

Para manipular as variáveis usa-se os chamados Operadores. Manipular é testar ou alterar uma variável. Os operadores têm características próprias como o número de operandos, se alteram ou não algum dos seus operandos, a acção que realizam, o ponto de sequência e se podem ser sobrecarregados ("overloaded" - ver secção sobre sobrecarga de operadores).

Quanto ao número de operandos, os operadores podem ser unários, binários e ternários, dependendo de terem, respectivamente, um, dois ou três operandos. Existe a situação de um símbolo poder definir dois operadores diferentes (o caso dos operadores "+", "-", "&", "*", e "<"/">"). Neste caso os operadores são distinguidos não pelo símbolo, mas pelo contexto e número de operandos.

Existem os seguintes operadores:

Operadores aritméticos

Operador Sintaxe Tipo Descrição
Atribuição simples = var = exp; Binário Atribui o valor resultante da expressão "exp" à variável "var"
Soma + exp1 + exp2 Binário Gera uma expressão composta cujo resultado é a soma dos resultados de "exp1" e "exp2"
Subtracção - exp1 - exp2 Binário Gera uma expressão composta cujo resultado é a subtracção dos resultados de "exp1" e "exp2"
Multiplicação - exp1 * exp2 Binário Gera uma expressão composta cujo resultado é a multiplicação dos resultados de "exp1" e "exp2"
Divisão - exp1 / exp2 Binário Gera uma expressão composta cujo resultado é a divisão dos resultados de "exp1" por "exp2"
Módulo - exp1 % exp2 Binário Gera uma expressão composta cujo resultado é o resto da divisão de inteiros do resultado de "exp1" por "exp2"
Incremento ++ ++ var;
ou
var ++;
Unário Incrementa a variável "var" na unidade; no caso de apontadores, incrementa a variável no tamanho do tipo para o qual aponta
Decremento -- -- var;
ou
var --;
Unário Decrementa a variável "var" na unidade; no caso de apontadores, decrementa a variável no tamanho do tipo para o qual aponta
Auto-soma += var += exp; Binário Soma à var "var" o valor resultante de "exp"
Auto-subtracção -= var -= exp; Binário Subtrai à variável "var" o valor resultante de "exp"
Auto-multiplicação *= var *= exp; Binário Multiplica a variável "var" pelo valor resultante de "exp"
Auto-divisão /= var /= exp; Binário Divide a variável "var" pelo valor resultante de "exp"
Auto-módulo %= var %= exp; Binário Atribui à variável "var" o resto da divisão de inteiros de si própria pela expressão "exp"

Operadores lógicos

Operador Sintaxe Tipo Descrição
E && expressão1 && expressão2 Binário A expressão resultante é verdadeira se e só se ambas as expressões "expressão1" e "expressão2" forem verdadeiras. Se "expressão1" for falsa, "expressão2" não chega a ser avaliada.
Ou || expressão1 || expressão2 Binário A expressão resultante é verdadeira se qualquer uma das expressões envolvidas for verdadeira. Se "expressão1" for verdadeira, "expressão2" não chega a ser avaliada.
Negação ! !expressão1 Binário O valor lógico de "expressão1" é invertido, se o valor de "expressão1" for verdadeiro, a expressão resultante é falsa, se for falsa o valor é verdadeiro.

De notar que, no caso das operações lógicas não existe um "Ou exclusivo". No entanto o mesmo efeito poderia ser alcançado com a expressão "(!expressão1 != !expressão2)".

Operadores relacionais/comparativos

Operadores bit-a-bit

Instruções de controlo de fluxo

As instruções de controlo de fluxo são as responsáveis pelas decisões no programa. São estas instruções que determinam quais dos potencialmente infinitos caminhos de um programa serão tomados. Voltando à analogia de um gestor, considere o seguinte quadro:

Sintaxe na nossa linguagem O que o gestor diria Sintaxe em C++ Exemplo em C++ Descrição Notas
se condição então predicado Se não houver parafusos então encomenda novos. if(condição) predicado; if(0 == num_parafusos)
encomenda_parafusos();
se a condição "condição" se verificar, "predicado" é executado.
enquanto condição faz predicado Enquanto tiveres comida no prato, continuas a comer while(condição) predicado; while(esta_cheio(prato))
come_de(prato);
enquanto a condição "condição" se verificar, "predicado" é executado.
faz predicado enquanto condição Come até não teres comida no prato do predicado while(condição); do come_de(prato)
while(esta_cheio(prato))
"predicado" é executado enquanto a condição "condição" se verificar. É a instrução oposta ao while, esta instrução executa primeiro, verifica depois e volta ao início do ciclo.
for([inicialização]; condição; [actualização]) predicado; "predicado" é executado enquanto a condição "condição" for verdadeira; de cada vez que "predicado" é executado, a "actualização" é executada imediatamente a seguir. Esta instrução e o while podem ser usados de forma equivalente.
break;
continue;
switch(expressão)
{
case caso1: predicado1; [break];
...
[default: predicado;]
}
goto etiqueta;

Tipos compostos

Funções

Voltemos a abordar o exemplo da introdução teórica, que tinha a seguinte declaração em pseudo-código:

booleano juiz(jogador, tipo de peça, posição original, posição de destino);


Voltando também a analisar os componentes, temos "booleano" como tipo de valor de retorno, temos "juiz", como nome da função e, dentro de parêntesis, a lista de parâmetros.

Em C++, a declaração é parecida, mas há regras a que obedecer:

Em primeiro lugar, como descrito anteriormente, os "símbolos" (nomes usados dentro do programa), que neste caso são os nomes das funções e dos parâmetros, só podem conter letras não acentuadas, números e o travessão inferior (underscore) tendo, obrigatoriamente, que começar por uma letra ou um underscore.

Em segundo lugar, os parâmetros, na sua declaração, têm que ser precedidos pelo seu tipo. Mais ainda, os tipos básicos de C++, são unitários. Não existem tipos básicos compostos, todos esses terão que ser criados pelo programador por outros métodos. Isso significa que, a menos que o programador efectivamente crie esses tipos compostos, as posições presentes nos parâmetros não poderão ser passadas sem serem quebradas nas suas coordenadas, dado que as coordenadas de um tabuleiro de xadrez variam em dois eixos - que aqui consideraremos como sendo X e Y. Sabemos, no entanto, que cada uma dessas coordenadas são limitadas a valores inteiros de 0 a 7 (oito posições diferentes em cada direcção, ou seja, oito linhas e oito colunas, dando o total de 64 casas).

E depois temos que, também, ter forma de representar os jogadores e os tipos de peças. Como já explicado, os computadores não pensam, os computadores calculam. O que também significa que a melhor forma de tirar partido do poder computacional dessa máquina é transformar as tarefas que tem que executar em regras matemáticas para poderem ser tratadas como cálculos. É portanto, razoável querer representar os jogadores por números. Por exemplo, representar o jogador que fica com as peças pretas como 0 e o jogador que fica com as peças brancas como 1. E com as peças, passa-se a mesma situação. Caberá ao programador representar as peças de tal forma a que o programa (o jogo de xadrez) consiga permitir ao seu utilizador saber de que tipo de peça se trata. Mas para as decisões do programa, as mesmas têm que estar representadas de uma forma que seja eficiente e que, acima de tudo, o computador entenda. Para tal, também para representar os tipos de peças, nada melhor que usar números.

Como não temos meio jogador, nem meio tipo de peça, também esses dois dados são valores inteiros. Os jogadores, um valor de 0 ou 1 e seis tipos diferentes de peças, que poderemos representar com os números de 0 a 5.

Podemos então produzir uma nova declaração da função, desta vez já em C++:

bool juiz(int jogador, int tipo_peca, int pos_orig_x, int pos_orig_y, int pos_dest_x, int_pos_dest_y);

// TODO

Classes e objectos