Programar em C++/Operadores: diferenças entre revisões

[edição verificada][revisão pendente]
Conteúdo apagado Conteúdo adicionado
m <source> -> <syntaxhighlight> (phab:T237267)
Linha 21:
Digamos que temos uma estrutura '''ponto''', como definida abaixo:
 
<sourcesyntaxhighlight lang='cpp'>
struct Ponto
{ int x;
int y;
};
</syntaxhighlight>
</source>
 
Uma vez que tenhamos definido um ponto, nada mais natural que queiramos somar, subtrair, enfim operar, pontos diferentes de acordo com nossas necessidades. Para isso podemos criar operadores para fazer isso, da seguinte forma:
Linha 33:
*Inserimos o código da referida função dentro de uma chamada de operador, usando a palavra reservada '''operator''' seguida do operador que desejamos definir:
 
<sourcesyntaxhighlight lang='cpp'>
Ponto operator+ ( Ponto a, Ponto b )
{ Ponto soma;
Linha 40:
return soma;
}
</syntaxhighlight>
</source>
 
E assim, o operador é entendido como uma função, sendo a sobrecarga um processo de definição da operação a ser executada. Recebe esse nome porque todo operador já existe e a definição de uma nova funcionalidade apenas adiciona (sobrecarrega) as habilidades anteriores do operador. Embora isto seja comum, é bom lembrar que operações de tipos primitivos não poderão ser modificadas, restando apenas a funcionalidade de criar operadores para nossos tipos (classes).
Linha 54:
Podemos ver a chamada da seguinte forma:
 
<sourcesyntaxhighlight lang='cpp'>
c = operator+( a, b );
</syntaxhighlight>
</source>
 
No momento da operação, o compilador montará a chamada do operador "+" da forma que escrevemos acima, ou seja como uma função que recebe os pontos "a" e "b" como argumentos e retorna o resultado, como operado na declaração anterior, no ponto "c". De fato, "c" será ''' ( a.x + b.x, a.y + b.y )''' como foi operado na declaração da função ( '''operator+''' ) discutida no tópico anterior.
Linha 62:
==Operadores aritméticos==
Operadores aritméticos são utilizados para efetuar operações matemáticas entre dados. São 5 operadores aritméticos em C++:
<sourcesyntaxhighlight lang=cpp>
#include <iostream>
using namespace std;
Linha 78:
 
}
</syntaxhighlight>
</source>
A saída desse programa gera no console o seguinte:
 
Linha 103:
 
Se quisermos que a divisão entre inteiros retorne a divisão real, deveremos efetuar uma conversão '''explícita''', conforme o exemplo:
<sourcesyntaxhighlight lang=cpp>
int num = 3;
int num2 = 2;
Linha 109:
cout << "Resultado: " << (float) num/num2 << endl;
// o resultado foi convertido para ponto flutuante explicitamente.
</syntaxhighlight>
</source>
 
=== Aritméticos com atribuição ===
Linha 115:
Temos, inspirados pelas operações de processador, operadores que efetuam as operações e em seguida atribuem o valor das operações a uma das variáveis participantes do processo. Temos os operadores "+=", "-=", "*=", "/=" e "%=" que basicamente funcionam da seguinte maneira:
 
<sourcesyntaxhighlight lang=cpp>
int a,b;
 
Linha 148:
cout << a << endl; // Mostrará o resto da divisão de "a" e "b" antes da operação, neste caso: "3";
 
</syntaxhighlight>
</source>
 
Observemos o que há em comum nas operações acima, em todos os exemplos temos duas variáveis "a" e "b" e um operador aritmético com atribuição. O que efetua-se em todos os exemplos é uma operação aritmética com uma atribuição final do valor calculado a uma das variáveis, que neste caso é o "a". A sintaxe é simples de entender, sempre o valor de "a" é operado com o valor de "b" e depois o valor do resultado é depositado em "a".
Linha 158:
Se tivermos que operar os números hexadecimais: "1A2C" e "2B34" podemos fazê-lo da seguinte forma:
 
<sourcesyntaxhighlight lang="cpp">
 
int Va = 0x1A2C;
Linha 186:
 
 
</syntaxhighlight>
</source>
 
Observe que convertemos, nos comentários, os números para binário a fim de facilitar a visualização de cada operação feita bit a bit. De forma simples o resultado é obtido e convertemos na saída o número para o formato hexadecimal, apenas para facilitar a visualização.
Linha 194:
A estes operadores lógicos bit a bit podemos ainda adicionar os operadores compostos da linguagem "C": "&=", "|=" e "^=" que são, respectivamente: "E" com atribuição, "Ou" com atribuição e "Ou exclusivo" com atribuição. A operação dos três operadores tem em comum o fato de funcionarem de forma semelhante. Primeiro se faz a operação "E", "Ou" ou "Ou exclusivo" entre a variável à esquerda e o número ou variável à direita, depois se atribui o resultado da operação à variável da esquerda. Vejamos os exemplos abaixo:
 
<sourcesyntaxhighlight lang="cpp">
 
int Va = 0x1A2C;
Linha 210:
cout << hex << Va << endl; // Isto mostrará na saída: "3118" que corresponde a operação "OU exclusivo" dos dois números.
 
</syntaxhighlight>
</source>
 
Notemos que os resultados são os mesmos que obtivemos quando operamos com os operadores sem atribuição, mostrados anteriormente. A diferença no modo de operação está no fato de que, ao operarmos duas variáveis, a primeira sempre recebe o resultado da operação. Este comportamento, na verdade, imita o modo de operação de alguns registradores dentro dos microprocessadores. Certamente o compilador aproveitará esta capacidade, dependendo do processador, para otimizar o código de máquina gerado durante o processo de compilação.
Linha 220:
Todos estes operadores funcionam em conjunto com as operações condicionais, como o "if" por exemplo. Vejamos alguns exemplos:
 
<sourcesyntaxhighlight lang="cpp">
#include <iostream>
 
Linha 250:
}
 
</syntaxhighlight>
</source>
 
Neste simples programa, usamos os operadores comparativos básicos. Nele, o usuário poderá digitar dois números e depois o programa informará os comparativos de magnitude dos dois números, embora os faça de maneira bastante simples, o usuário terá condições de saber se os números são iguais ou diferentes e se um é maior ou menor que o outro.
Linha 256:
Se quisermos aninhar condições, criando decisões mais complexas, podemos usar os operadores "&&", "||" e "!". Com esses operadores podemos combinar duas ou mais condições, por exemplo: Se quisermos estabelecer uma condição onde um número "b" está entre um valor "a" e outro valor "c" podemos fazer:
 
<sourcesyntaxhighlight lang="cpp">
 
#include <iostream>
Linha 274:
return 0;
}
</syntaxhighlight>
</source>
 
Neste simples exemplo, se o usuário digitar um número dentro do limite entre 5 e 14 o programa emitirá a mensagem, caso contrário não. Note que precisamos condicionar o número a estar abaixo de 14 "'''e'''" acima de 5, assim estabelecemos a faixa onde o programa reconhece como correta. A operação "(c < 14)" retorna verdadeiro quando c é menor que 14 e a operação "(c > 5)" retorna verdadeiro quando c é maior que 5, de fato, se tivermos verdadeiro nas duas operações o operador "&&" retorna verdadeiro, se qualquer das duas operações retornar falso o operador "&&" retorna falso.
Linha 290:
O operador "[]" usa-se "a[n]" é conhecido como operador de arranjo ou acesso a elemento de vetor. Este é bem mais específico das linguagens de programação baseadas na linguagem "C" e devemos analisar melhor o seu funcionamento. Digamos que temos que criar um conjunto de valores em forma de arranjo, ou "array", designado pela letra "a", então temos a1, a2, a3, ... an. Neste caso devemos declará-lo da seguinte forma:
 
<sourcesyntaxhighlight lang=cpp>
int a[5];
</syntaxhighlight>
</source>
 
Isto significa que alocamos 5 posições de memória de tipo "int" para ser usadas como arranjo, cujo nome é "a". Veja que a função de "[]" é de alocar a quantidade de 5 elementos para serem usados no arranjo. Porém, este mesmo operador tem outra função, que é de acesso aos valores dentro do arranjo, vejamos o próximo exemplo:
 
<sourcesyntaxhighlight lang=cpp>
b = a[3];
</syntaxhighlight>
</source>
 
Esta linha de código mostra como podemos atribuir à variável "b" o valor contido na quarta posição do vetor que declaramos anteriormente. Observe que apesar de termos colocado a[3] obtemos o quarto valor pois a posição a1 está atribuída ao elemento a[0], assim, se quisermos acessar o elemento a4, devemos acessar o elemento a[3].
Linha 306:
O operador "()" - parênteses também tem duas funções, embora que bem distintas. A primeira e a de agrupar operações matemáticas, como podemos ver no exemplo logo a seguir:
 
<sourcesyntaxhighlight lang=cpp>
c = ( a + b ) * 10;
</syntaxhighlight>
</source>
 
Nesta simples operação agrupamos a operação "a + b" para que seja efetuada antes da operação de multiplicação, trata-se do uso trivial da matemática, funciona da mesma forma: adiciona-se o que está entre parênteses antes de efetuar a multiplicação declarada logo após os mesmos.
Os parênteses podem ser combinados de diversas formas, sempre seguindo o uso análogo dos agrupadores matemáticos, a diferença é que não fazemos, como na matemática, o uso dos colchetes "[]" e das chaves "{}" como agrupadores. Para estas funções usamos sempre parênteses, não importando se já existam parênteses dentro de um certo agrupamento. Vejamos outro exemplo:
 
<sourcesyntaxhighlight lang=cpp>
e = ((( a + b ) * 10 - 1)*c - d)*8 - 3;
</syntaxhighlight>
</source>
 
Em matemática faríamos:
Linha 325:
A outra função do operador "()" é a chamada e declaração de função, além da participação em outros elementos de linguagem como laços, operações lógicas e switch. Vejamos alguns exemplos:
 
<sourcesyntaxhighlight lang = "cpp">
 
void myswitch(int a)
Linha 344:
}
}
</syntaxhighlight>
</source>
 
Observemos que o operador "()" é bastante usado nas linguagens "C", "C++" e derivadas... Destacamos neste exemplo a declaração da função "myswitch", o uso no laço "while" e no comando "switch", além do uso na chamada de funções "load", "configure", "execute" e "unload". Seu uso é bastante extenso e poderá ser bem explorado no decorrer da leitura deste livro.
Linha 350:
O operador () ao preceder uma variável ou valor pode agir como agente de "typecasting", ou seja, forçar que o compilador entenda que o tipo de dado é o apresentado entre parênteses. Vejamos o exemplo:
 
<sourcesyntaxhighlight lang=cpp>
void func( int x );
...
Linha 356:
...
func( (int)a );
</syntaxhighlight>
</source>
 
Neste trecho de código vemos que a função espera uma variável inteira como argumento de entrada, porém o programador quer passar uma variável tipo "float" ( que em uma máquina arbitrária qualquer tem o mesmo tamanho de um inteiro) para a função e para isto ele usa o "typecasting" na chamada da função, com isto o compilador ignora a verificação de tipo na entrada da função e aceita a variável como se ela fosse inteira.
Linha 362:
Outro uso interessante de uso do operador "()" é a conversão de tipo, faz-se "tipo(a)" para transformar uma variável de um tipo específico para outro. Observe que isto é um pouco diferente de fazer (tipo)a que não transforma nenhum tipo em outro, mas sim fazer como no exemplo abaixo:
 
<sourcesyntaxhighlight lang=cpp>
void func( char y );
...
Linha 370:
...
func(char(a) );
</syntaxhighlight>
</source>
 
Neste caso a variável "a" será convertida em um inteiro. Imaginem uma máquina em que o tipo "char" tem 8 bits e tipo "int" tem 32 bits, então o valor inteiro será transformado de 32 bits para 8 bits. Isto se torna mais relevante na chamada da função, quando só existem 8 bits na entrada da mesma, e por isso, a chamada de "char(a)" transforma o inteiro em um caractere.
Linha 378:
Como já vimos anteriormente o operador "*" é um dos operadores aritméticos, o da multiplicação, mas podemos usá-lo com outra função, como declarador de ponteiro e acesso a valor apontado por ponteiro. Primeiramente se declaramos algo como:
 
<sourcesyntaxhighlight lang=cpp>
int *a;
</syntaxhighlight>
</source>
 
Neste caso estamos declarando um ponteiro para um valor inteiro armazenado na memória. Significa dizer que se quisermos colocar um endereço de memória na variável "a" poderemos fazê-lo, desde que o endereço pertença a um valor inteiro, assim, poderemos manipulá-lo quando quisermos. Isso nos indica a necessidade de uma segunda função ao operador "*" quando usado com ponteiros, a de apontar para o valor armazenado na memória cujo endereço está em "a", vejamos:
 
<sourcesyntaxhighlight lang=cpp>
int *a = 0x3B12242C58E50023;
*a = 5 + 8;
cout << *a;
</syntaxhighlight>
</source>
 
Imaginemos que, numa máquina hipotética, tenhamos a sequência de código acima, então no endereço 3B12242C58E50023, será armazenado o valor 13, resultado da operação acima, logo após será mostrado este valor na saída do dispositivo. Porém, devemos nos atentar a uma particularidade das linguagens baseadas em "C"... na primeira linha, quando fizemos: "int *a = 0x3B12242C58E50023;" estamos declarando a variável ponteiro "a" e, só neste caso, o número que colocamos se refere ao endereço de memória para o qual ela aponta, nos demais casos que se seguem, quando fazemos "*a = " estamos colocando valores dentro da memória apontada e quando fazemos "*a" estamos nos referindo ao valor armazenado na memória apontada e não em "a". Parece um pouco confuso, não é? Mas tudo isso será abordado em mais detalhes na seção onde se aborda ponteiros e mais ainda no livro "[[Programar em C]]". Na verdade, para melhor entendimento, recomendamos que o leitor inicie o estudo de ponteiros pelo livro da linguagem "C", certamente o entendimento será muito melhor.
Linha 396:
Podemos chamar este operador de "endereço de" ou "referência a", quando o operamos junto com ponteiro podemos extrair o endereço de uma variável e, assim, colocá-lo no ponteiro. Sempre que quiseremos atribuir a um ponteiro um endereço de uma variável podemos usar o operador "&" como vemos no exemplo abaixo:
 
<sourcesyntaxhighlight lang=cpp>
int x = 23;
...
Linha 403:
a = &x;
cout << "O valor apontado pelo ponteiro a é " << *a <<endl;
</syntaxhighlight>
</source>
 
Como resultado deste trecho de código teremos na saída padrão: "O valor apontado pelo ponteiro a é 23". Note que quando fazemos "a = &x" estamos colocando o endereço da variável "x" no ponteiro "a", assim, quando fazemos "*a" acessamos o valor armazenado pela variável, que neste caso é "23".
Linha 409:
Temos outro uso do operador "&" na linguagem C++ que é dar referência de uma variável a outra. Em termos gerais funciona como dar um apelídio a um símbolo de forma que este passe a operar o conteúdo do outro. Vejamos um exemplo:
 
<sourcesyntaxhighlight lang=cpp>
int a;
int &b = a;
Linha 415:
a = 2;
cout << "O valor armazenado em a é: " << b << endl;
</syntaxhighlight>
</source>
 
Assim, o valor armazenado em "a" será o mesmo ao qual nos referimos quando acessamos "b", podemos usar tanto "a" como "b" para operar valores na variável em qualquer parte do programa pois eles se referem a uma só variável com dois nomes diferentes.
Linha 421:
Quando declaramos uma função e usamos, na declaração dos argumentos, o operador "&" passamos a operar os argumentos por chamada de referência, ou seja, se alterarmos o valor do argumento dentro do escopo da função também alteraremos o valor da variável que foi passada na chamada da função, ou seja, escopo acima. Vejamos um exemplo:
 
<sourcesyntaxhighlight lang=cpp>
void func(int &x)
{
Linha 432:
func(a);
cout << "O valor da variável é: "<< a << endl;
</syntaxhighlight>
</source>
 
Observe que o valor mostrado na saída padrão será "8" pois a função "func" recebe a variável "x" como referência de uma variável externa ao seu corpo, desta forma, quando se chama a função "func(a)" temos "a" e "x" como nomes de uma mesma variável e dentro da função, esta variável é alterada para o valor "8".
Linha 440:
Este operador é característico da linguagem C++ e apresenta uma função pertencente à orientação a objeto, refere-se a característica de declarar e se referir a elementos de outros escopos que não pertencem ao escopo atual. Por exemplo, quando queremos criar uma classe e não desejamos colocar o código das funções membro dentro da declaração da mesma utilizamos o operador de resolução de escopo, veja o código a seguir:
 
<sourcesyntaxhighlight lang=cpp>
class top{
 
Linha 463:
}
 
</syntaxhighlight>
</source>
 
Como podemos ver as funções membro "print()", "get_a()" e "get_b()" foram declaradas fora do escopo da classe, e para isso temos que adicionar o nome da classe seguido do operador "::" imediatamente antes do nome da função, esta sintaxe faz com que indiquemos ao compilador que a função que está sendo escrita pertence a classe "top", que propositalmente foi denominada desta forma para melhor entendimento. A classe topo, abriga os elementos: "top::a", "top::b", "top::c", "top::print()", "top::get_a()", "top::get_b()" e assim eles podem ser referenciados fora do corpo da mesma desde que obedecendo as regras da linguagem.