O documento apresenta um resumo de um minicurso sobre C++. É dividido em sete partes, cobrindo visão geral, fundamentos, estruturas de dados, funções, programação orientada a objetos básica, intermediária e avançada.
6. C++::ORIGENS
Para superar as limitações da linguagem C, Bjarne Stroustrup constrói, em 1980 nos
Laboratórios Bell (Nova Jérsei, EUA), um conjunto de extensões para permitir a
criação de programas melhores e mais complexos, principalmente do ponto de vista
de projeto.
Estrutura sintática da linguagem C
Conceitos de classe da linguagem Simula67
Sobrecarga de operadores do Algol68
Resultou no “C with Classes”, cujo nome foi alterado para C++ (“C plus plus” cujo
sentido pretendido era “C com algo mais”).
A adoção surpreendentemente grande fez com que fosse padronizada pela ANSI e
ISO em 1990. Atualmente seu padrão é a ISO/IEC 14882.
20/04/2017 (C) 2017, PJANDL. 6
8. C++::CARACTERÍSTICAS
Simplicidade
Estrutura sintática simples e concisa. Oferece
sistema de divisão modular que favorece o
reuso.
Performance
Ausência de restrições e mecanismos embutidos
de controle possibilitam a geração de código
em linguagem de máquina conciso e muito
eficiente.
Portabilidade
A padronização efetiva faz com que, quando
seguida, possibilite a recompilação do código
fonte para diferentes plataformas sem
necessidade de qualquer ajuste ou alteração.
Versatilidade
Embora com sintaxe simples, é uma linguagem
de alto nível que permite a expressão de
algoritmos e estruturas de dados sofisticadas,
acesso ao hardware e integração com outras
linguagens de programação.
20/04/2017 (C) 2017, PJANDL. 8
9. C++::ABSTRAÇÃO
C++ permite que a programação seja
realizada de maneira genérica.
Possibilita a definição de novos tipos.
Garante isolamento adequado entre
as funcionalidades existentes.
Permite uso amplo e eficiente dos
conceitos da programação orientada a
objetos.
20/04/2017 (C) 2017, PJANDL. 9
10. C++::RECURSOS NECESSÁRIOS
GNU C++ Compiler [“nativo” no Linux, disponível para Windows como MinGW:
http://www.mingw.org/ ]
Dev C++ [IDE free, open source, disponível para Windows e outras
plataformas: http://www.bloodshed.net/dev/devcpp.html ]
Eclipse C++ IDE [tradicional IDE Java com plugins para desenvolvimento C++:
http://www.bloodshed.net/dev/devcpp.html
Requer MinGW em sistemas Windows]
VisualStudio C++ [IDE popular da Microsoft também permite desenvolvimento
voltado para C++]
20/04/2017 (C) 2017, PJANDL. 10
12. (O)
EXEMPLO _HELLO
(MAIS TRADICIONAL DE TODO MUNDO)
/* Arquivo: main01.cpp
Autor: Prof. Peter Jandl Jr
*/
#include <iostream>
using namespace std;
int main() {
// impressão de mensagem no console
cout << "Hello world!" << endl;
// finalização do main (funcão principal)
return 0;
}
20/04/2017 (C) 2017, PJANDL. 12
include: efetua a
inclusão de uma
biblioteca no programa.
using namespace:
indica o uso de um
espaço declarativo
(no caso o padrão std).
Para um programa mínimo em
C++ basta remover a diretiva de
impressão cout.
14. C++::ESTRUTURA DOS PROGRAMAS
Programa em linguagem C++
são compostos de um ou mais
arquivos de programa fonte,
cada um considerado uma
unidade de compilação (ou
translation unit).
Cada unidade de compilação
pode conter:
diretivas do pré-processador
(include, define, if, ifdef...)
declarações de:
variáveis;
estruturas de dados;
funções; e
classes.
implementação de:
funções; e
classes.
20/04/2017 (C) 2017, PJANDL. 14
15. C++::VARIÁVEIS
Variáveis são nomes definidos pelo
programador para os quais podem ser
associados valores.
Em linguagens fortemente tipadas, como
C++, tais valores devem pertencer a um
tipo (que determina uma faixa de
valores aceitáveis ou pertencentes a um
elemento).
Sintaxe:
<Tipo> <nome1> [, <nome2> [...] ];
Identificadores válidos:
sequência de um ou mais caracteres alfabéticos,
dígitos numéricos e `_` (sublinhado), iniciados
por letra ou sublinhado.
usualmente apenas 32 primeiros caracteres são
usados para distinção dos identificadores.
C++ é sensível ao caixa, ou seja, diferencia
maiúsculas de minúsculas.
Palavras reservadas não podem ser usadas
como identificadores.
20/04/2017 (C) 2017, PJANDL. 15
16. C++::KEYWORDS*
(PALAVRAS RESERVADAS*)
auto bool break case catch char
class const const_cast continue default delete
do double dynamic_cast else enum explicit
export extern false float for friend
goto if inline int long mutable
namespace new operator private protected public
register reinterpret_cast return short signed sizeof
static static_cast struct switch template this
throw true try typedef typeid typename
union unsigned using virtual void volatile
while
20/04/2017 (C) 2017, PJANDL. 16
São destacadas as
47 que serão vistas
neste tutorial.
C++ possui 61
keywords.
*Emitálico,keywordscompatilhadascomC.
17. C++::TIPOS DE DADOS
Estão disponíveis os tipos de dados pré-
definidos típicos da maioria das LPs:
caracteres
inteiros
ponto flutuante
lógico
Também existem tipos derivados e a
possibilidade de definição de novos tipos
por parte do programador.
Tipos de
Dados C++
Tipos de
Dados C++
Pré-
definidos
Pré-
definidos
IntegraisIntegrais
charchar
intint
Ponto
flutuante
Ponto
flutuante
floatfloat
doubledouble
LógicoLógico boolbool
DerivadosDerivados
ArranjoArranjo
FunçãoFunção
PonteiroPonteiro
ReferênciaReferência
DefiníveisDefiníveis
EnumeraçãoEnumeração
EstruturaEstrutura
ClasseClasse
UniãoUnião
20/04/2017 (C) 2017, PJANDL. 17
18. C++::TIPOS DE DADOS
Existem modificadores
short
long
signed
unsigned
Quando aplicados aos tipos integrais
permitem reduzir/ampliar a faixa de
valores e também desconsiderando o
sinal.
Existe também o tipo void, especial,
que sinaliza a ausência de resultado.
20/04/2017 (C) 2017, PJANDL. 18
20. C++::TIPOS DE DADOS
Inteiros
int a = 2;
signed int x = -13;
long int y = 95000L; // sufixo L
unsigned int z = 765u; // sufixo u
int h = 0xCAFE; // prefixo 0x : hexa
int octal = 02000; // prefixo 0 : octal
Dica
Arquivo de cabeçalho (header file)
"climits.h" da biblioteca padrão contém
os tamanhos em bytes, bem como os
valores mínimos e máximos dos tipos
primitivos e outros eventualmente
adicionados pela implementação.
20/04/2017 (C) 2017, PJANDL. 20
21. C++::TIPOS DE DADOS
Ponto flutuante
float f = 1.46;
float c = -25.34e8;
double d = 534.789e-11;
long double ld = 143.2314673595l;
Lógico
bool flag = true;
bool error = false;
Também existe equivalência entre tipos
lógicos e numéricos, tal como na
linguagem C:
valores iguais a zero equivalem a false
valores diferentes de zero equivale a true
20/04/2017 (C) 2017, PJANDL. 21
long também se aplica ao tipo
double e suas constantes
requerem o sufixo l ou L.
22. EXEMPLO _SIZEOF
/* Arquivo: main02.cpp
Autor: Prof. Peter Jandl Jr
*/
#include <iostream>
using namespace std;
int main() {
cout << " char:" << sizeof(char) << "n bool:" << sizeof(bool) << endl;
cout << " short:" << sizeof(short) << "n int:" << sizeof(int) << endl;
cout << " long:" << sizeof(long) << "n float:" << sizeof(float) << endl;
cout << " double:" << sizeof(double) << "n long double:"
<< sizeof(long double) << endl;
return 0;
}
20/04/2017 (C) 2017, PJANDL. 22
sizeof retorna o
tamanho em bytes do
tipo indicado
endl é uma constante
e representa o fim de
uma linha de texto.
23. C++::CONSTANTES
Definidas
Identificador associado a um valor literal
constante.
#define <id> <valor>
Exemplos:
#define PI 3.1415926
#define MAX 1024
Durante pré-processamento do programa,
identificador será substituído pelo literal
previamente indicado.
Declaradas
Variável cujo conteúdo está associado
ao tipo especificado, mas que não pode
ter valor alterado durante execução do
programa.
const <tipo> <id> = <expr>;
Exemplos:
const double PI = 3.1415926;
const long MAX = 1024L;
20/04/2017 (C) 2017, PJANDL. 23
24. C++::MODIFICADORES DE ACESSO
const
Define um elemento que não pode ser
modificado pelo programa.
Pode ser usado para declaração de
constantes, como já visto, e também
para indicar parâmetros que não
podem ser modificados por funções ou
métodos:
<tipoRet> nomeF ( const <tipo> param [, ...] );
size_t strlen(cont char *str);
volatile
Indica ma variável cujo conteúdo pode
ser alterado de maneira indireta, não
causada pelo próprio programa.
volatile <tipo> id;
Exemplos dessa situação são variáveis
compartilhadas entre o programa e o
sistema operacional, onde este último é
responsável pela atualização do
conteúdo da variável.
volatile unsigned char *clock = 0x3F;
20/04/2017 (C) 2017, PJANDL. 24
25. C++::CONVERSÃO DE TIPOS
A promoção automática de tipos é a
conversão implícita e automática de um
tipo mais simples para outro mais
complexo adequado à avaliação de
uma expressão.
int a = 1;
long b = 99999; // conversão
b = a + b; // conversão
float c = b * 0.33; // conversão
20/04/2017 (C) 2017, PJANDL. 25
bool char
int
long
float
double
long double
26. C++::CONVERSÃO DE TIPOS
20/04/2017 (C) 2017, PJANDL. 26
long
char
float float
char
char char
intint
long
long
float
char
doubledouble
int
long
float
int
float
double
double
long
double
int
double
char
long double long double
long double
long double
long
int
char
float
long double
long double
long double
Este diagrama mostra apenas
os tipos de dados principais
27. C++::CONVERSÃO DE TIPOS
A conversão explícita de tipos (coerção ou
type casting) permite que o
programador especifique uma
conversão desejada.
(tipo) expressão forma comum
tipo(expressão) forma funcional
Exemplos:
int a = 3, b = 2;
float c1 = a / b;
cout << c1; // exibe 1
float c2 = (float) a / b;
cout << c2; // exibe 1.5
20/04/2017 (C) 2017, PJANDL. 27
28. C++::CONSOLE
Entrada
A entrada direta pode utilizar outro
objeto pré-definido, cin (console in) que
permite o uso do dispositivo de entrada
padrão (teclado).
int x;
cin >> x;
float f;
cin >> f;
Saída
Exibição simples de valores e mensagens
pode ser feita por meio de cout (console
out), um objeto pré-definido que permite
a impressão no dispositivo de saída
padrão (console).
cout << 10;
cout << "Mensagem";
cout << "Concatenação: " << x
<< endl;
20/04/2017 (C) 2017, PJANDL. 28
Também existe um objeto pré-
definido para saída de erros,
cerr, semelhante a cout.
29. C++::ESCOPO
Escopo são os locais do programa nos
quais uma declaração específica tem
validade.
É o espaço declarativo de variáveis e
outras construções válidas.
C++ permite declarar variáveis em
qualquer ponto do código, as quais
serão válidas até o final do bloco onde
foram declaradas.
C++ oferece três níveis de escopo:
global, local e imediato.
Global
Local
Imediato
• Visível em todo
código.
• Visibilidade
limitada à função
ou método.
• Visibilidade
restrita ao bloco.
20/04/2017 (C) 2017, PJANDL. 29
30. EXEMPLO _ESCOPO
#include <iostream>
using namespace std;
int x = 10; // variável global
int main() {
cout << "x: " << x << endl;
int x = 20; // variável local
cout << "x: " << x << endl;
{
int x = 30; // variável imediata
cout << "x: " << x << endl;
cout << "x: " << ::x << endl; // uso do operador ::
}
cout << "x: " << x << endl;
cout << "x: " << ::x << endl; // uso do operador ::
return 0;
}
20/04/2017 (C) 2017, PJANDL. 30
Operador ::
(resolução de escopo)
provê acesso ao nível
global.
Variáveis
redeclaradas ocultam
o escopo exterior.
31. C++::OPERADORES
Aritméticos
+, -, *, / operadores algébricos
% resto da divisão inteira
++, -- incremento e decremento
unitários
Relacionais
==, != igualdade e diferença
>, >=,
<, <= comparadores
20/04/2017 (C) 2017, PJANDL. 31
32. C++::OPERADORES
Lógicos
&& e lógico
|| ou lógico
! não lógico (negação)
Bit-a-bit
& e bitwise
| ou bitwise
ˆ ou-exclusivo bitwise
~ complemento
>>, << deslocamento (shift) à
direita e à esquerda
20/04/2017 (C) 2017, PJANDL. 32
33. C++::OPERADORES
Atribuição
= atribuição
+=, -=, atribuição compacta
*=, /=,
%=, &=,
|=, ˆ=,
>>=, <<=
Exemplo:
x = x + 10;
x += 10;
Ternário
? : operador ternário
Permite seleção de um resultado entre
dois para uma expressão, baseado no
resultado de uma expressão lógica:
exprLog ? expr1 : expr2
onde:
exprLog seleciona o resultado
true toma expr1
false toma expr2
20/04/2017 (C) 2017, PJANDL. 33
34. C++
::PRECEDÊNCIA
A precedência é a ordem padronizada
com que os operadores da linguagem
são executados na avaliação de uma
expressão.
A precedência garante consistência
matemática na avaliação de expressões
algébricas, lógicas e relacionais, além
das operações associadas às estruturas
de dados e objetos.
20/04/2017 (C) 2017, PJANDL. 34
35. C++::CONTROLE
As diretivas que permitem realizar o
controle do fluxo de execução.
C++ oferece:
diretivas de repetição
diretivas de decisão
(ou desvio de fluxo)
construções para modularização
diretivas de controle de erros
20/04/2017 (C) 2017, PJANDL. 35
37. C++::SEQUENCIAÇÃO
Organização da sequência de diretivas
da linguagem que conduzem a execução
do programa no sentido de produzir o
resultado desejado.
Diretivas em C++ devem ser separadas
por um ; (ponto-e-vírgula), organizadas
tipicamente uma em cada linha. Mas
várias diretivas podem existir numa
mesma linha, quando separadas
adequadamente.
As chaves { } permitem delimitar um
bloco de diretivas, que passarão a ser
tratadas como uma unidade.
//Exemplo _Seq
#include <iostream>
#include <cmath>
using namespace std;
int main() {
double raio;
cout << "Raio? "; cin >> raio;
double area = M_PI * pow(raio, 2);
cout << "Area = " << area << endl;
return 0;
}
20/04/2017 (C) 2017, PJANDL. 37
Exemplo _Seq
38. C++::WHILE
Diretiva de repetição condicional.
int k = 0, j = 20;
while (k < j) {
cout << k << " menor " << j << endl;
k++;
j = j - 2;
}
20/04/2017 (C) 2017, PJANDL. 38
expressão
diretiva
falsaverdadeira
Os fragmentos que seguem podem ser
testados, bastando incluí-los num
programa mínimo.
Exemplo
_Fragmentos
39. C++::DO/WHILE
Diretiva de repetição condicional.
float valor, min=0, max=10;
do {
cout << "Digite valor [0..10]? ";
cin >> valor;
} while (valor<min || valor>max);
20/04/2017 (C) 2017, PJANDL. 39
expressão
diretiva
falsa
verdadeira
Exemplo
_Fragmentos
41. C++::IF
Diretiva de desvio condicional simples.
int x;
cout << "Digite um inteiro para x: ";
cin >> x;
if (x < 0) {
cout << "x menor do que zero";
}
20/04/2017 (C) 2017, PJANDL. 41
expressão
diretiva1
falsaverdadeira
Exemplo
_Fragmentos
42. C++::IF/ELSE
Diretiva de desvio condicional completa.
int y;
cout << "Digite um inteiro para y: ";
cin >> y;
if (y > 0 && y < 11) {
cout << "y no intervalo [1..10]" << endl;
} else {
cout << "y fora do intervalo [1..10]" << endl;
}
20/04/2017 (C) 2017, PJANDL. 42
expressão
diretiva1
falsaverdadeira
diretiva2
Exemplo
_Fragmentos
43. C++::SWITCH
Diretiva de desvio condicional múltiplo, baseado em
expressão ordinal.
char letra;
cout << "Digite uma letra maiúscula entre A e E: ";
cin >> letra;
switch (letra) {
case "A": cout << "Conceito máximo";
break;
// :
case "E": cout << "Conceito mínimo";
break;
default:
cout << "Conceito inválido";
}
20/04/2017 (C) 2017, PJANDL. 43
expressão
ordinal
diretiva1
defaultcase 1
diretivaNdiretiva2 diretiva3
case 2
case 3
Exemplo
_Fragmentos
44. C++::GOTO
Diretiva de desvio incondicional.
goto <label>;
Onde label é um rótulo, definido acima
(antes) ou abaixo (depois) da diretiva.
label:
diretiva1;
diretiva2;
:
Rótulos devem ser declarados no mesmo
escopo onde diretiva goto é usada.
Embora possível e disponível na
linguagem C++, o uso da diretiva goto
é fortemente desencorajado, pois em
raríssimas situações é, de fato a melhor
alternativa. Em geral seu uso esconde
alguma deficiência no projeto do
algoritmo.
20/04/2017 (C) 2017, PJANDL. 44
45. EXEMPLO _GOTO
#include <iostream>
#include <iomanip>
using namespace std;
int main() {
cout << "Caracteres ASCII [33..132]" << endl;
unsigned char c = 33;
int i = 0;
laco:
cout << c << " " << setw(3) << int(c) << "| ";
i++; c++;
if (i%10==0) { cout << endl; }
if (c<=132) { goto laco; }
return 0;
}
20/04/2017 (C) 2017, PJANDL. 45
Resultados do
programa
46. C++::BREAK & CONTINUE
break
Diretiva de desvio incondicional que
interrompe o comando corrente (um laço
ou decisão múltipla com switch), fazendo
que a execução prossiga no comando
subsequente àquele em que foi usado.
continue
Diretiva de desvio incondicional que
abrevia a iteração corrente do laço,
fazendo que a expressão de controle do
comando de repetição seja novamente
avaliada, acelerando assim a
continuação do comando de repetição.
20/04/2017 (C) 2017, PJANDL. 46
47. EXEMPLO _GRAFICO
#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;
int main() {
cout << "Polinomio de 2o. grau" << endl;
// coeficientes do polinômio deveriam ser lidos
double a = -1.5, b = 3.0, c = 2.2, xi, xf;
// intervalo da ordenada
cout << "Valor inicial da ordenada? "; cin >> xi; // 0
cout << "Valor final da ordenada? "; cin >> xf; // 2.4
// desenha eixo da abcissa
cout << “______0";
for (int i=1; i<6; i++) {
cout << "---------"<< i;
}
cout << " (Y)" << endl;
// plota polinômio
for (double x=xi; x<=xf; x+=0.2) {
double aux = (int(10*x))/10.0;
cout << setw(6) << aux << " ";
double y = a*pow(x, 2) + b*x + c;
if (y<0 || y>5) {
cout << endl; // abcissa fora da escala
continue; // abrevia iteração
}
// plota abcissa em escala 10:1
for (int i=0, l=int(10*y)-1; i<l; i++) {
cout << " ";
}
cout << "+" << endl; // ponto da função
}
cout << " (X)" << endl;
return 0;
}
20/04/2017 (C) 2017, PJANDL. 47
Uso de continue
50. C++
::ESTRUTURAS DE DADOS
C++ oferece várias estruturas de dados.
Derivadas
Arranjo
Função
Ponteiro
Referência
Definíveis
Enumeração
Estrutura
União
Classe
20/04/2017 (C) 2017, PJANDL. 50
51. C++::ARRANJOS
Arranjos ou Arrays são:
conjuntos de elementos de um mesmo tipo;
organizados em posições consecutivas da
memória;
ocupando uma região de tamanho fixo
(capacidade máxima pré-definida);
seus elementos podem ser acessados individual
e aleatoriamente por meio de um índice
(primeira posição é zero).
Arranjos podem ser unidimensionais ou
multidimensionais,
Declaração (unidimensional):
<Tipo> <id>[<tamanho>];
Exemplos:
int a[10];
double f[1024];
float k[] = { 0.1, 2.3, 4.56, -78.9 };
20/04/2017 (C) 2017, PJANDL. 51
53. EXEMPLO _ARRANJO
#include <iostream>
using namespace std;
const int MAX = 5;
int main() {
double a[MAX];
// lê arranjo
for (int i=0; i<MAX; i++) {
cout << "#" << i << "? ";
cin >> a[i];
}
// soma elementos do arranjo
double soma = 0;
for (int i=0; i<MAX; i++) {
soma = soma + a[i];
}
cout << "Soma = " << soma << endl;
return 0;
}
Cuidado!
C++ inicializa automaticamente apenas
arranjos (e variáveis) globais.
C++ não mantém o tamanho dos
arranjos, nem dispõe de função para tal
fim.
C++ não oferece qualquer mecanismo
de proteção ou restrição quanto ao uso
de índices inválidos para acesso aos
elementos do arranjo.
20/04/2017 (C) 2017, PJANDL. 53
Uso de array
unidimensional
54. EXEMPLO _MATRIZ
#include <iostream>
#include <iomanip>
using namespace std;
int main() {
// declara e inicializa matriz
int matriz[3][4] = { { 31, 713, 37, 512 }, { 102, -82, 9, -28 },
{ 8, 946, 546, 91 } };
double res[3][4]; // declara matriz
cout << "Matriz dada:n";
for (int l=0; l<3; l++) {// exibe matriz organizada em linhas e colunas
cout << "[ ";
for (int c=0; c<4; c++) { cout << setw(6) << matriz[l][c] << " "; }
cout << "]n";
}
cout << "Normalizando Matriz...n";
double maior = matriz[0][0];
for (int l=0; l<3; l++) {// determina maior elemento da matriz
for (int c=0; c<4; c++) {
if (maior<matriz[l][c]) maior = matriz[l][c];
}
}
// normaliza matriz: maior=1 e outros proporcionais a maior
for (int l=0; l<3; l++) {
for (int c=0; c<4; c++) {
res[l][c] = matriz[l][c]/maior;
}
}
cout << "Matriz resultado:n";
// exibe matriz organizada em linhas e colunas
for (int l=0; l<3; l++) {
cout << "[ ";
for (int c=0; c<4; c++) {
cout << setw(10) << setprecision(3) << res[l][c] << " ";
}
cout << "]n";
}
return 0; // encerra programa
}
20/04/2017 (C) 2017, PJANDL. 54
Uso de arrays
bidimensional
55. C++::STRINGS
Uma string é uma sequência de
caracteres de comprimento arbitrário.
C++ compartilha com sua antecessora C
o uso de arrays de caracteres
terminados com nulo (caractere ‘0’ ou
0).
20/04/2017 (C) 2017, PJANDL. 55
Exemplos:
char nome[ ] = “Peter Jandl Jr.”;
char lang [ ] = { ‘C’, ‘+’, ‘+’, 0 };
char s[ ] = { ‘0’ };
56. C++::STRINGS
#include <iostream>
#include <cstring>
using namespace std;
int main() {
char nome[20], linha[80]; // duas strings
// entrada de string com uso direto de cin
cout << "Qual o seu nome? ";
cin >> nome; // lê apenas 1a palavra
cin.ignore(80, 'n'); // ignora restante da entrada até 'ENTER'
cout << "Alo " << nome << "!n"
<< "Digite uma ou mais frases, '.' finaliza programa.n";
do { // entrada de string com uso de cin.getline
cin.getline(linha, 80); // lê tudo até 'ENTER'
cout << linha << " : " << strlen(linha) << endl;
} while (linha[0]!='.'); // encerra laço se 1o caractere='.'
cout << "Tchaun";
return 0; // encerra programa
}
20/04/2017 (C) 2017, PJANDL. 56
Exemplo _String
57. C++::ENUMERAÇÕES
Uma enumeração é uma construção da
linguagem que permite agrupar um
conjunto de elementos constantes
definidos pelo programador.
enum [nome] { <id1> [, <id2> [...] ] };
São mais convenientes que constantes
individuais quando o grupo de valores
enumerados constitui um conjunto (como
um tipo de dados).
A cada constante é associado um valor
inteiro a partir do zero.
Exemplos:
enum cor { Branco, Vermelho, Cinza };
enum escolaridade { Fundamental,
Medio, Superior, Especializacao,
Mestrado, Doutorado,
PosDoutorado };
enum zoom { z0=1, z1=2, z2=4 };
enum mes { janeiro=1, fevereiro,
marco, abril, maio, junho, julho,
agosto, setembro, outubro,
novembro, dezembro };
20/04/2017 (C) 2017, PJANDL. 57
58. EXEMPLO _ENUM
#include <iostream>
using namespace std;
enum zoom { z0=1, z1=2, z2=4 };
int main() {
enum { A, B, C }; // enum anônima
cout << A << " ... " << C << endl;
zoom zIni = z0; // uso de constante
zoom zMax = zoom(3); // coerção
cout << zIni << " ... " << zMax << endl;
return 0;
}
20/04/2017 (C) 2017, PJANDL. 58
Uso de
enumerações
59. C++::PONTEIROS
Ponteiros (pointers) são variáveis
especiais capazes de armazenar
endereços de memória, ou seja, seus
conteúdos se referem à localização de
outro objeto na memória (como uma
variável, arranjo, outro ponteiro etc.).
Ponteiros permitem o acesso e a
modificação das posições de memória
indicadas.
Proveem suporte para alocação
dinâmica de memória.
Declaração de ponteiro:
<Tipo> *<nome>;
Exemplos:
char *palavra; // ponteiro para caractere
int *p; // ponteiro para inteiro
long *cont; // ponteiro para long
void *qq; // ponteiro para void
double *total; // ponteiro para double
20/04/2017 (C) 2017, PJANDL. 59
60. C++::PONTEIROS
Operadores Específicos:
• Endereço de &
• Conteúdo de *
Exemplos:
int a = 33; // variável int
int *p1 = &a; // ponteiro para int
char c = 'A'; // variável char
char *p2 = &c; // ponteiro para char
int b = *p1; // var. b recebe conteúdo
// apontado por p1
// exibe o conteúdo apontado por p2
cout << *p2 << endl;
20/04/2017 (C) 2017, PJANDL. 60
61. C++::PONTEIROS
A obtenção do conteúdo de um
endereço de memória através do
operador '*' é conhecida como
'indireção' (indirection ou dereferencing)
e é uma operação fundamental para a
utilização efetiva dos ponteiros.
#include <iostream>
using namespace std;
int main() {
int a = 33; // variável inteira simples
char c = 'A'; // variável caractere simples
int* p1 = &a; // ponteiro para inteiro
char* p2 = &c; // ponteiro para caractere
// exibe informações sobre os ponteiros
cout << " Ponteiro p1: " << p1 << endl
<< "Conteudo do endereco p1: " << *p1 << endl
<< "Endereco do ponteiro p1: " << &p1 << endl;
cout << " Ponteiro p2: " << (int*)p2 << endl
<< "Conteudo do endereco p2: " << *p2 << endl
<< "Endereco do ponteiro p2: " << &p2 << endl;
return 0; // encerra o programa
}
20/04/2017 (C) 2017, PJANDL. 61
Uso de ponteiros e
seus operadores
Exemplo _Ponteiro
62. C++::PONTEIROS
Os operadores soma (‘+’), subtração (‘-’),
incremento (‘++’) e decremento (‘--’)
podem ser aplicados aos ponteiros para
modificar o local apontado.
Através do operador soma ('+') podemos
adicionar um valor inteiro a um ponteiro de modo
que ele seja “avançado” tal número de elementos
do tipo, passando a apontar uma localidade de
memória num endereço superior ao anterior.
Com o operador subtração (‘-') ocorre o inverso,
fazendo que o ponteiro seja “retrocedido” o
número indicado de elementos, apontando para
um endereço anterior.
20/04/2017 (C) 2017, PJANDL. 62
Aritmética de
ponteiros
63. C++::PONTEIROS
#include <iostream>
using namespace std;
int main() {
// ponteiros com endereços literais inválidos em outros sistemas!
char *pChar = (char *)0x0065FDF4;
cout << (int *)pChar << ": " << *pChar << endl;
pChar = pChar + 1;
cout << (int *)pChar << ": " << *pChar << endl;
pChar += 1;
cout << (int *)pChar << ": " << *pChar << endl;
pChar++;
cout << (int *)pChar << ": " << *pChar << endl;
long *pLong = (long *)0x0065FE00;
cout << pLong << ": " << *pLong << endl;
pLong = pLong - 1;
cout << pLong << ": " << *pLong << endl;
pLong -= 1;
cout << pLong << ": " << *pLong << endl;
pLong--;
cout << pLong << ": " << *pLong << endl;
return 0; // encerra o programa
}
Não pode ser empregado o operador '*'
em ponteiros do tipo void porque não se
sabe o tamanho dos dados apontados,
exigindo uma operação de type casting
para o tipo correto:
int k = 10; // variável inteira
void *p = &k; // ponteiro void recebe endereço
cout << *((int*)p) << endl;
// uso do ponteiro void para
// acessar conteúdo apontado
*((int*)p) = 33; // uso do ponteiro void para
// modificar conteúdo apontado
20/04/2017 (C) 2017, PJANDL. 63
Exemplo _Ponteiro2
64. C++::PONTEIROS
#include <iostream>
using namespace std;
const int MAX =10;
int main() {
int a[MAX];
cout << "Entrada de valoresn";
for (int i=0; i<MAX; i++) {
cout << "a[" << i << "] ?b"; cin >> a[i];
}
cout << "Exibicao do arranjon[ ";
for (int i=0; i<MAX; i++) { cout << a[i] << " "; }
cout << "]n";
cout << "Invertendo posicao do elementos...n";
for (int i=0,j=MAX-1; i<j; i++, j--) {
int tmp = *(a+i); // uso de aritmética de ponteiros
*(a+i) = *(a+j); // para acessar e modificar
*(a+j) = tmp; // elementos do arranjo
}
cout << "Exibicao do arranjo invertidon[ ";
for (int i=0; i<MAX; i++) { cout << *(a+i) << " "; }
cout << "]n";
return 0; // encerra o programa
}
20/04/2017 (C) 2017, PJANDL. 64
Equivalência do uso
de ponteiros e
arranjos
Exemplo _Ponteiro3
65. C++::ALOCAÇÃO DINÂMICA
Mecanismo que permite a agregação de
novas regiões de memória para uso do
programa durante sua execução.
C++ permite:
alocação dinâmica de memória por
meio do operador new.
liberação das regiões alocadas por
meio do operador delete.
Estes operadores são utilizados em
conjunto com os ponteiros.
Exemplos:
int *pInt; // ponteiro para inteiro
pInt = new int; // aloca memória p/ um int
delete pInt; // libera região alocada
double *pDouble;
// ponteiro para double
pDouble = new double[1000];
// aloca mem p/1000 doubles
delete[] pDouble;
// libera memória alocada
20/04/2017 (C) 2017, PJANDL. 65
66. EXEMPLO _ALOCDINAM
#include <iostream>
using namespace std;
int main() {
int max; // tamanho do arranjo dinamicamente alocado
cout << "Quantos elementos?n"; cin >> max;
// aloca arranjo dinamicamente
double *pDouble = new double[max];
if (pDouble==NULL) {
cout << "Nao ha memoria suficiente no sistema.n";
return 1; // encerra programa com erro
}
cout << "Entrada de valoresn";
for (int i=0; i<max; i++) {
cout << "valor[" << i << "] ?b"; cin >> pDouble[i];
}
double soma = 0; // variável para total dos valores
cout << "Exibicao do arranjon ";
for (int i=0; i<max; i++) {
cout << pDouble[i] << " ";
soma += pDouble[i]; // acumula valores dados
}
// exibe média dos valores
cout << "nMedia = " << soma/max << endl;
delete[] pDouble; // libera memória alocada
return 0; // encerra o programa
}
20/04/2017 (C) 2017, PJANDL. 66
67. C++::ALOCAÇÃO DINÂMICA
Ponteiros para Ponteiros
Um ponteiro pode conter o endereço de
qualquer objeto existente, até de um
outro ponteiro e este para outro, até
que dados sejam apontados, o que
constitui a indireção múltipla (multiple
indirection).
int x = 17580; // variável int simples
int *p1 = &x; // ponteiro de int
int **p2 = &p1; // ponteiro de ponteiro de int
int ***p3 = &p2; // 3ª indireção para int
Referências
Uma referência é como um ponteiro
implícito que funciona como um 'nome
alternativo' para uma entidade.
double resultado; // variável comum
double &ref = resultado; // referência
É obrigatória a inicialização das
referências com uma variável ou valor
constante, pois não podem ser alteradas
depois de inicializadas.
20/04/2017 (C) 2017, PJANDL. 67
68. C++::ESTRUTURAS
Uma estrutura (structure) é:
um agrupamento de variáveis relacionadas,
mas de tipos arbitrários,
referenciadas por um mesmo nome.
Cada variável designada como
parte de uma estrutura é chamada
de campo ou membro.
Sintaxe:
struct <nomeEstrutura> {
<tipo1> <campo1>;
[<tipo2> <campo2>; [...] ]
} [var1 [, var2 [...]]];
Exemplo:
struct s_pessoa {
char nome[80]; // string com 80 caracteres
short ddd; // inteiro curto
long telefone; // inteiro longo
char email[80]; // string com 80 caracteres
};
20/04/2017 (C) 2017, PJANDL. 68
69. C++::ESTRUTURAS
Declaração:
struct s_pessoa eu;
s_pessoa você;
Inicialização na declaração:
s_pessoa peter = { "Peter Jandl", 11,
987654321,
"prof.peter@fatec.sp.gov.br" };
Cópia:
s_pessoa copia = peter;
Uso:
cout << "nome : " << eu.nome
<< "nfone : (" << eu.ddd << ")"
<< eu.telefone << "nemail: “
<< eu.email << endl;
strcpy(eu.nome, "Peter Jandl Jr.");
// nome é um campo string!
eu.telefone = 976543210;
// telefone é um campo inteiro
20/04/2017 (C) 2017, PJANDL. 69
70. EXEMPLO _STRUCT
#include <iostream>
#include <cstring>
using namespace std;
struct s_pessoa {
char nome[80]; // string com 80 caracteres
short ddd; // inteiro curto
long telefone; // inteiro longo
char email[80]; // string com 80 caracteres
};
int main() {
// declaração e inicialização de estrutura
struct s_pessoa eu = { "Peter", 11, 0, "jandl@live.com" };
// exibe campos
cout << "nome : " << eu.nome
<< "nfone : (" << eu.ddd << ")" << eu.telefone
<< "nemail: " << eu.email << endl;
// altera campos
strcpy(eu.nome, "Peter Jandl Jr."); // nome é um campo string!
eu.telefone = 38323374; // telefone é um campo inteiro
// exibe campos novamente
cout << "nome : " << eu.nome
<< "nfone : (" << eu.ddd << ")" << eu.telefone
<< "nemail: " << eu.email << endl;
// declara outra estrutura e efetua leitura de seus campos
struct s_pessoa voce;
cout << "Seu nome? "; cin.getline(voce.nome,80);
cout << " DDD? "; cin >> voce.ddd;
cout << "Telefone? "; cin >> voce.telefone;
cout << " E-mail? "; cin >> voce.email;
// exibe campos
cout << "nome : " << voce.nome
<< "nfone : (" << voce.ddd << ")" << voce.telefone
<< "nemail: " << voce.email << endl;
return 0; // encerra o programa
}
20/04/2017 (C) 2017, PJANDL. 70
Uso de struct e seus
campos
71. C++::ESTRUTURAS
Composição de Estruturas
struct s_data {
short ano;
short mes;
short dia;
};
struct s_compromisso {
// estrutura independente
struct s_data data;
char lembrete[80];
}
// declaração de variável
struct s_compromisso c;
// campos
c.data.ano
c.data.mes
c.data.dia
c.lembrete
Composição com Estrutura Anônima
struct s_compromisso {
// estrutura anônima
struct {
short ano;
short mes;
short dia;
};
char lembrete[80];
}
// declaração de variável
struct s_compromisso c;
// campos
c.ano
c.mes
c.dia
c.lembrete
20/04/2017 (C) 2017, PJANDL. 71
72. EXEMPLO
#include <iostream>
#include <cstring>
using namespace std;
// estruturas independentes aninhadas
struct s_hora {
short HH;
short MM;
};
struct s_compromisso {
struct s_hora hora;
char lembrete[80];
};
// estrutura anônima aninhada
struct s_compromisso2 {
struct {
short HH;
short MM;
};
char lembrete[80];
};
int main() {
// declara e inicializa estrutura e ponteiro para a mesma
struct s_compromisso c1 = { 10, 30, "Cliente 1" };
struct s_compromisso *p1 = &c1;
// exibe conteúdo dos campos da estrutura
cout << c1.hora.HH << ":" << c1.hora.MM << " "
<< c1.lembrete << endl;
cout << p1->hora.HH << ":" << p1->hora.MM << " "
<< p1->lembrete << endl;
// declara e inicializa estrutura e ponteiro para a mesma
struct s_compromisso2 c2;
c2.HH = c1.hora.HH;
c2.MM = p1->hora.MM;
strcpy(c2.lembrete, p1->lembrete);
struct s_compromisso2 *p2 = &c2;
// exibe conteúdo dos campos da estrutura
cout << c2.HH << ":" << c2.MM << " "
<< c2.lembrete << endl;
cout << p2->HH << ":" << p2->MM << " "
<< p2->lembrete << endl;
return 0; // encerra programa
}
20/04/2017 (C) 2017, PJANDL. 72
Uso de struct e seus campos
por meio de ponteiros
73. C++::UNIÕES
Uma união (union) é como uma estrutura
(struct), ou seja, organiza variáveis de
tipos diferentes sob um mesmo nome,
exceto pelo fato de que todas as
variáveis compartilham o mesmo espaço
em memória, não podendo ser utilizadas
simultaneamente
Declaração:
union <nomeUnião> {
<tipo1> <campo1>;
[<tipo2> <campo2>; [...] ]
} [var1 [, var2 [...]]];
Exemplo:
union u_variante {
short valor_s; // campo inteiro curto
long valor_l; // campo inteiro longo
double valor_d; // campo real
};
20/04/2017 (C) 2017, PJANDL. 73
74. C++::DEFINIÇÃO DE TIPOS
Para melhorar a legibilidade dos
programas é possível que novos tipos
sejam criados a partir de outros
existentes utilizando-se a palavra
reservada typedef com a sintaxe
abaixo:
typedef <tipoExistente> <nomeNovoTipo>;
Exemplos:
typedef int integer;
typedef int* pInt;
typedef double real;
typedef unsigned char byte;
typedef unsigned long DWORD;
20/04/2017 (C) 2017, PJANDL. 74
76. C++::FUNÇÕES
Uma função é um segmento de
programa independente (subprograma),
ou seja, um bloco de diretivas agrupadas
ao qual se associa um nome (o
identificador de função).
Cada função tem uma finalidade
específica, realizada por meio de suas
diretivas.
Para executarmos uma função devemos
efetuar uma chamada à função (function
call) de qualquer ponto do programa.
Uma função:
Pode ser chamada qualquer número de
vezes;
Pode receber valores (argumentos) para
realizar suas tarefas de maneira
customizada;
Pode retornar um valor como resultado de
sua execução;
Pode acionar a si mesma (recursão).
Programas em C++ podem ser
organizados como um conjunto de
funções.
20/04/2017 (C) 2017, PJANDL. 76
77. C++::FUNÇÕES
Forma geral da definição:
tipoRetorno nome (listaParâmetros) corpoFunção
Onde:
tipoRetorno especifica o tipo do valor
retornado pela função. O default é int;
qualquer outro pode ser escolhido; void indica
uma função sem valor de retorno.
nome é o identificador da função, usado em
seu acionamento (chamada da função).
listaParâmetros relaciona o tipo e nome dos
parâmetros opcionalmente recebidos pela
função.
corpoFunção é o bloco de código associado.
Um trecho de código como segue:
int temp;
cout << "Digite um valor inteiro: ";
cin >> temp;
Pode ser convertido numa função como:
int leInteiro(char *msg) {
int temp;
cout << msg;
cin >> temp;
return temp;
}
20/04/2017 (C) 2017, PJANDL. 77
78. C++::FUNÇÕES
Ao invés de repetir-se código, o uso de
funções não apenas reduz a quantidade
de programa a ser escrito, mas melhora
sua abstração, facilita sua manutenção e
promove o reuso.
Observe que a definição da função
aparece no código antes de sua
utilização (no caso, antes do main).
#include <iostream>
using namespace std;
int LeInteiro(const char *msg) { // definição da função
int temp; // declaração var auxiliar
cout << msg; // exibe mensagem
cin >> temp; // lê valor
return temp; // retorna valor lido
}
int main() {
int valor1, valor2; // declaração de variáveis
// chamada da função e atribuição do valor retornado
valor1 = LeInteiro(“Valor1? ");
// chamada da função e atribuição do valor retornado
valor2 = LeInteiro(“Valor2? ");
// exibe valores lidos
cout << “Valor1:” << valor1 << endl
<< “Valor2:” << valor2 << endl;
return 0; // encerramento do programa
}
20/04/2017 (C) 2017, PJANDL. 78
Função que retorna
tipo primitivo
79. C++::RETORNO DE FUNÇÕES
Toda função deve retornar um único valor
como seu resultado.
Tal valor deve ser do tipo especificado
para retorno.
O valor de retorno deve ser indicado
diretamente através da diretiva return:
return expressão;
bool EPrimo(long numero) {
// laço que percorre as possibilidades de teste
for (int div=2; div<=numero/2; div++) {
if (numero%div==0) { // verifica se div é divisor
// encontrou divisor, número não é primo
return false;
}
}
// laço concluído, número dado é primo
return true; // retorno do resultado
}
20/04/2017 (C) 2017, PJANDL. 79
Função que retorna
tipo primitivo
80. C++::DECLARAÇÃO OU PROTOTIPAÇÃO
A declaração ou prototipação (function
prototype) é a especificação do nome
pretendido para uma função, juntamente
com seu tipo de retorno e a lista dos
tipos de seus argumentos.
A declaração não inclui o bloco de
código da função e é finalizada por um
ponto e vírgula (';').
Exemplos:
• int LeInteiro(const char*);
• bool EPrimo(long);
• double Soma(double, double);
• int Procura(const string, char);
• void Troca(double*, double*);
20/04/2017 (C) 2017, PJANDL. 80
81. EXEMPLO _FUNCAO2
20/04/2017 (C) 2017, PJANDL. 81
#include <iostream>
using namespace std;
// declaração das funções
bool EPrimo(long);
int LeInteiro(const char*);
// função principal
int main() {
// mensagem inicial
cout << "Verificacao de numero primon";
// declara var, chama função e atribui valor lido
int valor = LeInteiro("Valor inteiro?");
// exibe mensagem contendo resultado de 'EPrimo(long)'
cout << "Numero '" << valor << "' "
<< (EPrimo(valor) ? "e" : "nao e") << " primon";
return 0; // encerramento do programa
}
bool EPrimo(long numero) { // definição da função EPrimo
bool primo = true; // declara e inicia var auxiliar
// laço percorre as possibilidades de teste
for(int div=2; div<=numero/2; div++) {
if (numero%div==0) { // verifica se div é divisor
primo = false; // encontra divisor, número não é primo
break; // interrompe laço
}
} // não encontrou divisor, número é primo
return primo; // retorno do resultado
}
int LeInteiro(const char *msg) { // definição da função LeInteiro
int temp; // declaração var auxiliar
cout << msg; // exibe mensagem
cin >> temp; // lê valor
return temp; // retorna valor lido
}
Funções que retornam
tipos primitivos
82. EXEMPLO _FUNCAO3
#include <iostream>
using namespace std;
// declaração da função 'ObtemArranjo(int)'
int* ObtemArranjo(int);
// função principal
int main() {
int* arranjo; // ponteiro para arranjo de inteiros
const int TAM = 10; // constante para tamanho do arranjo
arranjo = ObtemArranjo(TAM); // lê arranjo de tamanho TAM
cout << "[ "; // exibe arranjo obtido
for (int i=0; i<TAM; i++) {
cout << arranjo[i] << " ";
}
cout << "]n";
delete[] arranjo; // memória alocada é liberada
return 0; // encerra programa
}
// definição da função 'ObtemArranjo(int)'
int* ObtemArranjo(int tamanho) {
int* tmp = new int[tamanho]; // aloca arranjo dinamicamente
for (int i=0; i<tamanho; i++) { // laço para leitura de valores
cout << "Valor[" << i << "] ?b";
cin >> tmp[i];
}
return tmp; // retorna arranjo
}
20/04/2017 (C) 2017, PJANDL. 82
Função que retorna
tipo ponteiro
83. C++::PASSAGEM DE PARÂMETROS
Passagem de parâmetros
por valor
Mecanismos mais simples de
transferência de argumentos.
O valor dos argumentos usados na
chamada é copiado para os parâmetros
de entrada da função.
Se tais parâmetros são alterados na
função, a modificação não afeta os
argumentos na chamada (passagem
unidirecional, sem efeito colateral).
Passagem de parâmetros
por referência
Mecanismos mais sofisticado de
transferência de argumentos.
O endereço dos argumentos usados na
chamada é copiado para os parâmetros
de entrada da função.
Se tais parâmetros são alterados na
função, a modificação afeta os
argumentos na chamada (passagem
bidirecional, com efeito colateral).
20/04/2017 (C) 2017, PJANDL. 83
Uso de const impede que
argumentos passados por referência
sejam alterados na função.
84. C++::ARGUMENTOS PARA MAIN()
A linguagem C++ admite duas formas
para a função principal:
// função principal sem argumentos
int main() { ... }
// função principal com argumentos
int main(int argc, char *argv[]) { ... }
Na segunda forma, os argumentos são
providos pelo sistema operacional em uso
e correspondem aos argumentos da linha
de comando (dos consoles).
20/04/2017 (C) 2017, PJANDL. 84
85. EXEMPLO _MAIN
#include <iostream>
using namespace std;
// função principal com recebimento de argumentos
int main (int argc, char *argv[]) {
// exibe mensagem com número de argumentos recebidos
cout << "Argumentos recebidos: " << argc << endl;
// exibe todos os argumentos recebidos
for (int i=0; i<=argc; i++) {
cout << i << ": " << argv[i] << endl;
}
return 0; // encerra o programa
}
20/04/2017 (C) 2017, PJANDL. 85
86. C++::ARGUMENTOS DEFAULT
Construção conveniente da linguagem
C++ que possibilita definir argumentos
default para funções, isto é, definir
funções onde um ou mais de seus
parâmetros tenham valores pré-definidos
em sua declaração.
Quando um argumento é omitido na
chamada da função, é automaticamente
usado seu valor default.
Isso exige que os argumentos default
sejam os últimos das listas de parâmetros
das funções.
#include <iostream>
using namespace std;
// declaração da função 'Inc(double&, double)'
double Inc (double&, double = 1);
int main() { // função principal
double valor = 5;
cout << "Valor Inicial: " << valor << endl;
Inc(valor, 2.4);
cout << "Valor+2.4: " << valor << endl;
cout << "Valor+1: " << Inc(valor) << endl;
return 0; // encerra programa
}
// definição da função 'Inc(double&, double)'
double Inc (double &valor, double incremento) {
valor += incremento; // adiciona incremento ao valor
return valor; // retorna valor
}
20/04/2017 (C) 2017, PJANDL. 86
Função com passagem de
parâmetro por referência e
argumento default
87. C++::SOBRECARGA DE FUNÇÕES
É a possibilidade de existirem várias
funções com o mesmo nome dentro de um
mesmo espaço declarativo (function
overload).
Assim, em um mesmo escopo, podem
existir funções homônimas desde que
possuam diferentes assinaturas
(signatures).
A assinatura de uma função é a lista dos
tipos de seus parâmetros formais na
ordem em que foram declarados.
Exemplo:
double Inc(double&);
double Inc(double&,double);
double Inc(double*,double);
20/04/2017 (C) 2017, PJANDL. 87
88. EXEMPLO _SOBRECARGA
#include <iostream>
using namespace std;
double Inc (double&);
double Inc (double&, double);
double Inc (double*, double);
int main() {
double x = 0;
double y = 3;
double *w = &y;
cout << "x inicial = " << x << endl;
Inc(x);
cout << "x + 1 = " << x << endl;
cout << "y inicial = " << y << endl;
cout << "y + 2.8 = " << Inc(y, 2.8) << endl;
cout << "y + 1.2 = " << Inc(&y, 1.2) << endl;
cout << "y = " << y << endl;
Inc(w, 0.5);
cout << "y + 0.5 (indireto) = " << y << endl;
cout << "x + Inc(y, 0.7) = " << (x + Inc(y, 0.7)) << endl;
return 0;
}
double Inc (double &valor) {
valor += 1;
return valor;
}
double Inc (double &valor, double quant) {
valor += quant;
return valor;
}
double Inc (double *valor, double quant) {
*valor = *valor + quant;
return *valor;
}
20/04/2017 (C) 2017, PJANDL. 88
Estas duas versões da função
poderiam ser substituídas por
uma única dotada de
argumento default
89. PARTE V::
ORIENTAÇÃO A OBJETOS BÁSICA
C++ 200
UM MINICURSO
20/04/2017 (C) 2017, PJANDL. 89
90. ORIENTAÇÃO A OBJETOS
Sobre a ideia de objeto:
"No sentido mais simples, um objeto é
uma coisa ou uma entidade do mundo
real." (Jamsa & Klander, 1999)
Sobre a orientação a objetos:
"...uma forma particular de organizar o
desenvolvimento de software como uma
coleção de objetos que incorporam tanto
uma estrutura de dados como
comportamentos." (Rumbaugh, 1991)
20/04/2017 (C) 2017, PJANDL. 90
91. ORIENTAÇÃO A OBJETOS::CARACTERÍSTICAS
Classificação
Característica que permite a criação de categorias de objetos (as classes) para facilitar a
compreensão do mundo e dos problemas.
Generalização
Mecanismo que possibilita o compartilhamento de características entre classes, evitando sua
repetição.
Encapsulamento
Mecanismo que determina quais elementos de uma classe serão visíveis, permitindo proteger
ou restringir o acesso a outros elementos.
20/04/2017 (C) 2017, PJANDL. 91
92. C++::CLASSES
Uma classe (class) é um novo tipo de
dados que pode ser definido pelo
programador para descrever uma
entidade real ou abstrata.
As classes representam os conceitos
fundamentais da aplicação em termos
da realidade 'modelada‘ pelo
programador.
20/04/2017 (C) 2017, PJANDL. 92
Enquanto uma classe é um modelo, as
ocorrências de uma classe são suas
instâncias.
93. C++::CLASSES
Classes em C++ possuem a seguinte
estrutura:
class <NomeClasse> {
[membros]
[EspecificadorDeAcesso:
membros]
[...]
} [ListaDeObjetos];
Os membros de uma classe podem ser
basicamente de duas naturezas:
variáveis-membro ou campos da classe são as
declarações de variáveis que pertencem à classe
e representam seus atributos (características); e
funções-membro ou métodos da classe são as
declarações e definições de funções associadas à
classe e representam suas operações
(comportamentos).
Os especificadores de acesso (access
specifiers) determinam a visibilidade externa
dos membros da classe aos quais se aplicam,
indicando como podem ser utilizados.
20/04/2017 (C) 2017, PJANDL. 93
94. C++::CAMPOS
Uma classe pode possuir um ou mais
atributos, os quais podem ser
representados por seus campos ou
variáveis-membro.
As variáveis-membro podem ser de
qualquer tipo pré-definido pela
linguagem ou definido pelo
programador, ou seja, tipos primitivos,
arrays, estruturas, uniões ou objetos de
outras classes.
Campos que não possuem restrição
podem ser declarados com acesso
público (public).
Nas situações ondem existem restrições
aos valores possíveis de um campo,
recomenda-se sua declaração com
acesso protegido (protected) ou privado
(private).
20/04/2017 (C) 2017, PJANDL. 94
95. EXEMPLO _INTEIRO
// Inteiro.h
class Inteiro { // denom. classe
public: // especif. acesso
int valor; // variável-membro
};
#include <iostream>
#include "Inteiro.h"
using namespace std;
int main() {
Inteiro i1, i2; // declaração de objetos Inteiro
i1.valor = 5;
cout << "i1.valor: " << i1.valor << endl;
cout << "Digite um valor inteiro: "; cin >> i2.valor;
cout << "i2.valor: " << i2.valor << endl;
cout << "i2 " << (i2.valor>i1.valor? "maior" : "menor ou igual")
<< " que i2" << endl;
return 0;
}
20/04/2017 (C) 2017, PJANDL. 95
Classe simples
contendo apenas
atributos públicos
Instanciação implícita dos
objetos da classe indicada
Campo público
apropriado, pois
não há restrição de
valores
Observe o uso do seletor ‘.’
para acesso aos campos dos
objetos
96. EXEMPLO _CAIXA
// Caixa.cpp
class Caixa {
public:
// campos públicos
// dimensões da caixa
double altura, largura, profundidade;
// informações para empilhamento
double peso;
int empilhamento;
};
#include <iostream>
#include "Caixa.cpp"
using namespace std;
void LeCaixa(Caixa&); // declaração de função
int main() {
Caixa cx; // declaração de objeto Caixa
LeCaixa(cx);
cout << "Dim (LARG x ALT x PROF): " << cx.largura << " x "
<< cx.altura << " x " << cx.profundidade << "nPeso: "
<< cx.peso << "nEmpilhamento: " << cx.empilhamento << endl;
return 0;
}
void LeCaixa(Caixa &cx) { // definição de função
cout << "Digite as dimensoes da caixa (LARG ALT PROF): ";
cin >> cx.largura >> cx.altura >> cx.profundidade;
cout << "Digite o peso da caixa: "; cin >> cx.peso;
cout << "Digite o empilhamento maximo da caixa: ";
cin >> cx.empilhamento;
}
20/04/2017 (C) 2017, PJANDL. 96
Classe simples contendo
apenas atributos públicos
Observe o uso do seletor ‘.’
para acesso aos campos dos
objetos
97. C++::MÉTODOS
Uma classe também pode possuir uma
ou mais operações, as quais podem ser
definidas por seus métodos ou funções-
membro.
As funções-membro podem tomar
qualquer número e tipo de parâmetros,
retornar qualquer tipo de resultados,
afetando (situação mais usual) ou não o
estado do objeto.
Métodos que permitem a utilização do
objeto em geral são declarados com
acesso público (public).
Métodos destinados a subdivisão interna
das responsabilidades do objeto, ou
aqueles cujo uso possui restrições que o
usuário da classe não necessita conhecer,
devem ser declarados com acesso
protegido (protected) ou privado
(private).
20/04/2017 (C) 2017, PJANDL. 97
É comum que métodos públicos
provejam acesso a campos privados
(operações de acesso e mutação)
98. EXEMPLO _CAIXA
// Caixa-cpp
class Caixa {
public:
// campos públicos
// dimensões da caixa
double altura, largura, profundidade;
// informações para empilhamento
double peso;
int empilhamento;
// declaração de método
double volume();
};
double Caixa::volume() { // definição do método
return altura*largura*profundidade;
}
#include <iostream>
#include "Caixa.cpp"
using namespace std;
void LeCaixa(Caixa&); // declaração de função
int main() {
Caixa cx; // declaração de objeto Caixa
LeCaixa(cx);
cout << "Dim (LARG x ALT x PROF): " << cx.largura << " x "
<< cx.altura << " x " << cx.profundidade << "nPeso: "
<< cx.peso << "nEmpilhamento: " << cx.empilhamento << endl;
cout << “Volume: “ << cx.volume() << endl;
return 0;
}
void LeCaixa(Caixa &cx) { // definição de função
cout << "Digite as dimensoes da caixa (LARG ALT PROF): ";
cin >> cx.largura >> cx.altura >> cx.profundidade;
cout << "Digite o peso da caixa: "; cin >> cx.peso;
cout << "Digite o empilhamento maximo da caixa: ";
cin >> cx.empilhamento;
}
20/04/2017 (C) 2017, PJANDL. 98
Classe simples contendo atributos e
operações públicos
Observe o uso do seletor ‘.’
para acesso à operação do
objeto
99. C++::FUNÇÕES INLINE
// Caixa-cpp
class Caixa {
public:
// campos públicos
// dimensões da caixa
double altura, largura, profundidade;
// informações para empilhamento
double peso;
int empilhamento;
// declaração implícita de método inline
double volume() {
return altura*largura*profundidade;
}
};
Funções podem ser declaradas inline. Se uma
função é assim declarada, o compilador substitui
cada chamada existente da função por uma
cópia de seu código. Com isso o código
produzido torna-se mais rápido, apesar de maior.
inline int Max(int x, int y) {
return (x > y)? x : y;
}
Funções-membro torna-se implicitamente inline se
definidas dentro da declaração da classe.
O uso do modificador inline pode ser aplicado à
funções comuns ou funções-membro declaradas
externamente.
20/04/2017 (C) 2017, PJANDL. 99
100. C++::ACESSIBILIDADE
A acessibilidade dos membros de uma
classe, também conhecida como
encapsulamento ou ocultamento de
dados (data hiding), é a forma com que
tais elementos podem ser vistos e
utilizados externamente, ou seja, pelas
instâncias da classe e por outras classes.
O encapsulamento auxilia na separação
do projeto (design) da implementação
(coding), proporcionando facilidades de
modificação e padronização do código
Em C++ a acessibilidade é definida
pelos especificadores de acesso:
public
protected
private
20/04/2017 (C) 2017, PJANDL. 100
102. C++::CONSTRUTORES
Os objetos das classes também devem
ser inicializados de modo que se tornem
consistentes e que seja evitado o retorno
de valores não esperados.
Para a criação de objetos em estados
consistentes, podem ser declarados os
construtores (constructors), métodos
especiais acionados apenas na criação
dos objetos das próprias classes, que
preparam os objetos para uso, isto é,
inicializam apropriadamente seus
campos.
// Circunferencia.h
#include <cmath>
class Circunferencia {
private:
double raio;
public:
void setRaio(double);
double getRaio();
double area();
double perimetro();
Circunferencia(); // construtor default
};
Circunferencia::Circunferencia() { raio = 0; }
void Circunferencia::setRaio(double r) {
if (r >= 0) { raio = r; }
}
double Circunferencia::getRaio() { return raio; }
double Circunferencia::area() { return M_PI * pow(raio, 2); }
double Circunferencia::perimetro() { return 2 * M_PI * raio; }
20/04/2017 (C) 2017, PJANDL. 102
Construtores sempre têm o
nome da classe e não
possuem valor de retorno
103. C++::SOBRECARGA DE MÉTODOS E CONSTRUTORES
Métodos e construtores podem ser
sobrecarregados, tal como funções.
A sobrecarga é possível sempre que a
assinatura da operação é diferente.
É um mecanismo natural, pois como
veremos, os compiladores geram, como
padrão, dois construtores: o default e o
cópia.
class Caixa {
public: // campos públicos p/ info. da caixa
double altura, largura, profundidade;
double peso;
int empilhamento;
// declaração de métodos
double volume() { return altura*largura*profundidade; }
void ajustaMedidas(double, double, double, double, int);
void ajustaMedidas(double, double, double);
void ajustaMedidas(double, int);
// declaração de construtores
Caixa() { ajustaMedidas(0, 0, 0, 0, 0); }
Caixa(double, double, double, double, int);
Caixa(double, double, double);
Caixa(double, int);
Caixa(Caixa &c);
};
20/04/2017 (C) 2017, PJANDL. 103
104. C++::CONSTRUTORES
Construtores sem parâmetros são
denominados construtores-default, pois
são automaticamente acionados na
declaração de objetos do tipo:
Circunferencia c1, c2;
Construtores parametrizados podem ser
acionados por meio da passagem
adequada de parâmetros na
declaração dos objetos:
Circunferencia c3(2.5), c4(10);
// Circunferencia.h
#include <cmath>
class Circunferencia {
private:
double raio;
public:
void setRaio(double);
:
// construtores
Circunferencia(); // default
Circunferencia(double); // parametrizado
};
Circunferencia::Circunferencia() { raio = 0; }
Circunferencia::Circunferencia(double r) {
setRaio(r);
}
void Circunferencia::setRaio(double r) {
if (r >= 0) { raio = r; }
}
:
20/04/2017 (C) 2017, PJANDL. 104
Os construtores default são
supridos pelo compilador
quando outros não são
especificados
105. EXEMPLO _PONTO
class Ponto {
public:
float x, y; // coord. do ponto
Ponto(float=0, float=0); // val. default p/ args
void translacao(float, float);
};
// construtor parametrizado
Ponto::Ponto(float x, float y) {
translacao(x, y); // uso de método da classe
}
// ajusta nova coordenada
void Ponto::translacao(float x, float y) {
Ponto::x = x; // op. escopo diferencia parâmetro
Ponto::y = y;
}
#include <iostream>
#include "Ponto.h"
using namespace std;
int main() {
Ponto p1; // declara objeto s/ args. (default)
cout << "p1(" << p1.x << "," << p1.y << ")n";
p1.translacao(-5,10);// ajusta coordenadas
cout << "p1(" << p1.x << "," << p1.y << ")n";
Ponto p2(5); // declara objeto c/ 1 arg. (x)
cout << "p2(" << p2.x << "," << p2.y << ")n";
Ponto p3(100, 50); // declara objeto / 2 args. (x e y)
cout << "p3(" << p3.x << "," << p3.y << ")n";
return 0; // encerra programa
}
20/04/2017 (C) 2017, PJANDL. 105
Os construtores default com valores default têm
comportamento dual: default e parametrizado
106. C++::CONSTRUTORES CÓPIA
Classes declaradas sem construtores explícitos fazem que compiladores adicionem
dois construtores automaticamente:
Construtor default (sem parâmetros) e
Construtor cópia.
O construtor default representa o mecanismo natural de inicialização de objetos,
enquanto o construtor cópia é responsável por:
1. realizar a inicialização de objetos a partir de outros objetos do mesmo tipo já existentes; e
2. permitir a passagem de objetos por valor para funções (ou métodos).
Exemplo (para classe Ponto):
Ponto::Ponto(const Ponto &p) { // copia atributos do
x = p.x; y = p.y; // objeto recebido para o novo
}
20/04/2017 (C) 2017, PJANDL. 106
107. EXEMPLO _PONTO
#include <cmath>
class Ponto {
public:
float x, y; // coord. do ponto
Ponto(float = 0, float = 0); // constr default
Ponto(const Ponto&); // construtor cópia
void translacao(float, float);
static float distancia(const Ponto &p1, const Ponto &p2);
};
// construtor parametrizado
Ponto::Ponto(float x, float y) {
translacao(x, y); // uso de método da classe
}
// construtor cópia
Ponto::Ponto(const Ponto &p) {
x = p.x;
y = p.y;
}
// ajusta nova coordenada
void Ponto::translacao(float x, float y) {
Ponto::x = x; // op. escopo diferencia parâmetro
Ponto::y = y;
}
// calcula distância entre pontos
float Ponto::distancia(const Ponto &p1, const Ponto &p2) {
return sqrt(pow(p1.x - p2.x, 2) + pow(p1.y - p2.y, 2));
}
20/04/2017 (C) 2017, PJANDL. 107
Os construtores cópia
precisam duplicar
adequadamente o objeto
Métodos estáticos
pertencem à classe e não
devem afetar instâncias
108. C++::MEMBROS ESTÁTICOS
Membros estáticos, isto é, declarados
como static, são elementos especiais de
uma classe que não estão associados as
suas instâncias e sim a própria classe.
Variáveis-membro estáticas existem
apenas na classe, e não em suas
instâncias, sendo compartilhadas por
todos objetos existentes.
Funções-membro estáticas, são
compartilhados entre as instâncias como
métodos comuns, mas utilizam
exclusivamente variáveis-membro
estáticas, ou seja, se aplicam ao
contexto da classe.
ImagemExecutável
Constantes
Código
Heap
Pilha
20/04/2017 (C) 2017, PJANDL. 108
110. C++::CONSTRUTORES EXPLÍCITOS
Considere a classe abaixo:
class Inteiro {
public:
int valor;
// construtor default inline com valor
Inteiro(int v=0) { valor = v; }
};
Ela permite instanciar objetos com:
Inteiro i1; i2(4);
Inteiro i3 = 44; // uso implícito de construtor
// transforma literal em objeto
O uso implícito de construtor é possível
quando não existe confusão possível
entre os construtores existentes, sendo
convertido para:
Inteiro i3(44);
Se desejado, o uso implícito de
construtores pode ser suprimido com uso
da palavra reservada explicit:
explicit Inteiro(int v=0) { valor = v; }
Isso evita que atribuições sejam
confundidas com a criação de objetos.
20/04/2017 (C) 2017, PJANDL. 110
111. C++::DESTRUTORES
Os construtores são operações especiais
que efetuam a inicialização dos objetos.
Por outro lado, existem os destrutores
(destructors), operações especiais que
atuam na remoção dos objetos,
permitindo que recursos do sistema
tomados na criação sejam devolvidos.
Os destrutores devem ser declarados
sempre que houver manipulação direta
de recursos de memória ou outros, que o
compilador não tem condição de
detectar e desfazer.
Considerando a existência dos
construtores e destrutores, percebemos
que os objetos possuem um ciclo de vida
associado ao escopo onde são
declarados.
Os destrutores são acionados quando o
escopo onde os objetos foram
declarados é finalizado.
20/04/2017 (C) 2017, PJANDL. 111
112. EXEMPLO _DINAMICA
#include <iostream>
using namespace std;
class Dinamica {
int* valor; // ponteiro para inteiro
public:
Dinamica(int=0); // construtor parametrizado
~Dinamica(); // destrutor
void ajustaValor(int); // ajusta valor do atributo
int obtemValor(); // obtém valor do atributo
};
Dinamica::Dinamica(int valor) { // construtor parametrizado
cout << "Construtorn"; // exibe mensagem
Dinamica::valor = new int; // aloca memória dinamicamente
*Dinamica::valor = valor; // armazena valor na memória
}
Dinamica::~Dinamica() { // destrutor
cout << "Destrutorn"; // exibe mensagem
delete valor; // libera região de memória alocada
}
void Dinamica::ajustaValor(int v) { *valor = v; }
int Dinamica::obtemValor() { return *valor; }
int main() {
cout << "inicio main()n"; // exibe mensagem
Dinamica obj1(10); // declara objeto
cout << obj1.obtemValor() << endl; // exibe valor do objeto
obj1.ajustaValor(20); // modifica valor do objeto
cout << obj1.obtemValor() << endl; // exibe valor do objeto
cout << "fim main()n"; // exibe mensagem
return 0; // encerra programa
}
20/04/2017 (C) 2017, PJANDL. 112
A execução deste programa
ilustra o ciclo de vida dos objetos
113. C++::THIS
A palavra reservada this representa o
endereço do próprio objeto na memória,
ou seja, é um ponteiro cujo valor é
diferente para cada objeto criado.
O ponteiro this é uma auto-referência
(self reference).
Em toda utilização de campo ou uso de
função-membro, implicitamente ocorre o
uso de this (exceto para membros
estáticos).
O uso de this é limitado, pois em geral
não é necessário exceto quando:
Deseja-se distinguir entre uma variável local e
um campo da classe com a mesma designação
(tal como feito pelo operador de resolução de
escopo ::); ou
Quando se deseja acesso ao objeto que
acionou um método específico; ou
Quando é necessário obter ou retornar um
ponteiro (this) ou referência (*this) para o
próprio objeto, útil na sobrecarga de
operadores.
20/04/2017 (C) 2017, PJANDL. 113
114. EXEMPLO _INTERVALO
class Intervalo {
double minimo;
double maximo;
public:
Intervalo(double min, double max) {
minimo = min;
maximo = max;
}
double valorMinimo() const {
return minimo;
}
double valorMaximo() const {
return maximo;
}
bool pertence(double v) const {
return v >= valorMinimo() && v <= valorMaximo();
}
};
this->minimo = min;
this->maximo = max;
return this->minimo;
return this->maximo;
return v >= this->valorMinimo() && v <= this->valorMaximo();
20/04/2017 (C) 2017, PJANDL. 114
Uso explícito de thisUso implícito de this
115. PARTE VI::
ORIENTAÇÃO A OBJETOS INTERMEDIÁRIA
C++ 200
UM MINICURSO
20/04/2017 (C) 2017, PJANDL. 115
116. C++::FUNÇÕES AMIGAS
Uma função não-membro de uma classe
pode receber o status de amiga (friend), o
que possibilita seu acesso aos membros
protegidos e privados, além dos públicos
cujo acesso é padrão.
Embora tal ação viole o encapsulamento
pretendido pela classe, é alternativa viável
na sobrecarga de operadores, além de
facilitar a criação de funções destinadas a
entrada/saída.
Seu uso deve ser feito com cautela!
class NomeClasse {
// membros privados e protegidos
public:
friend <tipo> funcao([paramList]);
:
};
// implementação da função-amiga
// que *não* é membro da classe!
<tipo> funcao([paramList]) {
}
20/04/2017 (C) 2017, PJANDL. 116
118. C++::CLASSES AMIGAS
Também é possível a existência de
classes amigas, que, como para as
funções amigas, também terão acesso a
membros privados e protegidos em
função da relação de amizade
estabelecida.
Novamente existe a situação de cautela
exigida pela violação conceitual do
encapsulamento.
// Colecao.h
#ifndef _COLECAO_H_
#define _COLECAO_H_
class Iterator; // definição da classe Iterator
class Colecao { // declaração da classe Colecao
int *v, tam, prox;
public:
Colecao(int=10); // construtor
~Colecao(); // destrutor
bool adiciona(int); // adiciona um elemento
int tamanho() const; // determina tamanho da coleção
int le(int) const; // obtém um elemento da coleção
void limpar(); // limpa coleção
friend class Iterator; // especifica classe amiga
};
class Iterator { // declaração da classe Iterator
int *v, tam, prox;
public:
Iterator(const Colecao&); // construtor
bool existeProximo() const; // verifica se existem mais elementos
int proximo(); // retorna próximo elemento
};
#endif
20/04/2017 (C) 2017, PJANDL. 118
Este exemplo também mostra a correta
organização do programa em múltiplos arquivos
de cabeçalho (header) e código-fonte (source).
119. EXEMPLO _COLECAO
// Colecao.cpp
#include "Colecao.h"
Colecao::Colecao(int t) {
tam = t; v = new int[tam]; prox = 0;
}
Colecao::~Colecao() { delete[] v; }
bool Colecao::adiciona(int valor) {
if (prox<tam) {
v[prox++] = valor; return true;
}
return false;
}
int Colecao::tamanho() const { return tam; };
int Colecao::le(int pos) const { return v[pos]; };
void Colecao::limpar() { prox=0; }
Iterator::Iterator(const Colecao &c) { v = c.v; tam = c.prox; prox = 0; }
bool Iterator::existeProximo() const { return prox<tam; }
int Iterator::proximo() {
if (prox<tam) return v[prox++]; return 0;
}
#include <iostream>
#include "Colecao.h"
using namespace std;
void listaColecao(const Colecao &c) {
Iterator it(c); // cria Iterator para Colecao
// lista elementos da Colecao através do Iterator
cout << "Colecao [ ";
while(it.existeProximo()) cout << it.proximo() << " ";
cout << "]n";
}
int main() {
Colecao c; // cria Colecao e adiciona elementos
for (int i=0; i<c.tamanho(); i++) c.adiciona(i);
listaColecao(c); // lista Colecao
c.limpar(); // limpa Colecao
listaColecao(c); // lista Colecao
return 0;
}
20/04/2017 (C) 2017, PJANDL. 119
120. C++::SOBRECARGA DE OPERADORES
Operadores disponíveis em C++
permitem realizar operações sobre tipos
de dados pré-definidos.
C++ permite redefinir a função de
muitos de seus operadores,
possibilitando seu uso para outros tipos
de dados, ou seja, a sobrecarga de
operadores (operator overload).
Sintaxe:
<Tipo> operator <sinal> (<parâmetros>);
Isto permite a construção de uma sintaxe
mais rica para os novos tipos definidos
para o programador.
Os operadores sobrecarregáveis são:
20/04/2017 (C) 2017, PJANDL. 120
+ - * / % ++ -- < <= >
>= == != && || ! & | ~ ^
>> << += -= *= /= %= &= |= ^=
>>= <<= , ( ) [ ] = -> ->* new delete
121. EXEMPLO _PONTO
#include <iostream>
using namespace std;
class Ponto {
public:
float x, y;
Ponto(float xi=0, float yi=0) {
x = xi; y = yi;
}
Ponto operator+(Ponto p) { // oper. sobrecarregado
Ponto tmp; // declara objeto aux
tmp.x = x + p.x; // soma x obj + param
tmp.y = y + p.y; // soma y obj + param
return tmp; // retorna objeto aux
}
};
int main() {
Ponto p1, p2; // declara objetos Ponto
cout << "Digite uma coordenada (x,y): ";
cin >> p1.x >> p1.y; // lê coord de ponto 1
cout << "Digite outra coordenada (x,y): ";
cin >> p2.x >> p2.y; // lê coord de ponto 2
// soma coordenadas
Ponto p3 = p1 + p2;
// exibe resultado e encerra programa
cout << "Coordenada final: (" << p3.x << ", “
<< p3.y << ")n";
return 0;
}
20/04/2017 (C) 2017, PJANDL. 121
Uso de sobrecarga de
operador
122. C++::SOBRECARGA DE OPERADORES
Sobrecarga de operadores possibilita
simplificação do programa:
Ponto p3 = p1 + p2;
O uso da sobrecarga é equivalente à:
Ponto p3 = p1.operator+(p2);
Uma classe pode possui várias operações
sobrecarregadas:
Ponto operator-(Ponto p) {
Ponto tmp;
tmp.x = x - p.x;
tmp.y = y - p.y;
return tmp;
}
Quando corretamente implementada, a
sobrecarga permite o encadeamento de
operações:
Ponto p = p1 + p2 + p3 + p4;
Que equivale à:
Ponto p =
p1.operator+(p2.operator+(p3.operator+(p4)));
20/04/2017 (C) 2017, PJANDL. 122
124. EXEMPLO _FRACAO
Fracao Fracao::operator+ (const int i) {
Fracao tmp(i/1);
return operator+(tmp);
}
Fracao Fracao::operator- (const int i) {
Fracao tmp(i/1);
return operator-(tmp);
}
istream& operator>>(istream& stream, Fracao &f) {
stream >> f.Numerador >> f.Denominador;
f.reduzir();
return stream;
}
ostream& operator<<(ostream& stream, const Fracao &f) {
stream << f.Numerador;
if (f.Denominador!=1) stream << "/" << f.Denominador;
return stream;
}
void Fracao::reduzir() {
int a, b, sinal = 1, resto;
if (Numerador==0) Denominador = 1;
if (Numerador<0 && Denominador<0) {
Numerador = -Numerador; Denominador = - Denominador;
} else if (Numerador<0) {
Numerador = - Numerador; sinal = -1;
} else if (Denominador<0) {
Denominador = - Denominador; sinal = -1;
}
if (Numerador<Denominador) {
a = Numerador; b = Denominador;
} else {
a = Denominador; b = Numerador;
}
while (b!=0) {
resto = a % b;
a = b; b = resto;
}
Numerador /= a*sinal;
Denominador /= a;
}
20/04/2017 (C) 2017, PJANDL. 124
125. EXEMPLO _FRACAO
#include "Fracao.h"
#include <iostream>
using namespace std;
int main() {
Fracao f1, f2, f3;
cout << "Digite 1a. fracao (nun den): "; cin >> f1;
cout << "Digite 2a. fracao (nun den): "; cin >> f2;
cout << "Soma de Fracoesn";
f3 = f1 + f2;
cout << f1 << " + " << f2 << " = " << f3 << endl;
cout << "Subtracao de Fracoesn";
f3 = f1 - f2;
cout << f1 << " - " << f2 << " = " << f3 << endl;
cout << "Soma de Fracao e inteiron";
f3 = f1 + 1;
cout << f1 << " + 1 = " << f3 << endl;
cout << "Subtracao de Fracao e inteiron";
f3 = f1 - 1;
cout << f1 << " - 1 = " << f3 << endl;
return 0;
}
Exemplos de uso de Fracao:
Fracao f1(1/4), f2(3/6), f3(4/5);
Fracao f4 = f1 + f2 + f3;
f4 = f4 + 1;
Fracao f5 = f1 – f2 – f3;
f5 = f4 – 3;
20/04/2017 (C) 2017, PJANDL. 125
126. C++::HERANÇA
A herança (inheritance) é uma das formas
mais importantes do polimorfismo e pode
ser entendida como uma técnica para
que uma classe passe a utilizar atributos
e operações definidas em uma outra
classe, ou seja, compartilhe uma parcela
de sua implementação.
C++ oferece tanto a herança simples,
como a herança múltipla.
Em geral, podemos perceber que existe
uma relação de herança entre duas
classes quando a pergunta 'é um(a)?' é
respondida afirmativamente.
Sintaxe da herança simples:
class <NomeClasseDerivada> :
[especificadorAcesso] <NomeClasseBase> {
// corpo da classe derivada
};
20/04/2017 (C) 2017, PJANDL. 126
127. EXEMPLO
// Base.h
class Base {
private:
int a;
protected:
int b;
public:
void ajustaAB(int na, int nb) {
a = na; b = nb; }
int leA() { return a; }
int leB() { return b; }
};
#include <iostream>
#include "Base.h"
using namesapce std;
int main() {
Base obj;
cout << obj.leA() << "," << obj.leB() << endl;
obj.ajustaAB(5, -2);
cout << obj.leA() << "," << obj.leB() << endl;
return 0;
}
20/04/2017 (C) 2017, PJANDL. 127
129. C++::HERANÇA
A herança pública é uma situação comum em
projetos C++, mas também pode ser
especificada diferentemente.
Na herança pública, a implementação da
própria subclasse e de suas subclasses têm
acesso aos membros herdados públicos e
protegidos; já as instâncias destas subclasses
têm acesso somente aos membros herdados
públicos.
Na herança privada apenas a implementação
da própria subclasse tem acesso aos membros
herdados públicos e protegidos. Nem as
instâncias desta subclasse nem suas subclasses
poderão utilizar os membros herdados.
20/04/2017 (C) 2017, PJANDL. 129
130. C++::HERANÇA MÚLTIPLA
A herança múltipla resolve as questões
de quando uma nova classe possui
relacionamento com várias outras, pois
permite que sejam criadas novas classes
que compartilhem as características de
duas ou mais classes base
simultaneamente.
Sintaxe para herança múltipla:
class <NomeClasseDerivada> :
[especificadorAcesso1] <NomeClasseBase1>,
[especificadorAcesso2] <NomeClasseBase2>,
:
[especificadorAcessoN] <NomeClasseBaseN>
{
// corpo da classe derivada
};
20/04/2017 (C) 2017, PJANDL. 130
131. EXEMPLO
// Func.h
#ifndef _FUNC
#define _FUNC
#include <iostream>
using namespace std;
class Funcionario {
long id;
public:
Funcionario(long nid) { id = nid;
cout << "Construtor Funcionario: " << nid << endl;
}
~Funcionario() { cout << "Destrutor Funcionarion"; }
long getId() { return id; }
};
ostream& operator<<(ostream &out, Funcionario &f) {
return out << "Funcionario[" << f.getId() << "]";
}
class Temporario {
int periodo;
public:
Temporario(int p) {
cout << "Construtor Temporario: " << p << endl;
periodo = p;
}
~Temporario() { cout << "Destrutor Temporarion"; }
int getPeriodo() { return periodo; }
};
ostream& operator<<(ostream &out, Temporario &t) {
return out << "Temporario(" << t.getPeriodo() << "d)";
}
20/04/2017 (C) 2017, PJANDL. 131
Observe a existência apenas de
construtores parametrizados.
Observe o uso da sobrecarga
de operadores.
132. EXEMPLO
class Engenheiro: public Funcionario {
public:
Engenheiro(long nid): Funcionario(nid) {
cout << "Construtor Engenheiro: " << nid << endl;
}
~Engenheiro() { cout << "Destrutor Engenheiron"; }
};
ostream& operator<<(ostream &out, Engenheiro &e) {
return out << "Engenheiro[" << e.getId() << "]";
}
class Estagiario: public Funcionario, public Temporario {
public:
Estagiario(long nid, int p): Funcionario(nid), Temporario(p) {
cout << "Construtor Estagiario: " << nid << ",“
<< p << endl;
}
~Estagiario() { cout << "Destrutor Estagiarion"; }
};
ostream& operator<<(ostream &out, Estagiario &e) {
return out << "Estagiario[" << e.getId() << "]";
}
#endif
20/04/2017 (C) 2017, PJANDL. 132
Observe como os parâmetros dos
construtores das superclasses foram supridos.
133. EXEMPLO
#include <iostream>
#include "Func.h"
using namespace std;
int main() {
cout << "Criando objeto Engenheiron";
Engenheiro eng(12345);
cout << "Criando objeto Estagiarion";
Estagiario est(67890, 90);
return 0; // destrói objetos implicitamente
}
A execução deste programa demonstra
a passagem de parâmetros para as
superclasses envolvidas.
20/04/2017 (C) 2017, PJANDL. 133
134. C++::POLIMORFISMO
O polimorfismo permite:
a sobrecarga de funções e operadores,
obtida em tempo de compilação (isto é,
implementadas diretamente) no código e
também possibilita explorar a herança e
funções virtuais para manipulação
genérica de classes em tempo de execução
As classes Engenheiro e Estagiario
podem ter objetos declarados assim:
Engenheiro eng(1111);
Estagiario estag(2222, 60);
Como ambos são derivados da classe
Funcionario é possível simplesmente
atribuir seus endereços a ponteiros do
tipo da superclasse:
Funcionario *func1 = ŋ
Funcionario *func2 = &estag;
20/04/2017 (C) 2017, PJANDL. 134
135. EXEMPLO
#include <iostream>
#include "Func.h“
using namespace std;
// função genérica baseada em referência
void informacao(Funcionario &f) {
cout << f << endl;
}
// função genérica baseada em ponteiro
void mostraId(Funcionario *f) {
cout << "Id: " << f->getId() << endl;
}
int main() {
Engenheiro eng(1111);
Estagiario estag(2222, 60);
Engenheiro &e = eng;
cout << eng << endl; // exibição de dados originais
cout << estag << endl;
informacao(e); // usa função genérica c/ referências
informacao(estag);
// declaraçao de ponteiros tipo Funcionario (genericos)
Funcionario *func1 = ŋ
Funcionario *func2 = &estag;
Funcionario *func3 = &e;
mostraId(func1); // usa função genérica c/ ponteiros
mostraId(func2);
mostraId(func3);
return 0;
}
20/04/2017 (C) 2017, PJANDL. 135
136. PARTE VII::
ORIENTAÇÃO A OBJETOS AVANÇADA
C++ 200
UM MINICURSO
20/04/2017 (C) 2017, PJANDL. 136
137. C++::FUNÇÕES VIRTUAIS
Uma subclasse pode substituir uma
método existente em sua superclasse
(sobreposição ou method override).
Devido o polimorfismo, o método
chamado (da superclasse ou da
subclasse) depende do tipo de ponteiro
ou referência usada.
Mas nem sempre o efeito produzido é o
desejado. Nestes casos pode-se lançar
mão das funções virtuais.
Funções virtuais são marcadas com o
modificador virtual.
Observe nos próximo exemplos o efeito
do modificador virtual, assim como o
fato de ser hereditário.
20/04/2017 (C) 2017, PJANDL. 137
138. EXEMPLO
#include <iostream>
using namespace std;
class ValorSimples {
public:
int v_valor;
ValorSimples(int v=0) { v_valor = v; }
int valor() { return v_valor; }
};
class ValorDuplo: public ValorSimples {
public:
ValorDuplo(int v=0): ValorSimples(v) { };
int valor() { return 2*v_valor; }
};
int main() {
ValorSimples vs(5); // declara obj ValorSimples
ValorDuplo vd(5); // declara obj ValorDuplo
ValorSimples *pvs; // declara ponteiro ValorSimples
pvs = &vs; // obtém endereço obj ValorSimples
cout << "obj. ValorSimples via pont. ValorSimples: "
<< pvs->valor() << endl;
pvs = &vd; // obtém endereço obj ValorDuplo
cout << "obj. ValorDuplo via pont. ValorSimples: "
<< pvs->valor() << endl;
ValorDuplo *pvd = &vd; // declara pont. ValorDuplo
cout << "obj. ValorDuplo via pont. ValorDuplo : "
<< pvd->valor() << endl;
return 0;
}
20/04/2017 (C) 2017, PJANDL. 138
Sem o uso de funções virtuais
139. EXEMPLO
#include <iostream>
using namespace std;
class ValorSimples {
public:
int v_valor;
ValorSimples(int v=0) { v_valor = v; }
virtual int valor() { return v_valor; } // função virtual
};
class ValorDuplo: public ValorSimples {
public:
ValorDuplo(int v=0): ValorSimples(v) { };
int valor() { return 2*v_valor; } // func virtual herdada
};
int main() {
ValorSimples vs(5); // declara obj ValorSimples
ValorDuplo vd(5); // declara obj ValorDuplo
ValorSimples *pvs; // declara ponteiro ValorSimples
pvs = &vs; // obtém endereço obj ValorSimples
cout << "obj. ValorSimples via pont. ValorSimples: "
<< pvs->valor() << endl;
pvs = &vd; // obtém endereço obj ValorDuplo
cout << "obj. ValorDuplo via pont. ValorSimples: "
<< pvs->valor() << endl;
ValorDuplo *pvd = &vd; // declara pont. ValorDuplo
cout << "obj. ValorDuplo via pont. ValorDuplo : "
<< pvd->valor() << endl;
return 0;
}
20/04/2017 (C) 2017, PJANDL. 139
Com o uso de funções virtuais Classe ValorDuplo e função
main() não foram alteradas
140. C++::FUNÇÕES VIRTUAIS PURAS
Uma função-membro virtual pura é
aquela que não possui definição numa
classe, obrigando que suas subclasses
realizem tal definição.
Para indicar que uma função-membro é
'puramente virtual' (pure virtual) devemos
declará-la como:
virtual <tipo> nomeFunc([listaParam]) = 0;
Classes contendo métodos virtuais puros
são consideradas classes abstratas
(abstract classes), pois como sua
implementação está incompleta, não
podem ser instanciadas.
20/04/2017 (C) 2017, PJANDL. 140
141. EXEMPLO
// Comp.h
#ifndef _COMPONENTE
#define _COMPONENTE
#include <iostream>
#include <string>
class Componente {
string descr; // descrição do componente
int id; // id do componente
Componente *pai; // componente pai
public:
Componente(int n) {
id = n; defineDescr("Componente");
pai = NULL;
}
void defineDescr(const string d) { descr = d; }
string obtemDescr() const { return descr; }
unsigned int obtemId() const { return id; }
void definePai(Componente *c) { pai = c; }
Componente *obtemPai() const { return pai; }
virtual void draw()=0;
};
20/04/2017 (C) 2017, PJANDL. 141
144. C++::NAMESPACES
Um namespace é um bloco de escopo
denominado ou um espaço declarativo
identificado (ANSI, 1989), cujas definições
permitem agrupar conjuntos de classes,
objetos e funções sob um nome.
Na prática, os namespaces dividem o escopo
global em escopos menores.
Sintaxe:
namespace identificador {
// bloco do sub-escopo (ou do namespace)
}
Exemplo:
namespace IC {
long a;
double b;
int func (int) { ... }
}
20/04/2017 (C) 2017, PJANDL. 144
146. C++::TEMPLATES
O mecanismo de construção dos templates
(ou modelos) em C++ permite que um tipo
(primitivo ou classe) seja empregado como
parâmetro na definição de uma função, ou
classe, ou mesmo outro modelo.
Os templates possibilitam criar funções e
classes capazes de realizar suas operações
com tipos distintos de dados sem o emprego
da sobrecarga, ou seja, preservando a lógica
interna e mantendo-se genérica em relação
aos tipos de dados manipulados.
Sintaxe:
template <classId1 [, classId2 ...]>
declaraçãoDaFunção;
template <classId1 [, classid2 ...]>
declaraçãoDaClasse;
Exemplo:
template <class Tipo>
Tipo Minimo (Tipo x, Tipo y) {
Tipo resultado = x > y ? x : y;
return resultado;
}
20/04/2017 (C) 2017, PJANDL. 146
147. EXEMPLO _TEMPLATES
#include <iostream>
using namespace std;
template <class T>
T Minimo (T x, T y) {
T resultado = x < y ? x : y;
return resultado;
}
int main() {
int a = 1, b = 2;
long c = 1029, d = -10;
double e = 2.34e10, f = 0.23e-2;
int r1 = Minimo<int>(a, b);
long r2 = Minimo(c, d);
cout << "Minimo(" << a << ", " << b
<< ")= " << r1 << endl;
cout << "Minimo(" << c << ", " << d
<< ")= " << r2 << endl;
cout << "Minimo(" << e << ", " << f
<< ")= " << Minimo(e, f) << endl;
return 0;
}
20/04/2017 (C) 2017, PJANDL. 147