Vous êtes sur la page 1sur 220

Universidade Católica de Pelotas

Escola de Informática
Ciência da Computação

C++ for Linux


por
Prof. Dr. Paulo Roberto Gomes Luzzardi
luzzardi@atlas.ucpel.tche.br
Home Page: http://infovis.ucpel.tche.br/luzzardi
http://graphs.ucpel.tche.br/luzzardi
http://gcg.ucpel.tche.br/luzzardi

Versão: 2.03

Referências Bibliográficas

Stroustrup, Bjarne. The C++ Programming Language. Third Edition and


Special Edition. Addison-Wesley, 2000.

Reissig, Noriel Chang. Programação Orientada a Objetos em C++.


Material de estudo, UCPel, 1994.

Pelotas, 01 de outubro de 2006


Sumário
1. Introdução
1.1 Origens
1.2 Conceitos básicos
1.2.1 Objetos, mensagens, classes, instâncias e métodos
1.2.2 Abstração
1.2.3 Encapsulamento
1.2.4 Polimorfismo
1.2.5 Herança
1.2.6 C++ versus C
1.2.7 Tipos de dados em C++
1.3 Estilo de programação em C++
1.4 Classes em C++
1.5 Sobrecarga de funções
1.6 Herança simples
1.7 Construtores e destrutores
1.8 Palavras reservadas em C++
1.9 Forma geral de um programa em C++
1.10 Classe “string”
1.11 Exemplos de programas em C++
2. Classes e Objetos
2.1 Classes
2.2 Funções friend
2.3 Funções inline
2.4 Definindo funções inline dentro de uma classe
2.5 Construtores parametrizados
2.6 Quando construtores e destrutores são executados
2.7 Operador resolução de escopo
2.8 Passando objetos para funções
2.9 Retornando objetos
2.10 Atribuição de objetos
3. Array, Ponteiros e Referências
3.1 Array de objetos
3.2 Ponteiros de objetos
3.3 O ponteiro this
3.4 Referências
3.4.1 Parâmetros referenciados
3.4.2 Passando referências a objetos
3.4.3 Retornando referências
3.5 Operadores C++ para alocação dinâmica
3.5.1 Alocando objetos
3.5.2 Alocação de memória
4. Sobrecarga de Operadores e Funções
4.1 Sobrecarga de operadores
4.2 Criando uma função-operador membro
4.3 Sobrecarga de operadores utilizando uma função friend
5. Herança
5.1 Controle de acesso em classes base
5.2 Herança e membros protegidos
5.3 Herança múltipla de classes base
5.4 Passando parâmetros para os construtores das classes base
5.5 Garantindo acesso
5.6 Classes base virtuais
6. Funções Virtuais e Polimorfismo
6.1 Funções virtuais
6.2 Funções virtuais puras
6.3 Classes abstratas
6.4 Usando funções virtuais
7. Utilização Básica do Sistema de I/O do C++
7.1 Fluxos do C++
7.2 Classes básicas dos streams
7.3 Streams pré-definidos do C++
7.4 Entrada e saída formatada
7.5 Formatando utilizando os membros de entrada e saída
7.6 Setando flags de formato
7.7 Formatando usando manipuladores
8. Tratamento de Exceções
9. Jogo escrito em C++
10. Classes pré-definidas do C++
10.1 Classe <string>
10.2 Classe <vector>
11. Tabela ASCII
12. Glossário
13. Arquivos em C++
14. Programas em C++
15. Outros conceitos em C++
15.1 Métodos const
15.2 Métodos static
15.3 Referências para Ponteiros
15.4 Arquivos “conio.c” e “conio.h” em C++
15.5 Templates em C++
16. Composição
C++ for Linux
Prof. Dr. Paulo Roberto Gomes Luzzardi

1. Introdução
O termo Programação Orientação à Objetos (OOP - Object
Oriented Programming) significa organizar um programa de forma
que o mundo real seja representado virtualmente (ou internamente)
como se fosse uma coleção de objetos que incorpora uma estrutura
de dados (variáveis ou atributos) e um conjunto de operações
(funções ou métodos) que manipulam esta estrutura.

1.1 Origens

A linguagem de programação C++ é uma extensão da linguagem


C padrão. Foi criada por Bjarne Stroustrup em 1980 na Bell, que a
chamou de “C com Classes” e em 1983 passou-se a se chamar C++.

1967: Simula (Noruega).


1980: Small Talk (Xerox) com objetivos comerciais e acadêmicos (Adele Goldberg).
1980's Objective C (Cox), C++ (Stroustrup), Eifell (Meyer).

1.2 Conceitos básicos

O paradigma orientado à objetos possui cinco componentes


básicos: objetos, mensagens, classes, instâncias e métodos.

1.2.1 Objetos, mensagens, classes, instâncias e métodos

Objetos são entidades lógicas que contém atributos (dados


armazenados em variáveis) e métodos (funções) que manipulam estes
dados. Um objeto pode ser definido através de um tipo de dado
chamado classe (class) ou através de uma estrutura (struct).

Atributos: São as variáveis definidas e declaradas para cada


objeto. Existe dois tipos: atributos dos objetos (é individual
para cada objeto, ou seja, cada objeto pode possuir um valor
diferente) e atributos da classe (são estáticos, ou seja,
coletivos, iguais para todos os objetos).

Métodos: São as funções definidas pelo programador que


servirão para manipular os atributos.

Mensagens: São as chamadas dos métodos (chamada das


funções).
Classe: É um tipo de dado definido por class ou struct. Uma
classe não é um objeto, é sim uma descrição do objeto.

Instância: Os objetos são instâncias de uma classe.

Resumidamente, objetos são instâncias de classes que


respondem as mensagens através dos métodos escritos pelo
programador.

Existem algumas diferenças na nomenclatura da programação


orientação à objetos e a definida em C++, veja no quadro abaixo:

POO C++
classe classe
objeto objeto
Método função
atributo atributo
mensagem chamada de uma função
sub-classe classe derivada
super-classe classe base
herança derivação

const int max = 10;

typedef int TDADOS;

// ----------------------------------- Definição da Classe Pilha (... // comentário em C++)

class Pilha
{
TDADOS pilha[max]; // ... atributo do objeto, cada um possui o seu
int topo; // ... atributo do objeto, cada um possui o seu
static int n; // ... atributo da classe, coletivo para todos os objetos
static const float pi; // ... atributo constante da classe, coletivo para todos os objetos
public:
  void Cria_Pilha(void); // ... métodos (ou mensagens)
  void Push(TDADOS dado); // ... métodos (ou mensagens)
  TDADOS Pop(void); // ... métodos (ou mensagens)
  TDADOS Consulta_Pilha(void); // ... métodos (ou mensagens)
void Exibe_Pilha(void); // ... métodos (ou mensagens)
};

Os atributos podem ser: atributos do objeto, atributos da


classe (estáticos) e atributos constantes (veja o próximo programa
exemplo).
● Atributos do objeto: São individuais para cada objeto, ou seja,
cada objeto pode ter um valor diferente.
● Atributos da classe: São estáticos, ou seja, coletivos, iguais para
todos os objetos. Podem ser alterados (a inicialização deve ser
feita fora da classe).
● Atributos constantes: São constantes e estáticos, ou seja,
coletivos, iguais para todos os objetos. Não podem ser alterados,
pois são constantes (a inicialização deve ser feita fora da classe).

class Math
{
int x, y; // ... atributo do objeto, cada um possui o seu
static int n; // ... atributo da classe, coletivo para todos os objetos
static const float pi; // ... atributo constante da classe, coletivo para todos os objetos
public:
Math(void) : x(1), y(2) { } // inicialização dos atributos através do construtor
void Exibe(void)
{
cout << x << “ - “ << y << endl;
}
};

int Math :: n = 7; // inicialização do atributo da classe (tem que ser fora da classe)
const float Math :: pi = 3.141516; // inicialização do atributo constante da classe

Observação: Um objeto (instância de uma classe) pode ser


comparado a uma estrutura (struct) do C padrão, mas além de possuir
campos (dados, variáveis ou atributos), possui também as funções
(métodos) que manipulam estes dados (atributos), ou seja,
encapsulamento de dados e código. Uma classe é uma extensão do
tipo de dados struct. Uma estrutura (struct) em C++ tem as mesmas
características de uma classe (class).

Uma linguagem de programação orientada à objetos precisa


suportar quatro propriedades: abstração, encapsulamento, herança
e polimorfismo.

1.2.2 Abstração

Objetos devem representar dados do mundo real.

1.2.3 Encapsulamento (“encapsulação”)

Os objetos possuem internamente atributos e métodos agrupados


no mesmo local, onde os métodos manipulam os atributos.

1.2.4 Polimorfismo (grego: “muitas formas”)


É a capacidade de objetos diferentes reagirem segundo a sua
função a uma ordem padrão. Significa que o nome de um objeto pode
ser utilizado para vários propósitos ligeiramente diferentes, ou seja, “ ...
uma interface, vários métodos ... ”. A característica de polimorfismo é
utilizada na sobrecarga de funções e sobrecarga de operadores.

1.2.5 Herança

É o processo pelo qual uma classe de objetos pode adquirir as


propriedades de outra classe de objetos, em outras palavras, um objeto
herda as características de outro (herança simples) ou vários objetos
(herança múltipla).

1.2.6 C++ versus C

A Linguagem de Programação C++ possui as seguintes caracterís-


ticas que a linguagem C não possui, dentre elas pode-se citar:

a) Utilização de classes e objetos;


b) Utilização de funções inline;
c) Conversão de tipos (vários tipos de casts);
d) Verificação de argumentos (parâmetros) das funções;
e) Operadores de gerenciamento de memória (new e delete) específicos;
f) Utilização de referências no lugar de ponteiros;
g) Uso de constantes tipadas (const int n = 7;)
h) Sobrecarga de operadores;
i) Sobrecarga de funções;
j) Polimorfismo (sobrecarga de operadores e funções);
k)Templates (utilização de gabaritos): são funções genéricas em que o
tipo dos dados (parâmetros e retorno da função) são definidos em tempo
de compilação;
l) Tratamento de exceções (tratamento de erros);
m) Espaços de nomes (namespace).

1.2.7 Tipos de dados em C++

Tipos básicos: char, int, float, double, void.

Tipos derivados: vetor, funções, ponteiros, referências, constantes,


classes e estruturas.

Tipo lógico: bool (true e false são pré-definidos em C++)


Como declarar e utilizar uma variável lógica:

int main(void)
{
bool ok = true;
bool flag = false;
}

Modificadores de tipos em C++: signed, unsigned, short e long.

Tipo de Dado Tipo Bits Bytes Faixa


bool lógico 8 1 true ou false (0 ou 1)
char caracter 8 1 ­128 à 127
unsigned char caracter c/sinal 8 1 0 à 255
short int inteiro curto 16 2 ­32768 à 32767
unsigned short int inteiro curto sem sinal 16 2 0 à 65535
int inteiro 32 4 ­2.147.483.648 à 2.147.483.648
unsigned int inteiro sem sinal 32 4 0 à 4.294.295.000
long int inteiro longo 32 4 ­2.147.483.648 à 2.147.483.648
unsigned long int inteiro longo sem sinal 32 4 0 à 4.294.967.296
float real (precisão de 7 dígitos) 32 4 ­3.4e­38 à 3.4e+38
double real (precisão de 15 dígitos) 64 8 ­1.7e­308 à 1.7e+308
long double real (precisão de 18 dígitos) 80 10 ­3.4e­4932 à 3.4e+ 4932
enum enumeração 16 2 ­2.147.483.648 à 2.147.483.648
long long int  inteiro super longo 64 8 ­9.223.372.036.854.775.808 à  
9.223.372.036.854.775.807

long int x = 2147483648l; // necessário um “l”


long long int y = 9223372036854775807ll; // necessário dois “ll”

Programa exemplo:

#include <iostream>

using namespace std;

int main(void)
{
long long int x = 9223372036854775807ll;

cout << x << endl; // 9223372036854775807


x++;
cout << x << endl; // -9223372036854775808 Porque?
}

Observação: Sempre que uma operação matemática for realizada e o valor for maior
ou menor que os valores máximo e mínimo, referente a faixa de valores válidos, o
programa rotaciona e coloca o resultado da operação dentro da faixa de valores
válidos. No programa acima, quando o maior valor possível de um inteiro super longo é
acrescido em um, o valor resultante é o menor valor da faixa de valores.
1.2.8 Alguns conceitos básicos em C++

Classes de armazenamento: É responsável pelo tempo de vida de um


objeto:

● Se o objeto for estático ele dura (permanece alocado na memória


RAM) todo o tempo de vida do programa.
● Se ele for dinâmico (new) ele tem um tempo finito de vida, ou
seja, ele depende do comando (delete), ou seja, ele é alocado e
desalocado da memória RAM.

1.3 Estilo de programação em C++

Aqui são mostradas mais algumas diferenças entre o C e C++.

Programa exemplo (1): Primeiro programa em C++: “Hello World”.

// hello.cpp // ... comentário em C++

#include <iostream.h> // ... header responsável pelas funções de entrada e saída (cin e cout)

int main(void)
{
cout << "Hello, World ...\n"; // ... imprime na tela
cout << “Tecle <enter> para continuar";
cin.get(); // ... para e espera que uma tecla seja pressionada
return(0);
}

Programa exemplo (2): Programa permite a entrada de uma palavra


via teclado (cin) e exibe (cout) o número de caracteres (strlen) desta
palavra na tela.

// palavra.cpp

#include <iostream.h>
#include <string.h>

int main(void)
{
char palavra[256];

cout << "Digite uma palavra: ";


cin >> palavra; // ... entrada de dados via teclado (não aceita espaços)
cout << "Palavra tem " << strlen(palavra) << " caracter(es)" << endl; // pula próxima linha
return(0); // strlen pertence ao C padrão
}
Observações:

cout << “Palavra: ”; // ... << é chamado operador de saída


cin >> palavra; // ... >> é chamado operador de entrada

Programa exemplo (3): O programa permite a entrada de uma palavra


via teclado (cin.getline) e exibe (cout) o número de caracteres (strlen)
desta palavra na tela.

// nome.cpp

#include <iostream.h>
#include <string.h>

int main(void)
{
char nome[81];

cout << "Digite um Nome: ";


cin.getline(nome, 80); // ... entrada de dados via teclado (aceita espaços)
cout << nome << " tem " << strlen(nome) << " caracter(es)" << endl;
return(0);
}

Programa exemplo (4): O programa permite a entrada de uma palavra


via teclado (cin) e exibe (cout) o número de caracteres (strlen) desta
palavra na tela demonstrando como limpar o buffer de teclado
(cin.ignore).

// pausa.cpp

#include <iostream.h>
#include <string> // header do C++, existe também string.h do C padrão

using namespace std; // necessário para o header string

void pausa(void)
{
cin.ignore(5,'\n'); // limpar o buffer de teclado
cin.get(); // espera uma tecla qualquer
}

int main(void)
{
string palavra; // classe string, não precisa inicializar

cout << "Digite uma palavra: ";


cin >> palavra; // ... entrada de dados via teclado
cout << "Palavra tem " << palavra.length() << " caracter(es)" << endl;
pausa(); // pausa
}

Programa exemplo (5): O programa demonstra a definição e utilização


de uma classe Ponto.

// ponto.cpp

#include <iostream>

using namespace std; // necessário por causa do include sem (.h)

class Ponto // definição de uma classe


{
int x,y; // não é necessário declarar implicitamente como private

void seta_atributos(int tx, int ty) // método privado, não pode ser chamado pelo main
{ // somente por métodos da classe Ponto
x = tx;
y = ty;
}
public:
void Inicializa(int tx, int ty) // métodos públicos, podem ser chamados pelo main
{
seta_atributos(tx,ty);
}
void Exibe(void)
{
cout << "( x = " << x << " ) ( y = " << y << " )" << endl;
}
void Move(int tam)
{
x = x + tam;
y = y + tam;
}
}; // não esquecer ponto-e-vírgula

int main(void)
{
Ponto pt; // declaração de um objeto pt da classe Ponto

pt.Inicializa(1,2);
pt.Exibe();
pt.Move(10);
pt.Exibe();
}

Resultado do Programa:

(x=1)(y=2)
( x = 11 ) ( y = 12 )

Programa exemplo (6): Programa demonstra a definição e utilização


de uma classe Calculadora, simulando quatro operações [+, -, * e /].

// calc.cpp

#include <iostream>

using namespace std;

class Calculadora
{
private:
double x,y,resp;
char op;
bool erro; // bool ... tipo lógico (true ou false)
private:
void Add(void)
{
resp = x + y;
erro = false;
}
void Sub(void)
{
resp = x - y;
erro = false;
}
void Mult(void)
{
resp = x * y;
erro = false;
}
void Div(void)
{
if (y not_eq 0) // not_eq é igual a !=
{
resp = x / y;
erro = false;
}
else
erro = true;
}
public:
void Entrada(void)
{
cout << "Digite um valor: ";
cin >> x;
cout << "Operador [+-*/]: ";
do {
op = cin.get();
} while (not strchr("+-*/",op)); // not é igual a !
cout << "Digite outro valor: ";
cin >> y;
}
void Calcula(void)
{
switch (op)
{
case '+': Add();
break;
case '-': Sub();
break;
case '*': Mult();
break;
case '/': Div();
break;
}
}
void Exibe(void)
{
if (erro)
cout << "ERRO: Divisão por Zero" << endl;
else
cout << "Resposta: " << resp << endl;
}
};

int main(void)
{
Calculadora calc; // Calculadora (classe) – calc (objeto)

calc.Entrada();
calc.Calcula();
calc.Exibe();
}

Programa exemplo (7): O programa demonstra a declaração de


variáveis em qualquer lugar ou no escopo de um bloco ou comando.

// ascii.cpp

#include <iostream.h>

int main(void)
{
for (char i = 'A';i <= 'Z';i++) // a variável “i” foi declarada no escopo do comando “for”
cout << i;
cout << endl;
for (char j = 'a';j <= 'z';j++) // a variável “j” foi declarada no escopo do comando “for”
cout << j;
cout << endl;
return(0);
}

Programa exemplo (8): O programa exibe na tela a tabela ASCII.

// asctable.cpp

#include <iostream>
using namespace std;

int main(void)
{
for (int cod = 32;cod <= 127;cod++)
{
cout << "Código: " << cod << "-> Caracter: " << (char) cod; // cast char
cin.get();
}
}

Comentário: Em C++ é permitido declarar variáveis locais dentro de


um bloco.

Observação: Uma variável declarada no escopo de um comando ou


dentro de um bloco somente pode ser acessada no bloco ou no escopo
do comando.

namespace
Quando o programador escreve um programa pode ocorrer a
repetição de um nome de um método e/ou classe que já existe em
alguma biblioteca padrão. Para evitar esse erro, utiliza-se namespace.

Um namespace permite dividir um programa em regiões que


mantêm suas próprias tabelas de símbolos (regiões chamadas
declarativas). Um namespace evita que nomes declarados em um
programa entrem em conflito com outros nomes definidos no mesmo
programa, uma vez que os nomes de um namespace são
independentes dos outros.

Se um namespace não é utilizado é preciso referenciar as


funções da seguinte maneira: namespace :: nome (exemplo:
std::cout).

Programa SEM o uso o namespace:

Programa exemplo (9): O programa exibe na tela a tabela ASCII


mostrando a não utilização do namespace.

// ascii.cpp

#include <iostream> // note que o arquivo de header está sem “.h”

int main(void)
{
for (char i = 'A';i <= 'Z';i++)
std::cout << i;
std::cout << std::endl;
for (char j = 'a';j <= 'z';j++)
std::cout << j;
std::cout << std::endl;
}

Programa COM o uso o namespace:

Programa exemplo (10): O programa exibe na tela a tabela ASCII


mostrando a utilização do namespace.

// ascii.cpp

#include <iostream>

using namespace std; // necessário para o header iostream

int main(void)
{
for (char i = 'A';i <= 'Z';i++)
cout << i;
cout << endl;
for (char j = 'a';j <= 'z';j++)
cout << j;
cout << endl;
}

1.4 Classes em C++

Em C++, para criar um objeto, é necessário definir uma classe


(class). Como foi visto anteriormente, uma classe é sintaticamente
similar a uma estrutura (struct), apenas com a diferença que a estrutura
é manipulada por funções externas, ao invés da classe, que possui as
funções internas para manipular seus atributos.

Uma classe pode ter atributos e métodos privados (private) e/ou


públicos (public). Por default, os atributos e métodos de uma classe
são privados, ou seja, se nenhum especificador de acesso for
declarado, o compilador considera por default private.

Se os atributos e métodos são privados, eles só podem ser


acessados por funções (métodos) membros da classe.

Sintaxe de uma classe:

class nome_da_classe
{
atributos e métodos privados; // ... só podem ser acessados por objetos desta classe

public:
atributos e métodos públicos; // ... podem ser acessados por outros objetos
};
Exemplo da declaração de uma classe:

const int TAM = 9; // constante tipada

typedef int TDADOS;

// -------------------------------------- Definição da Classe Fila

class Fila
{
TDADOS fila[TAM]; // ... atributo privado
int inic, fim; // ... atributos privados

public:
  void Cria_Fila(void); // ... método público
  void Inclui_Fila(TDADOS dado); // ... método público
  TDADOS Exclui_Fila(void); // ... método público
  TDADOS Consulta_Fila(void); // ... método público
  void Exibe_Fila(void); // ... método público
};

Como escrever um método (função) fora da classe:

// -------------------------------------- Inclui_Fila

void Fila :: Inclui_Fila(TDADOS dado) // ... :: operador de resolução de escopo


{
if (fim == TAM-1)
{
cout << "Erro: Fila Cheia" << endl;
return;
}
fila[fim] = dado;
fim++;
}

Outra forma de declarar uma classe (struct):

Programa exemplo (11): O programa demonstra a declaração de uma


classe através de uma struct.

// struct.cpp

#include <iostream>

using namespace std;

struct Contador
{
private:
int num;
public:
void init(void)
{
num = 0;
}
void incrementa(void)
{
num = num + 1;
}
int exibe(void)
{
return(num);
}
};

int main(void)
{
Contador c;

c.init();
cout << c.exibe() << endl;
c.incrementa();
cout << c.exibe() << endl;
cin.get();
}

Como definir um objeto:

nome_da_classe nome_do_objeto, nome_do_objeto, ...;

Exemplo:

Fila fila1, fila2; // ... definição dos objetos “fila1” e “fila2”

Como acessar um método (como enviar mensagem para um objeto):

fila1.Cria_Fila();
fila2.Cria_Fila();

Programa exemplo (12): Implementação do objeto Lista (Lista Linear).

// linear.cpp (Lista_Linear)

#include <iostream>
#include <string>
#include <cctype> // ctype para o C++

using namespace std;


const int tam = 5;

typedef int TDADOS;

// -------------------------------------- Definição da Classe Lista


class Lista
{
TDADOS lista[tam]; // atributos privados (private)
int n;
public:
void Inicializa_Lista(void);
void Inclui_Lista(TDADOS dado);
TDADOS Exclui_Lista(void);
TDADOS Consulta_Lista(void);
void Exibe_Lista(void);
}; // ... obrigatório ponto-e-vírgula

// -------------------------------------- Inicializa_Lista

void Lista :: Inicializa_Lista(void)


{
n = 0;
}

// -------------------------------------- Inclui_Lista

void Lista :: Inclui_Lista(TDADOS dado)


{
if (n == tam)
{
cout << "Erro: Lista Cheia" << endl;
return;
}
lista[n] = dado;
n++;
}

// -------------------------------------- Exclui_Lista

TDADOS Lista :: Exclui_Lista(void)


{
if (n == 0)
{
cout << "Erro: Lista Vazia” << endl;
return(0);
}
n--;
return(lista[n+1]);
}

// -------------------------------------- Consulta_Lista

TDADOS Lista :: Consulta_Lista(void)


{
if (n == 0)
{
cout << "Erro: Lista Vazia" << endl;
return(0);
}
return(lista[n-1]);
}

// -------------------------------------- Exibe_Lista

void Lista :: Exibe_Lista(void)


{
cout << "Lista: ";
if (n == 0)
{
cout << "VAZIA” << end;
return;
}
for (int i = 0;i < n;i++)
cout << lista[i] << " ";
cout << endl;
return;
}

// -------------------------------------- Programa Principal

int main(void)
{
Lista lista;
char tecla;
TDADOS valor;

lista.Inicializa_Lista();
do {
lista.Exibe_Lista();
cout << "[I]nclui, [E]xclui, [C]onsulta ou [F]im: ";
do {
tecla = toupper(cin.get());
} while (not strchr("IECF", tecla));
switch (tecla)
{
case 'I': cout << "Valor: ";
cin >> valor;
lista.Inclui_Lista(valor);
break;
case 'E': valor = lista.Exclui_Lista();
if (valor not_eq 0)
cout << "Valor Excluído da Lista: " << valor << endl;
break;
case 'C': valor = lista.Consulta_Lista();
if (valor not_eq 0)
cout << "Valor Consultado: " << valor << endl;
break;
}
} while (tecla not_eq 'F');
}

Programa exemplo (13): Implementação de um objeto Pilha.

// Pilha.cpp
#include <iostream>
#include <string>
#include <cctype>

using namespace std;

const int tam = 50;

typedef int TDADOS;

// -------------------------------------- Definição da Classe Pilha

class Pilha
{
TDADOS pilha[tam];
int topo;
public:
void Cria_Pilha(void);
void Push(TDADOS dado);
TDADOS Pop(void);
TDADOS Consulta_Pilha(void);
void Exibe_Pilha(void);
};

// -------------------------------------- Cria_Pilha

void Pilha :: Cria_Pilha(void)


{
topo = 0;
}

// -------------------------------------- Push

void Pilha :: Push(TDADOS dado)


{
if (topo == tam)
{
cout << “Erro: Pilha Cheia” << endl;
return;
}
pilha[topo] = dado;
topo++;
}

// -------------------------------------- Pop

TDADOS Pilha :: Pop(void)


{
if (topo == 0)
{
cout << "Erro: Pilha Vazia” << endl;
return(0);
}
topo--;
return(pilha[topo]);
}

// -------------------------------------- Consulta_Pilha

TDADOS Pilha :: Consulta_Pilha(void)


{
if (topo == 0)
{
cout << "Erro: Pilha Vazia" << endl;
return(0);
}
return(pilha[topo-1]);
}

// -------------------------------------- Exibe_Pilha

void Pilha :: Exibe_Pilha(void)


{
cout << "Pilha: ";
if (topo == 0)
{
cout << "VAZIA” << endl;
return;
}
for (int i = topo-1;i >= 0;i--)
cout << pilha[i] << " ";
cout << endl; // … pode ser usada a função “endl”;
return;
}

// -------------------------------------- Programa Principal

int main(void)
{
Pilha pilha;
char tecla;
TDADOS valor;

pilha.Cria_Pilha();
do {
pilha.Exibe_Pilha();
cout << "[P]ush, P[o]p, [C]onsulta ou [F]im: ";
do {
tecla = toupper(cin.get());
} while (not strchr("POCF", tecla));
switch (tecla)
{
case 'P': cout << "Valor: ";
cin >> valor;
pilha.Push(valor);
break;
case 'O': valor = pilha.Pop();
if (valor not_eq 0)
cout << "Valor Excluído da Pilha: " << valor << endl;
break;
case 'C': valor = pilha.Consulta_Pilha();
if (valor not_eq 0)
cout << "Valor Consultado: " << valor << endl;
break;
}
} while (tecla not_eq 'F');
}

Programa exemplo (14): Implementação de um objeto Fila.

// Fila.cpp

#include <iostream>
#include <string>
#include <cctype>

using namespace std;

const int tam = 5;


typedef int TDADOS;

// -------------------------------------- Definição da Classe Fila

class Fila
{
TDADOS fila[tam];
int inic,fim;
public:
void Cria_Fila(void);
void Inclui_Fila(TDADOS dado);
TDADOS Exclui_Fila(void);
TDADOS Consulta_Fila(void);
void Exibe_Fila(void);
};

// -------------------------------------- Cria_Fila

void Fila :: Cria_Fila(void)


{
inic = 0;
fim = 0;
}

// -------------------------------------- Inclui_Fila

void Fila :: Inclui_Fila(TDADOS dado)


{
if (fim == tam-1)
{
cout << "Erro: Fila Cheia" << endl;
return;
}
fila[fim] = dado;
fim++;
}

// -------------------------------------- Exclui_Fila

TDADOS Fila :: Exclui_Fila(void)


{
if (fim == 0)
{
cout << "Erro: Fila Vazia" << endl;
return(0);
}
inic++;
if (inic >= fim)
fim = 0;
return(fila[inic-1]);
}

// -------------------------------------- Consulta_Fila

TDADOS Fila :: Consulta_Fila(void)


{
if (fim == 0)
{
cout << "Erro: Fila Vazia" << endl;
return(0);
}
return(fila[inic]);
}

// -------------------------------------- Exibe_Fila

void Fila :: Exibe_Fila(void)


{
cout << "Fila: ";
if (fim == 0)
{
cout << "VAZIA\n";
return;
}
for (int i = inic;i < fim;i++)
cout << fila[i] << " ";
cout << endl;
return;
}

// -------------------------------------- Programa Principal

int main(void)
{
Fila fila;
char tecla;
TDADOS valor;
fila.Cria_Fila();
do {
fila.Exibe_Fila();
cout << "[I]nclui, [E]xclui, [C]onsulta ou [F]im: ";
do {
tecla = toupper(cin.get());
} while (not strchr("IECF", tecla));
switch (tecla)
{
case 'I': cout << "Valor: ";
cin >> valor;
fila.Inclui_Fila(valor);
break;
case 'E': valor = fila.Exclui_Fila();
if (valor not_eq 0)
cout << "Valor Excluído da Fila: " << valor << endl;
break;
case 'C': valor = fila.Consulta_Fila();
if (valor not_eq 0)
cout << "Valor Consultado: " << valor << endl;
break;
}
} while (tecla not_eq 'F');
}

1.5 Sobrecarga de funções

Uma das formas de polimorfismo em C++ é feito através da


sobrecarga de funções, ou seja, duas ou mais funções, com mesmo
nome, recebem parâmetros de tipos diferente podendo ainda ter retorno
diferentes.

Programa exemplo (15): O programa demonstra a sobrecarga de


funções (abs).

// abs.cpp

#include <iostream>

using namespace std;

// ----------------------------- prototypes

int abs(int x); // declaração da função abs


double abs(double x); // … sobrecarga da função abs

// ----------------------------- Programa Principal

int main(void)
{
cout << abs(-10) << endl;
cout << abs(-12.34) << endl;
}
// ----------------------------- abs

int abs(int x)
{
return(x < 0 ? -x : x);
}

// ----------------------------- abs

double abs(double x)
{
return(x < 0 ? -x : x);
}

Operador Ternário:
Sintaxe: condição ? comando1 : comando2;

Exemplo:

int maior(int x, int y)


{
return(x > y ? x : y);
}

Programa exemplo (16): O programa demonstra a sobrecarga de


funções através da função stradd.

// stradd.cpp

#include <iostream>
#include <string>

using namespace std;

// --------------------------------- Prototypes

void stradd(char *s, char *r);


void stradd(char *s, int i);
void stradd(char *s, double d);

// --------------------------------- Programa Principal

int main(void)
{
char str[80] = "";

stradd(str,"UCPel, ");
stradd(str,2006);
stradd(str," -> ");
stradd(str,123.45);
cout << str << endl;
}
// --------------------------------- stradd

void stradd(char *s, char *r)


{
strcat(s,r);
}

// --------------------------------- stradd

void stradd(char *s, int i)


{
char tmp[80];

sprintf(tmp,"%d",i);
strcat(s,tmp);
}

// --------------------------------- stradd

void stradd(char *s, double d)


{
char tmp[80];

sprintf(tmp,"%.2f",d);
strcat(s,tmp);
}

Programa exemplo (17): O programa demonstra a sobrecarga de


funções através da função Imprime.

// imprime.cpp

#include <iostream>

using namespace std;

// --------------------------------- Prototypes

void Imprime(char *s);


void Imprime(char s);
void Imprime(int s);
void Imprime(double s);

// --------------------------------- Programa Principal

int main(void)
{
Imprime("Sistema Operacional Linux");
Imprime('A');
Imprime(123);
Imprime(123.45);
}

// --------------------------------- Imprime
void Imprime(char *s)
{
cout << s << endl;
}

// --------------------------------- Imprime

void Imprime(char s)
{
cout << s << endl;
}

// --------------------------------- Imprime

void Imprime(int s)
{
cout << s << endl;
}

// --------------------------------- Imprime

void Imprime(double s)
{
cout << s << endl;
}

Sobrecarga de operadores (polimorfismo)

Outra forma de polimorfismo em C++ é a sobrecarga de


operadores. Alguns operadores podem ser sobrecarregados. Por
exemplo, em “iostream” os operadores << e >> são sobrecarregados
nos métodos cout e cin.

cout << “Digite uma palavra: ”;


cin >> palavra;

Valores default de parâmetros formais

Os parâmetros formais (também conhecidos por argumentos) nas


funções ou métodos em C++ podem assumir valores default (por falta),
ou seja, no caso da chamada de uma função suprimir um parâmetro.

Função com valor default depois da função “main”:

Programa exemplo (18): O programa demonstra o uso de valores


default na função Imprime_String.

// default.cpp

#include <iostream>
using namespace std;

// --------------------------------- Prototypes

void Imprime_String(char *s, int linha = 1); // valor default

// --------------------------------- Programa Principal

int main(void)
{
Imprime_String("Ubuntu 6.06", 3); // ... parâmetro linha foi inserido
Imprime_String("Ubuntu 6.06"); // … parâmetro linha foi suprimido
}

// --------------------------------- Imprime_String

void Imprime_String(char *s, int linha) // sem valor default


{
for (int i = 1;i <= linha;i++)
cout << endl;
cout << s << endl;
}

Função com valor default antes da função “main”:

Programa exemplo (19): O programa demonstra o uso de valores


default na função Imprime_String.

// default.cpp

#include <iostream>

using namespace std;

// --------------------------------- Imprime_String

void Imprime_String(char *s, int linha = 1) // valor default


{
for (int i = 1;i <= linha;i++)
cout << endl;
cout << s << endl;
}

// --------------------------------- Programa Principal

int main(void)
{
Imprime_String("Ubuntu 6.06", 3); // … parâmetro linha foi inserido
Imprime_String("Ubuntu 6.06"); // … parâmetro linha foi suprimido
}
Referências e parâmetros de referência

As referências são diferentes de ponteiros, pois elas ficam


vinculadas diretamente à localização de memória de uma expressão ou
variável.

Não é reservado espaço de memória para uma referência, ou seja,


uma referência não ocupa espaço de memória.

As referências servem como uma forma alternativa de passagem


de parâmetro por referência, ou seja, sem o uso de ponteiros.

Sintaxe: tipo &variável = expressão_inicialização; // ... expressão ou variável

Significado: O operador & significa “referência ao tipo”, ou seja, a


variável de referência fica vinculada à posição de memória da expressão
de inicialização.

Programa exemplo (20): O programa demonstra a utilização de


ponteiros em C++.

// pointer.cpp

#include <iostream>

using namespace std;

int main(void)
{
int n = 7;
int *p = &n;

cout << "n é igual " << n << endl;


cout << "n é igual " << *p << endl;
cout << "o endereço de n é igual " << &n << endl;
cout << "o endereço de n é igual " << p << endl;
cout << "o endereço de p é igual " << &p << endl;
}

Programa exemplo (21): O programa demonstra a utilização de


referências e parâmetros de referência em C++.

// reference.cpp

#include <iostream>

using namespace std;

int main(void)
{
int n = 7;
int &ref = n; // … “ref” é uma referência para uma posição de memória

cout << "n é igual " << n << endl; // ... n é igual a 7
cout << "n é igual " << ref << endl; // .. ref é igual a 7
ref++;
cout << "n é igual " << n << endl; // ... n é igual a 8
cout << "n é igual " << ref << endl; // ... ref é igual a 8
}

Programa exemplo (22): O programa demonstra o uso de referências


e parâmetros de referência como parâmetro de funções através da
função troca.

// troca.cpp

#include <iostream>

using namespace std;

// ------------------ Prototypes

void troca(int &x, int &y); // passagem de parâmetros com referências


void troca(int *x, int *y); // passagem de parâmetros com ponteiros

// ----------------------------------------------------- Programa Principal

int main(void)
{
int x = 3, y = 4;

cout << x << " - " << y << endl;


cout << x << " - " << y << endl;
troca(x,y); // chamada com referências
troca(&x,&y); // chamada com ponteiros
cout << x << " - " << y << endl;
}

// ------------------------------ troca

void troca(int &x, int &y) // chamada com referências


{
int t;

t = x;
x = y;
y = t;
}

// ------------------------------ troca

void troca(int *x, int *y) // chamada com ponteiros


{
int t;
t = *x;
*x = *y;
*y = t;
}

Especificador inline

O especificador inline é utilizado na definição do protótipo de uma


função (ou na definição de uma função) para especificar ao compilador
que a função deve ser expandida na linha da chamada da função e não
seja feita a chamada da função propriamente dita, ou seja, torna o
programa mais rápido, pois a chamada da função não utiliza a pilha de
retorno.

Programa exemplo (23): O programa demonstra a utilização do


especificador inline.
// inline.cpp

#include <iostream>

using namespace std;

// ------------------------------------------- Random

inline void Random(int n)


{
cout << rand() % n << endl;
}

// ----------------------------------------------------- Programa Principal

int main(void)
{
srand(time(NULL)); // inicializa o gerador de números aleatórios
Random(10); // gera um número aleatório entre 0 e 9
Random(100); // gera um número aleatório entre 0 e 99
Random(1000); // gera um número aleatório entre 0 e 999
}

Especificador const

O especificador const serve para definir uma constante tipada,


ou seja, o valor da entidade declarada como const não pode ser
alterada.

Programa exemplo (24): O programa demonstra a utilização do


especificador const.
// circulo.cpp
#include <iostream>
#include <math.h>

using namespace std;

int main(void)
{
const float pi = 3.1416;
float raio,area;

cout << "Raio: ";


cin >> raio;
area = pi * pow(raio,2); // power – função potência
cout << "Area do Círculo: " << area << endl;
}

Programa exemplo (25): O programa demonstra a utilização do


especificador const.
// const.cpp

#include <iostream>
#include <math.h>

using namespace std;

const int tam = 5;


const double pi = 4 * atan(1);
const char *nome = "\nBy Paulo Roberto Gomes Luzzardi, 2006\n";

int main(void)
{
int x[tam] = {1, 2, 3, 4, 5};

cout << pi;


cout << nome;
for (int i = 0;i < 5;i++)
cout << x[i] << ", ";
cout << endl;
}

Operador de resolução de escopo (qualificação de escopo)

O operador de resolução de escopo ( :: ) permite escrever


funções fora do escopo de uma classe (class) ou estrutura (struct), ou
ainda, referenciar uma variável global dentro de um bloco que possui
uma variável local com o mesmo nome da variável global.

Programa exemplo (26): O programa demonstra a utilização do


operador de qualificação de escopo (::).
// escopo.cpp

#include <iostream>
using namespace std;

int valor = 1;

int main(void)
{
int valor = 2;

cout << valor << endl; // aqui valor é local (2)


cout << ::valor << endl; // ::valor é global (1)
}

Especificador enum

O especificador enum permite ao programador criar tipos de dados


do tipo enumeração.

Sintaxe: enum nome_enumeração {lista_das_enumerações}


lista_de_variáveis;

Programa exemplo (27): O programa demonstra a utilização do


especificador enum.
// enum.cpp

#include <iostream>

using namespace std;

int main(void)
{
enum Dias {Seg, Ter, Qua, Qui, Sex, Sab, Dom};
Dias d;
int i;

do {
cout << "Dia da Semana [0..6] ou [9] Sair: ";
cin >> i;
d = Dias(i);
switch (d)
{
case Seg: cout << "Segunda-feira" << endl;
break;
case Ter: cout << "Terça-feira" << endl;
break;
case Qua: cout << "Quarta-feira" << endl;
break;
case Qui: cout << "Quinta-feira" << endl;
break;
case Sex: cout << "Sexta-feira" << endl;
break;
case Sab: cout << "Sábado" << endl;
break;
case Dom: cout << "Domingo" << endl;
break;
}
} while (i not_eq 9);
}

Programa exemplo (28): O programa demonstra a utilização do


especificador enum.
// enum2.cpp

#include <iostream>

using namespace std;

int main(void)
{
enum Dias {Seg, Ter, Qua, Qui, Sex, Sab, Dom};
const char *nome[] = {"Segunda", "Terça", "Quarta", "Quinta", "Sexta", "Sábado",
"Domingo"};

for (int i = 0;i <= 6;i++)


cout << Dias(i) << " -> " << nome[Dias(i)] << endl;
}

Saída do programa:

0 -> Segunda
1 -> Terça
2 -> Quarta
3 -> Quinta
4 -> Sexta
5 -> Sábado
6 -> Domingo

Operadores new e delete (alocar e liberar memória)

Os operadores new e delete permitem ao programador alocar


(new) e liberar (delete) memória dinamicamente (alocação dinâmica, ou
seja, alocação em tempo de execução do programa) na área de heap
(local da memória RAM utilizada para o armazenamento de estruturas de
dados de tamanho e existência não determinada). Eles substituem as
funções malloc, calloc e free da linguagem C padrão.

Sintaxe (new): tipo_base *nome_ponteiro = new tipo_base;


tipo_base *nome_ponteiro = new (tipo_base);
tipo_base *nome_ponteiro = new
tipo_base[número_de_elementos];

Exemplos: float *p = new float;


float *q = new (float);
float *r = new float[7];
Sintaxe (delete): delete nome_ponteiro;

Exemplo: delete p;
ou
delete [] p; // quando é um vetor

Programa exemplo (29): O programa demonstra a utilização dos


operadores new e delete.

// new.cpp

#include <iostream>

using namespace std;

int main(void)
{
int *x = new int;

*x = 100;
cout << *x << endl; // … 100 (conteúdo do ponteiro)
cout << x << endl; // … 0x8fbe0dec (endereço do ponteiro)
delete x;
}

Programa exemplo (30): Programa demonstra a utilização dos


operadores new e delete.

// new2.cpp

#include <iostream>

using namespace std;

const int tam = 10;

int main(void)
{
int *x = new int[tam];

for (int i = 0;i < tam;i++)


x[i] = i; // … x recebe 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
for (int j = 0;j < tam;j++)
cout << &x[j] << " -> " << x[j] << endl;
delete [] x;
}

Resultado do programa:

0x8fc10db2 -> 0
0x8fc10db4 -> 1
0x8fc10db6 -> 2
0x8fc10db8 -> 3
0x8fc10dba -> 4
0x8fc10dbc -> 5
0x8fc10dbe -> 6
0x8fc10dc0 -> 7
0x8fc10dc2 -> 8
0x8fc10dc4 -> 9

Programa exemplo (31): O programa demonstra a utilização dos


operadores new e delete.
// new3.cpp

#include <iostream>

using namespace std;

const int tam = 10;

int main(void)
{
float *x = new float[tam];

for (int i = 0;i < tam;i++)


x[i] = (float) i / 2;
for (int j = 0;j < tam;j++)
cout << &x[j] << " -> " << x[j] << endl;
delete [] x;
}

Resultado do programa:

0x8f78124e -> 0
0x8f781252 -> 0.5
0x8f781256 -> 1
0x8f78125a -> 1.5
0x8f78125e -> 2
0x8f781262 -> 2.5
0x8f781266 -> 3
0x8f78126a -> 3.5
0x8f78126e -> 4
0x8f781272 -> 4.5

1.6 Herança simples

A herança simples permite que uma classe incorpore os


atributos e métodos de outra classe, ou seja, permite a construção de
hierarquias de classes.

O primeiro passo envolve a definição de uma classe base que


define as características comuns a todos os objetos derivados desta
classe. As classes oriundas da classe base são chamadas classes
derivadas.

Uma classe derivada herda todas as características da classe base


e pode ter novas características adicionadas a ela. Uma classe derivada
segue a seguinte diretriz em relação a classe base:

classe_derivada é um(a) classe_base

Exemplo: um cardial é um pássaro // classe base: pássaro


// classe derivada: cardial

Especificadores de acesso

public (público)

Quem tem acesso à classe tem acesso também a qualquer


membro público.
É raro ter atributos públicos, mas é comum ter métodos públicos.
Qualquer método tem acesso.

private (privado)

Um membro privado não é acessível fora da classe, somente pelos


membros da classe.
A intenção é permitir que apenas quem escreve a classe possa
usar esse membro.

protected (protegido)

O membro protegido é acessível à classe e a suas sub-classes


(classes derivadas).
A intenção é dar acesso aos programadores que estenderão sua
classe.

Controle de acesso na definição de uma classe


derivada

Quando uma classe derivada é definida, ou seja, na definição de


herança simples, seus membros (atributos e métodos) são declarados
internamente e o acesso a estes pode ser público (public), privativo
(private) ou protegido (protected). O acesso a membros protegidos é
igual ao acesso a membros privativos, exceto para o acesso das classes
derivadas da classe.
A forma geral de especificar herança simples é:

class classe_derivada : especificador_de_acesso classe_base


{
// atributos

// métodos

};

Quando uma classe herda as características de outra classe, todos


os membros da classe base tornam-se membros da classe derivada. O
tipo de acesso da classe base dentro da classe derivada é determinado
pelo especificador de acesso. Qualquer que seja o especificador de
acesso, membros privativos da classe base continuam sendo
propriedade privada da classe base, e não podem ser acessados por
classes derivadas.

Quando o especificador de acesso é public, todos os membros


públicos da classe base tornam-se membros públicos da classe derivada,
e os membros protegidos da classe base tornam-se membros protegidos
da classe derivada. Esta é a diferença que existe entre membros
privativos e membros protegidos.

Quando o especificador de acesso é private, todos os membros


públicos e protegidos da classe base tornam-se membros privativos da
classe derivada, ou seja, a classe derivada não pode transferir seus
privilégios de acesso a outras classes.

Quando o especificador de acesso é protected, todos os membros


públicos e protegidos da classe base tornam-se membros protegidos da
classe derivada.

Programa exemplo (32): O objetivo do programa é demonstrar a


utilização de herança simples (atributos da classe base são privados).

// heranca1.cpp

#include <iostream>

using namespace std;


class Base
{
int x, y; // atributos privados, somente a classe base pode acessa-los

public:
void Seta(int a, int b)
{
x = a;
y = b;
cout << "x = " << x << endl;
cout << "y = " << y << endl;
}
int Soma(void)
{
cout << "Soma (x+y): " << x+y << endl;
return(x+y);
}
};

class Derivada : public Base


{
int z;

public:
Derivada(int x)
{
z = x;
cout << "z = " << z << endl;
}
int Somador(int soma)
{
return(soma+z); // não é possível acessar x e y pois são privados a classe base
}
};

int main(void)
{
Derivada objeto(3); // construtor parametrizado
int resp;

objeto.Seta(1, 2);
resp = objeto.Soma();
cout << "Somador (x+y+z): " << objeto.Somador(resp) << endl;
}

Resultado do Programa:

z=3
x=1
y=2
Soma (x+y): 3
Somador (x+y+z): 6

Responda: Porque o atributo z é mostrado primeiro?


Tipos de acessos (resumo)

public (público): Todos os atributos da classe base são públicos na


classe derivada.
private (privado): Os atributos só podem ser acessados pelos
métodos que fazem parte da classe.
protected (protegido): Os atributos podem ser acessados pelos
métodos de classes derivadas.

Programa exemplo (33): O objetivo do programa é demonstrar a


utilização de herança simples (atributos da classe base são protegidos).

// heranca2.cpp

#include <iostream>

using namespace std;

class Base
{
protected:
int x, y; // atributos protegidos, ou seja, podem ser acessados na classe derivada

public:
void Seta(int a, int b)
{
x = a;
y = b;
cout << "x = " << x << endl;
cout << "y = " << y << endl;
}

void Soma(void)
{
cout << "Soma (x+y): " << x+y << endl;
}
};

class Derivada : public Base


{
int z;

public:
Derivada(int x)
{
z = x;
cout << "z = " << z << endl;
}

int Somador(void)
{
return(x+y+z);
}
};

int main(void)
{
Derivada objeto(3); // construtor parametrizado

objeto.Seta(1, 2);
objeto.Soma();
cout << "Somador (x+y+z): " << objeto.Somador() << endl;
}

Resultado do Programa:

z=3
x=1
y=2
Soma (x+y): 3
Somador (x+y+z): 6

1.7 Construtores e destrutores

Construtor é um método especial que tem o mesmo nome da


classe. Quando o objeto é criado, ou seja, é declarado, o construtor é
executado. Os objetos podem ser globais ou locais.

Destrutor é outro método especial que possui o nome da classe


precedido por um ~ (til). Quando o programa termina (objeto global) ou
quando um método termina (objeto local) o objeto é destruído. O
destrutor é muito útil quando o objeto é alocado dinamicamente.

Programa exemplo (34): O programa demonstra a criação e


manipulação de uma lista linear.

// linear.cpp (Lista_Linear)

#include <iostream>
#include <string>
#include <cctype>

using namespace std;

const int tam = 5;

typedef int TDADOS;

// -------------------------------------- Definição da Classe Lista

class Lista
{
TDADOS lista[tam]; // dados privados (private)
int n;

public:
Lista(void); // construtor (não tem tipo de retorno)
~Lista(void); // destrutor (não tem tipo de retorno)
void Inclui_Lista(TDADOS dado);
TDADOS Exclui_Lista(void);
TDADOS Consulta_Lista(void);
void Exibe_Lista(void);
}; // obrigatório ponto-e-vírgula

// -------------------------------------- Construtor

Lista :: Lista(void)
{
n = 0;
}

// -------------------------------------- Destrutor

Lista :: ~Lista(void)
{
n = 0;
}

// -------------------------------------- Inclui_Lista

void Lista :: Inclui_Lista(TDADOS dado)


{
if (n == tam)
{
cout << "Erro: Lista Cheia" << endl;
return;
}
lista[n] = dado;
n++;
}

// -------------------------------------- Exclui_Lista

TDADOS Lista :: Exclui_Lista(void)


{
if (n == 0)
{
cout << "Erro: Lista Vazia" << endl;
return(0);
}
n--;
return(lista[n+1]);
}

// -------------------------------------- Consulta_Lista

TDADOS Lista :: Consulta_Lista(void)


{
if (n == 0)
{
cout << "Erro: Lista Vazia" << endl;
return(0);
}
return(lista[n-1]);
}

// -------------------------------------- Exibe_Lista

void Lista :: Exibe_Lista(void)


{
cout << "Lista: ";
if (n == 0)
{
cout << "VAZIA" << endl;
return;
}
for (int i = 0;i < n;i++)
cout << lista[i] << " ";
cout << endl;
return;
}

// -------------------------------------- Programa Principal

int main(void)
{
Lista lista;
char tecla;
TDADOS valor;

do {
lista.Exibe_Lista();
cout << "[I]nclui, [E]xclui, [C]onsulta ou [F]im: ";
do {
tecla = toupper(cin.get());
} while (not strchr("IECF", tecla));
switch (tecla)
{
case 'I': cout << "Valor: ";
cin >> valor;
lista.Inclui_Lista(valor);
break;
case 'E': valor = lista.Exclui_Lista();
if (valor not_eq 0)
cout << "Valor Excluido da Lista: " << valor << endl;
break;
case 'C': valor = lista.Consulta_Lista();
if (valor not_eq 0)
cout << "Valor Consultado: " << valor << endl;
break;
}
} while (tecla not_eq 'F');
}
Programa exemplo (35): O programa demonstra a criação e
manipulação de uma Lista Simplesmente Encadeada.

// Lista Encadeada

#include <iostream>
#include <string>
#include <cctype>

using namespace std;

// ----------------------------------------- Definições

#define SUCESSO 0
#define FALTA_DE_MEMORIA 1
#define LISTA_VAZIA 2

typedef int TDADOS;

typedef struct nodo {


TDADOS dado;
struct nodo *elo;
} TNODO;

typedef struct {
TNODO *primeiro;
} TLISTA;

class Lista
{
TLISTA l;

public:
Lista(void); // construtor
~Lista(void); // destrutor
int Inclui_Lista(TDADOS dado);
int Exclui_Lista(void);
int Consulta_Lista(TDADOS *dado);
void Imprime_Erro(int erro);
void Exibe_Primeiro(void);
void Exibe_Lista(void);
};

// ------------------------------- Construtor

Lista :: Lista(void)
{
l.primeiro = NULL;
}

// ----------------------------------------- Destrutor

Lista :: ~Lista(void)
{
TNODO *p,*q;
if (l.primeiro not_eq NULL)
{
p = l.primeiro;
while (p not_eq NULL)
{
q = p->elo;
delete(p);
p = q;
}
}
l.primeiro = NULL;
}

// ------------------------------- Inclui_Lista

int Lista :: Inclui_Lista(TDADOS dado)


{
TNODO *p;

p = new TNODO; // em C seria p = (TNODO *) malloc(sizeof(TNODO));


if (p == NULL)
return(FALTA_DE_MEMORIA);
else
{
p->dado = dado;
if (l.primeiro == NULL)
{
l.primeiro = p;
p->elo = NULL;
}
else
{
p->elo = l.primeiro;
l.primeiro = p;
}
return(SUCESSO);
}
}

// ------------------------------- Exclui_Lista

int Lista :: Exclui_Lista(void)


{
TNODO *p;

if (l.primeiro == NULL)
return(LISTA_VAZIA);
else
{
p = l.primeiro;
l.primeiro = p->elo;
delete(p); // seria free(p);
return(SUCESSO);
}
}

// ------------------------------- Consulta_Lista

int Lista :: Consulta_Lista(TDADOS *dado)


{
TNODO *p;

if (l.primeiro == NULL)
return(LISTA_VAZIA);
else
{
p = l.primeiro;
*dado = p->dado;
return(SUCESSO);
}
}

// ------------------------------- Imprime_Erro

void Lista :: Imprime_Erro(int erro)


{
switch (erro)
{
case FALTA_DE_MEMORIA: cout << "ERRO: FALTA DE MEMORIA" << endl;
break;
case LISTA_VAZIA: cout << "ERRO: LISTA VAZIA” << endl;
break;
}
}

// ----------------------------------------- Exibe_Primeiro

void Lista :: Exibe_Primeiro(void)


{
if (l.primeiro not_eq NULL)
cout << "Primeiro: | " << l.primeiro;
else
cout << "Primeiro: | NULL |";
}

// ----------------------------------------- Exibe_Lista

void Lista :: Exibe_Lista(void)


{
TNODO *p;

cout << endl << "Lista Encadeada: ";


if (l.primeiro == NULL)
cout << "LISTA VAZIA";
else
{
p = l.primeiro;
while (p not_eq NULL)
{
cout << " | " << p->dado;
p = p->elo;
}
}
}

// ------------------------------- Programa Principal

int main(void)
{
Lista lista;
TDADOS valor;
int erro;
char tecla;

do {
lista.Exibe_Primeiro();
lista.Exibe_Lista();
cout << "\n[I]nclui, [E]xclui, [C]onsulta ou [F]im: ";
do {
tecla = toupper(cin.get());
} while (not strchr("IECF",tecla));
switch (tecla)
{
case 'I': cout << "Valor: ";
cin >> valor;
erro = lista.Inclui_Lista(valor);
break;
case 'E': erro = lista.Exclui_Lista();
if (not erro)
cout << "Ok, Elemento Excluido";
break;
case 'C': erro = lista.Consulta_Lista(&valor);
if (not erro)
cout << "Valor Consultado: " << valor << endl;
break;
}
if (erro and tecla not_eq 'F') // and é igual a &&
lista.Imprime_Erro(erro);
} while (tecla not_eq 'F');
}

Programa exemplo (36): O programa demonstra a criação e


manipulação uma Lista Duplamente Encadeada.

// Dupla.cpp

#include <iostream>
#include <string>
#include <cctype>

using namespace std;

#define SUCESSO 0
#define FALTA_DE_MEMORIA 1
#define LISTA_VAZIA 2
typedef int TDados;

typedef struct Nodo {


struct Nodo *anterior;
TDados dado;
struct Nodo *posterior;
} TNodo;

typedef struct {
TNodo *primeiro;
int n;
TNodo *ultimo;
} TDupla;

class Dupla
{
TDupla d;

public:
Dupla(void);
~Dupla(void);
int Insere_Direita(TDados dado);
int Insere_Esquerda(TDados dado);
void Imprime_Lista_Esquerda(void);
void Imprime_Lista_Direita(void);
void Imprime_Erro(int erro);
void Exibe_Descritor(void);
};

// ------------------------------- Construtor

Dupla :: Dupla(void)
{
d.primeiro = NULL;
d.n = 0;
d.ultimo = NULL;
}

// ------------------------------- Destrutor

Dupla :: ~Dupla(void)
{
TNodo *p,*q;

p = d.primeiro;
while (p not_eq NULL)
{
q = p;
delete(p);
p = q->posterior;
}
}

// ------------------------------- Insere_Direita
int Dupla :: Insere_Direita (TDados dado)
{
TNodo *p,*q;

p = new TNodo;
if (p == NULL)
return(FALTA_DE_MEMORIA);
else
{
p->dado = dado;
p->posterior = NULL;
if (d.n == 0)
{
d.primeiro = p;
d.n = 1;
d.ultimo = p;
p->anterior = NULL;
}
else
{
q = d.ultimo;
d.ultimo = p;
q->posterior = p;
p->anterior = q;
(d.n)++;
}
return(SUCESSO);
}
}

// ------------------------------- Insere_Esquerda

int Dupla :: Insere_Esquerda(TDados dado)


{
TNodo *p,*q;

p = new TNodo;
if (p == NULL)
return(FALTA_DE_MEMORIA);
else

{
p->dado = dado;
p->anterior = NULL;
if (d.n == 0)
{
d.primeiro = p;
d.n = 1;
d.ultimo = p;
p->posterior = NULL;
}
else
{
q = d.primeiro;
d.primeiro = p;
q->anterior = p;
p->posterior = q;
(d.n)++;
}
return(SUCESSO);
}
}

// ------------------------------- Imprime_Lista_Direita

void Dupla :: Imprime_Lista_Direita(void)


{
TNodo *p;

cout << "\nLista pela Direita: ";


p = d.ultimo;
while (p not_eq NULL)
{
cout << p->dado << " | ";
p = p->anterior;
}
}

// ------------------------------- Imprime_Lista_Esquerda

void Dupla::Imprime_Lista_Esquerda(void)
{
TNodo *p;

cout << "\nLista pela Esquerda: ";


p = d.primeiro;
while (p not_eq NULL)
{
cout << p->dado << " | ";
p = p->posterior;
}
}

// ------------------------------- Imprime_Erro

void Dupla::Imprime_Erro(int erro)


{
switch (erro)
{
case FALTA_DE_MEMORIA: cout << "ERRO: Falta de Memória" << endl;
break;
case LISTA_VAZIA: cout << "ERRO: Lista Vazia" << endl;
break;
}
}

// ------------------------------- Exibe_Descritor

void Dupla :: Exibe_Descritor(void)


{
printf("Descritor: | %p | %d | %p |", d.primeiro, d.n, d.ultimo);
}
// ------------------------------- Programa Principal

int main(void)
{
Dupla dupla;
TDados valor;
int erro;
char tecla;

do {
dupla.Exibe_Descritor();
dupla.Imprime_Lista_Esquerda();
dupla.Imprime_Lista_Direita();
cout << "\nValor: ";
cin >> valor;
if (valor not_eq 0)
{
cout << "[E]squerda ou [D]ireita: ";
do {
tecla = toupper(cin.get());
} while (not strchr("ED",tecla));
switch (tecla)
{
case 'E': erro = dupla.Insere_Esquerda(valor);
break;
case 'D': erro = dupla.Insere_Direita(valor);
break;
}
if (erro)
dupla.Imprime_Erro(erro);
}
} while (valor not_eq 0);
}

1.8 Palavras reservadas em C++

As palavras reservadas em C++ são: asm, catch, class, delete,


private, protected, public, template, friend, inline, new, operator,
overload, this, throw, try e virtual.

1.9 Forma geral de um programa em C++

A forma geral de um programa em C++ é:

#includes

declarações de classes base;


declarações de classes derivadas;

protótipos das funções não-membro;


int main(void)
{
}

1.10 Classe “string”

C++ possui uma classe chamada string que permite ao


programador fazer algumas operações não possíveis na linguagem C
padrão, como por exemplo, atribuir uma constante string a uma variável
string (veja exemplo abaixo) dentre outras coisas. Os próximos exemplos
demonstram alguns métodos da classe string.

Programa exemplo (37): O programa demonstra a utilização da classe


“string”.

// string1.cpp

#include <iostream>
#include <string>

using namespace std;

int main(void)
{
string s = "Couve", r = "-flor";
string t;

t = s + r; // C padrão não permite atribuição e soma de strings


cout << t << endl;
}

Programa exemplo (38): O programa demonstra a utilização da classe


“string”.

// string2.cpp

#include <iostream.h>
#include <string>

using std::string; // necessário por causa do arquivo de include <string.h> do C padrão

int main(void)
{
string s = "Couve", r = "-flor";
string t;

t = s + r;
cout << t << endl;
}

Programa exemplo (39): O programa demonstra a utilização da classe


“string”.

// string3.cpp

#include <iostream>
#include <string>

using namespace std;

int main(void)
{
string s = "C++ for Linux";

int n = s.length();
cout << "String: " << s << endl;
cout << "Total de Caracteres: " << n << endl;
}

Programa exemplo (40): O programa demonstra a utilização da classe


“string”.

// string4.cpp

#include <iostream>
#include <string>

using namespace std;

int main(void)
{
string s; // pode-se declarar uma string sem inicialização

cout << "Qual o seu nome? ";


getline(cin,s); // método para leitura de uma string
if (not s.empty()) // método verifica string vazia if (s != “”)
{
int n = s.size(); // método retorna o número de caracteres da string
cout << "String: " << s << endl;
cout << "Total de Caracteres: " << n << endl;
}
else
cout << "Erro: String Vazia" << endl;
}

Programa exemplo (41): O programa demonstra a utilização da classe


“string”.

// string5.cpp

#include <iostream>
#include <string>

using namespace std;


int main(void)
{
string s = "universidade", r;

r = s.substr(7, 5); // 7 - posição inicial | 5 - número de caracteres que serão copiados


cout << "String resultante: " << r << endl; // idade
s.erase(0, 7); // 0 - posição inicial | 7 - número de caracteres que serão apagados
cout << "String s: " << s << endl; // idade
}

Programa exemplo (42): O programa demonstra a utilização da classe


“string”.

// string6.cpp

#include <iostream>
#include <string>

using namespace std;

int main(void)
{
string s("universidade");

s.replace(7, 5, "os"); // 7 - posição inicial | 5 - número de caracteres que serão


trocados
cout << "String modificada: " << s << endl; // universos
}

Programa exemplo (43): O programa demonstra a utilização da classe


“string”.

// string7.cpp

#include <iostream>
#include <string>

using namespace std;

int main(void)
{
string s("Couve"), r("-flor"), t; // t é igual a t(“”)

t = s + r;
cout << t << endl;
}

Programa exemplo (44): O programa demonstra o cálculo do dia


juliano, ou seja, o usuário informa via teclado dia, mês e ano e o
programa informa o dia da semana (segunda, terça, quarta, etc)
correspondente a esta data.
Observação: Sem a utilização de objetos.

// dia.cpp

#include <iostream>

using namespace std;

// ---------------------------- Programa Principal

int main(void)
{
int dia, mes, ano;
int a, b, c;
long int d, e, dj;
char tecla;
double resp;

do {
do {
cout << "Dia [1..31]: ";
cin >> dia;
} while (dia < 1 or dia > 31); // or é igual a ||
do {
cout << "Mes [1..12]: ";
cin >> mes;
} while (mes < 1 or mes > 12);
do {
cout << "Ano [1900..2999]: ";
cin >> ano;
} while (ano < 1900 or ano > 2999);
cout << "Data: " << dia << " de ";
switch (mes)
{
case 1: cout << "Janeiro";
break;
case 2: cout << "Fevereiro";
break;
case 3: cout << "Março";
break;
case 4: cout << "Abril";
break;
case 5: cout << "Maio";
break;
case 6: cout << "Junho";
break;
case 7: cout << "Julho";
break;
case 8: cout << "Agosto";
break;
case 9: cout << "Setembro";
break;
case 10: cout << "Outubro";
break;
case 11: cout << "Novembro";
break;
case 12: cout << "Dezembro";
break;
}
cout << " de " << ano;
if (mes < 3)
{
ano--;
mes += 12;
}
a = ano / 100;
b = a / 4;
c = 2 - a + b;
resp = 365.25 * (ano + 4716);
d = (long int) resp;
resp = 30.6001 * (mes + 1);
e = (long int) resp;
dj = d + e + dia + c - 1524;
int resto = dj % 7;
cout << "\nDia da Semana: ";
switch (resto)
{
case 0: cout << "SEGUNDA-FEIRA";
break;
case 1: cout << "TERÇA-FEIRA";
break;
case 2: cout << "QUARTA-FEIRA";
break;
case 3: cout << "QUINTA-FEIRA";
break;
case 4: cout << "SEXTA-FEIRA";
break;
case 5: cout << "SÁBADO";
break;
case 6: cout << "DOMINGO";
break;
}
do {
cout << "\nNovo Cálculo [S/n]?";
cin >> tecla;
} while (not strchr("SsNn", tecla));
} while (strchr("Ss", tecla));
}

Programa exemplo (45): O programa demonstra o cálculo do dia


juliano, ou seja, o usuário informa via teclado dia, mês e ano e o
programa informa o dia da semana (segunda, terça, quarta, etc)
correspondente a data informada.

Observação: Com a utilização de um objeto “Data”.

// juliano.cpp
// --------------------------- Prototypes

#include <iostream>

using namespace std;

// --------------------------- Classe: Data

class Data
{
int dia, mes, ano;

public:
void Le_Atributos(void);
void Exibe_Data_Extenso(void);
int Calcula_Dia_Juliano(void);
void Exibe_Dia_Semana(int resto);
};

// --------------------------- Programa Principal

int main(void)
{
Data data; // definição do objeto “data”
char tecla;

do {
data.Le_Atributos();
data.Exibe_Data_Extenso();
int resto = data.Calcula_Dia_Juliano();
data.Exibe_Dia_Semana(resto);
cout << "\nNovo Cálculo [S/n]?";
do {
cin >> tecla;
} while (not strchr("SsNn", tecla));
} while (strchr("Ss", tecla));
}

// -------------------------------- Método: Le_Atributos

void Data :: Le_Atributos(void)


{
do {
cout << "Dia [1..31]: ";
cin >> dia;
} while (dia < 1 or dia > 31);
do {
cout << "Mes [1..12]: ";
cin >> mes;
} while (mes < 1 or mes > 12);
do {
cout << "Ano [1900..2999]: ";
cin >> ano;
} while (ano < 1900 or ano > 2999);
}
// -------------------------------- Método: Calcula_Dia_Juliano

int Data :: Calcula_Dia_Juliano(void)


{
int a, b, c;
long int d, e, dj;
int dd = dia, mm = mes, aa = ano;
double resp;

if (mm < 3)
{
aa--;
mm += 12;
}
a = aa / 100;
b = a / 4;
c = 2 - a + b;
resp = 365.25 * (aa + 4716);
d = (long int) resp;
resp = 30.6001 * (mm + 1);
e = (long int) resp;
dj = d + e + dd + c - 1524;
int resto = dj % 7;
return(resto);
}

// -------------------------------- Método: Exibe_Dia_Semana

void Data :: Exibe_Dia_Semana(int resto)


{
cout << "\nDia da Semana: ";
switch (resto)
{
case 0: cout << "SEGUNDA-FEIRA";
break;
case 1: cout << "TERÇA-FEIRA";
break;
case 2: cout << "QUARTA-FEIRA";
break;
case 3: cout << "QUINTA-FEIRA";
break;
case 4: cout << "SEXTA-FEIRA";
break;
case 5: cout << "SÁBADO";
break;
case 6: cout << "DOMINGO";
break;
}
}

// -------------------------------- Método: Exibe_Data_Extenso

void Data :: Exibe_Data_Extenso(void)


{
cout << "Data: " << dia << " de ";
switch (mes)
{
case 1: cout << "Janeiro";
break;
case 2: cout << "Fevereiro";
break;
case 3: cout << "Março";
break;
case 4: cout << "Abril";
break;
case 5: cout << "Maio";
break;
case 6: cout << "Junho";
break;
case 7: cout << "Julho";
break;
case 8: cout << "Agosto";
break;
case 9: cout << "Setembro";
break;
case 10: cout << "Outubro";
break;
case 11: cout << "Novembro";
break;
case 12: cout << "Dezembro";
break;
}
cout << " de " << ano;
}

Método cin.getline (leitura de uma string)

O método “cin.getline” permite a entrada de uma string qualquer


via teclado.

Protótipo: void cin.getline (char *s, int n);

Onde: “s” é a string declarada como char *s ou char s[]


“n” o número de caracteres

Programa exemplo (46): O programa demonstra a entrada de uma


string via teclado através do método cin.getline.

// string.cpp

#include <iostream>

using namespace std;

int main(void)
{
char s[81];
cout << "Digite seu nome: ";
cin.getline(s,80);
cout << s << "\nTotal de caracteres: " << strlen(s) << endl;
cout << "Tecle <ENTER> para encerrar";
cin.get();
}

Programa exemplo (47): O programa permite a entrada de strings


(nomes, máximo 50) até que o usuário digite apenas enter e após
ordena e imprime na tela os nomes em ordem alfabética.

// sort1.cpp

#include <iostream>

using namespace std;

const int tam= 50;

int main(void)
{
char nome[tam][41], temp[41];
bool trocou;
int n = -1;

do {
n++;
cout << "Nome: ";
cin.getline(nome[n],40);
} while (strcmp(nome[n],"") not_eq 0 and n < tam); // and é igual a &&
if (strcmp(nome[n],"") == 0)
n--;
int j = n;
cout << "Nomes digitados\n";
for (int i = 0;i <= n;i++)
cout << nome[i] << endl;
do {
trocou = false;
for (int i = 0;i < j;i++)
if (strcmp(nome[i],nome[i+1]) > 0)
{
strcpy(temp,nome[i]);
strcpy(nome[i],nome[i+1]);
strcpy(nome[i+1],temp);
trocou = true;
}
j--;
} while (trocou);
cout << "Nomes Ordenados\n";
for (int i = 0;i <= n;i++)
cout << nome[i] << endl;
}
Programa exemplo (48): O programa permite a entrada de strings
(nomes, máximo 50) até que o usuário digite apenas enter e após
ordena e imprime os nomes em ordem alfabética. Este programa possui
uma função que faz a troca de duas strings.

// sort2.cpp

#include <iostream>

using namespace std;

void troca(char *s, char *r)


{
int n, ns, nr;

ns = strlen(s);
nr = strlen(r);
ns > nr ? n = ns : n = nr;
char *t = (char *) new char * [n+1];
strcpy(t,s);
strcpy(s,r);
strcpy(r,t);
delete t;
}

const int tam = 50;

int main(void)
{
char nome[tam][41], temp[41];
bool trocou;
int n = -1;

do {
n++;
cout << "Nome: ";
cin.getline(nome[n],40);
} while (strcmp(nome[n],"") not_eq 0 and n < tam);
if (strcmp(nome[n],"") == 0)
n--;
int j = n;
cout << "Nomes digitados\n";
for (int i = 0;i <= n;i++)
cout << nome[i] << endl;
do {
trocou = false;
for (int i = 0;i < j;i++)
if (strcmp(nome[i],nome[i+1]) > 0)
{
troca(nome[i],nome[i+1]);
trocou = true;
}
j--;
} while (trocou);
cout << "Nomes Ordenados\n";
for (int i = 0;i <= n;i++)
cout << nome[i] << endl;
}

2. Classes e Objetos
2.1 Classes

A declaração de uma classe (class) define um novo tipo de dado


que mistura código (funções ou métodos) e dados (variáveis ou
atributos) e é utilizado para declarar objetos.

Como declarar uma classe:

class nome_da_classe
{
// atributos e métodos privadas;
// se for suprimido o especificador de acesso ele é por default: private

especificador_de_acesso:
//atributos e métodos;
.
.
.
especificador_de_acesso:
// atributos e métodos;

} lista_de_objetos;

Observações:

(1) A lista_de_objetos é opcional, ou seja, os objetos desta classe


podem ser declarados a qualquer momento, conforme exemplo abaixo:

nome_da_classe lista_de_objetos;

2)   O especificador de acesso padrão é private, ou seja, se não for


definido nenhum especificador, por default atributos e métodos são
private.

Programa exemplo (49): O programa exibe um “boneco” na tela. O


programa possui uma classe chamada Boneco.

// boneco.cpp

#include <iostream>
using namespace std;

// ---------------------------------------------- Classe: Boneco

class Boneco
{
private:
int n;

private:
void Cabeca(void);
void Corpo(void);
void Braco_Esquerdo(void);
void Braco_Direito(void);
void Perna_Esquerda(void);
void Perna_Direita(void);

public:
void Seta_Atributo(int x)
{
n = x;
}
void Incrementa_Atributo(void)
{
n++;
}
void Desenha_Boneco(void);
};

// ---------------------------------------------- Programa Principal

int main(void)
{
Boneco boneco;

boneco.Seta_Atributo(1);
for (int i = 1;i <= 6;i++)
{
boneco.Desenha_Boneco();
boneco.Incrementa_Atributo();
cin.get();
}
}

Programa exemplo (50): O programa faz o “boneco” andar na tela. O


programa possui uma classe chamada Boneco.

// anda.cpp

#include <iostream>
using namespace std;

// ---------------------------------------------- Classe: Boneco

class Boneco
{
private:
int c;

public:
void Seta_Atributo(int col) { c = col; }
void Incrementa_Atributo(void);
void Desenha_Boneco(void);
void Anda_Boneco(void);
};

// ---------------------------------------------- Programa Principal

int main(void)
{
Boneco boneco;

boneco.Seta_Atributo(10);
boneco.Desenha_Boneco();
for (int i = 1;i <= 70;i++)
{
boneco.Anda_Boneco();
boneco.Incrementa_Atributo();
system("clear");
}
}

// ---------------------------------------------- Boneco: Desenha_Boneco

void Boneco :: Desenha_Boneco(void)


{
cout << " O" << endl;
cout << "/|\\" << endl;
cout << " |" << endl;
cout << "/ \\" << endl;
}

// ---------------------------------------------- Boneco: Anda_Boneco

void Boneco :: Anda_Boneco(void)


{
char s[256] = "";
int i = 0;

for (int col = 1;col <= c;col++)


{
s[i++] = ' ';
s[i] = (char) NULL;
}
cout << s << " O" << endl;
cout << s << "/|\\" << endl;
cout << s << " |" << endl;
cout << s << "/ \\" << endl;
}

// ---------------------------------------------- Boneco: Incrementa_Atributo

void Boneco :: Incrementa_Atributo(void)


{
c++;
}

Especificadores de acesso:

public (público): Todos os elementos da classe base (atributos ou


métodos) são públicos na classe derivada, ou seja, podem ser
acessados por qualquer outro método ou função (função main, por
exemplo).

private (privado): Os elementos (atributos e métodos) só podem


ser acessados pelos métodos (funções) que fazem parte da classe.

protected (protegido): É necessário apenas quando utiliza-se


herança, ou seja, é necessário para que os métodos de uma classe
derivada possa acessar os atributos e métodos de uma classe
base.

Observação: A classe base é qualquer classe definida em C++. Classe


derivada herda todas as características (atributos e métodos públicos e
protegidos) da classe base. Apenas atributos e métodos privados não
são herdados pela classe derivada.

Os métodos declarados dentro de uma classe são chamados de


métodos membros e podem acessar qualquer atributo ou método da
classe, mesmo os privados a classe.

Os atributos declaradas dentro de uma classe são chamadas


atributos membros. Podem ser privados, públicos ou protegidos (quando
usados em herança).

Restrições na declaração de uma classe:

1) Nenhum atributo pode ser inicializado dentro da declaração da


classe;
2) Não pode-se referenciar um objeto de uma classe ainda não
declarada;
3)  Nenhum membro pode ser declarado como extern (tipo externo) ou
register (registrador).

Como acessar atributos públicos: os atributos públicos de uma


classe são acessados da mesma forma que os campos de uma estrutura,
ou seja, com ponto (.) ou seta (->), se o objeto for um ponteiro.

Programa exemplo (51): O programa possui atributos públicos que


são acessados pela função main. O programa pergunta o seu nome e
exibe na tela o número de caracteres do nome.

// public.cpp

#include <iostream>

using namespace std;

class Pessoa
{
public:
char nome[81];
int n;
};

int main(void)
{
Pessoa pessoa;

cout << "Qual o seu nome: ";


cin.getline(pessoa.nome,80);
pessoa.n = strlen(pessoa.nome);
cout << "Número de caracteres: " << pessoa.n << endl;
}

Programa exemplo (52): O programa possui atributos públicos que


são acessados pela função main. O programa pergunta o seu nome e
exibe na tela o número de caracteres deste nome utilizando alocação
dinâmica (ponteiros).

// public2.cpp

#include <iostream>

using namespace std;

class Pessoa
{
public:
char nome[81];
int n;
};

int main(void)
{
Pessoa *pessoa;

pessoa = new Pessoa;


cout << "Qual o seu nome: ";
cin.getline(pessoa->nome,80);
pessoa->n = strlen(pessoa->nome);
cout << "Número de caracteres: " << pessoa->n << endl;
}

2.2 Funções friend (amigas)

É possível acessar atributos e métodos privados (private) de uma


classe por funções não-membros da classe através da utilização de
funções amigas (friend).

Uma função amiga possui acesso a todos os atributos e métodos


privados (private) e protegidos (protected) de uma classe a qual ela é
amiga.

Como declarar uma função amiga:

friend tipo_retorno nome_método(lista_de_argumentos);

Programa exemplo (53): O programa mostra a utilização de uma


função amiga (friend).

// friend.cpp

#include <iostream>

using namespace std;

class Calc
{
float a, b;

public:
void Inicializa_Atributos(float x, float y)
{
a = x;
b = y;
}
friend float Div(Calc t); // observação: Div não é membro da classe Calc
};
int main(void)
{
Calc calc;

calc.Inicializa_Atributos(3.0,4.0);
cout << "Soma: " << Div(calc) << endl;
}

float Div(Calc t)
{
return(t.a / t.b); // pode acessar a e b pois é uma função amiga
}

Funções amigas (friend) podem ser utilizadas em três situações:

1) Podem ser úteis quando se sobrecarrega certos tipos de operadores;


2) Tornam a criação de certas funções de entrada e saída mais fáceis;
3) Podem ser utilizadas quando duas ou mais classes contém membros
que estão interligados, ou necessitam testar os atributos de ambas.

2.3 Funções inline

Funções inline são pequenas funções (ou métodos) que são


expandidas na chamada da função. Esta característica aumenta o
desempenho do programa (velocidade), pois não há chamada da função,
ou seja, não é utilizada a pilha de retorno da função e não são utilizados
os registradores para armazenar o estado do programa, ocupando
tempo e memória.

Programa exemplo (54): O programa mostra a utilização de uma


função inline.

// inline.cpp

#include <iostream>

using namespace std;

inline int maior(int x, int y)


{
return(x > y ? x : y);
}

inline int menor(int x, int y)


{
return(x < y ? x : y);
}
int main(void)
{
cout << "Maior: " << maior(5,6) << endl;
cout << "Menor: " << menor(5,6) << endl;
}

Programa exemplo (55): O programa mostra como o programa seria


compilado pelo compilador.

// inline2.cpp

#include <iostream>

using namespace std;

int main(void)
{
cout << "Maior: " << (5 > 6 ? 5 : 6) << endl;
cout << "Menor: " << (5 < 6 ? 5 : 6) << endl;
}

Restrições na utilização do inline:

1)  Não pode conter nenhuma variável estática (static int n = 0;);


2)  Não pode conter nenhum comando de repetição, switch ou goto;
3) Não pode ser recursiva;
4)  Declaração de vetores, matrizes e strings não são aceitas;
5)  Se a função é void não pode-se utilizar return.

2.4 Definindo funções inline dentro de uma classe

Pequenos métodos quando escritos dentro de uma classe são


considerados inline (não sendo necessário colocar o inline, pois o
método é automaticamente inline). Normalmente, o construtor é
pequeno e inserido dentro da classe.

2.5 Construtores parametrizados

Em C++ é permitido passar argumentos (parâmetros com valores


iniciais) para construtores de classes (objetos). Isto evita que existam
métodos específicos para inicializar atributos. Isto é necessário, pois
nenhum atributo de uma classe pode ser inicializado diretamente na
declaração de uma classe.

Programa exemplo (56): O programa possui uma classe: Boneco. A


classe possui um construtor parametrizado.
// boneco.cpp

#include <iostream>

using namespace std;

// ---------------------------------------------- Classe: Boneco

class Boneco
{
private:
int n;

private:
void Cabeca(void);
void Bracos(void);
void Corpo(void);
void Pernas(void);

public:
Boneco(int x) // construtor parametrizado
{
n = x;
}
void Desenha_Boneco(void);
};

// ---------------------------------------------- Programa Principal

int main(void)
{
Boneco boneco(1); // construtor parametrizado

boneco.Desenha_Boneco();
}

// ---------------------------------------------- Boneco: Cabeca

void Boneco :: Cabeca(void)


{
cout << " O" << endl;
}

// ---------------------------------------------- Boneco: Bracos

void Boneco :: Bracos(void)


{
cout << "/|\\" << endl;
}

// ---------------------------------------------- Boneco: Corpo


void Boneco :: Corpo(void)
{
cout << " |" << endl;
}

// ---------------------------------------------- Boneco: Pernas

void Boneco :: Pernas(void)


{
cout << "/ \\" << endl;
}

// ---------------------------------------------- Boneco: Desenha_Boneco

void Boneco :: Desenha_Boneco(void)


{
Cabeca();
Bracos();
Corpo();
Pernas();
}

Programa exemplo (57): O programa demonstra a utilização de uma


classe de objetos chamada “Arquivo”. O programa permite criar, abrir,
gravar, exibir, anexar e ordenar palavras em um arquivo binário de
palavras.

// Arquivo.cpp

#include <iostream>

using namespace std;

// ----------------------------------------------- Classe: Arquivo

class Arquivo
{
FILE *fp; // lista de atributos
char nome[81], palavra[31], tecla;
bool aberto; // tipo lógico (boolean)

void Erro(int erro); // métodos privados


long int Tamanho_Arquivo(void);

public: // métodos públicos


Arquivo(char *s);
~Arquivo(void);
void Cria_Arquivo(void);
void Abre_Arquivo(void);
void Grava_Palavras(void);
void Exibe_Palavras(void);
void Insere_Palavras(void);
void Consulta_Palavras(void);
void Ordena_Palavras(void);
};

// ----------------------------------------------- Programa Principal

int main(void)
{
char nome[81], tecla;

cout << "Nome do Arquivo de Palavras: ";


cin.getline(nome,80);
Arquivo arquivo(nome); // construtor parametrizado
do {
cout << "[1] - Cria o Arquivo" << endl;
cout << "[2] - Abre o Arquivo" << endl;
cout << "[3] - Grava primeiras Palavras" << endl;
cout << "[4] - Exibe todas Palavras" << endl;
cout << "[5] - Insere mais Palavras" << endl;
cout << "[6] - Consulta Palavras" << endl;
cout << "[7] - Ordena Palavras" << endl;
cout << "[9] - Fim" << endl;
do {
cout << "Qual a alternativa: ";
cin >> tecla;
} while (not strchr("12345679",tecla));
switch (tecla)
{
case '1': arquivo.Cria_Arquivo();
break;
case '2': arquivo.Abre_Arquivo();
break;
case '3': arquivo.Grava_Palavras();
break;
case '4': arquivo.Exibe_Palavras();
break;
case '5': arquivo.Insere_Palavras();
break;
case '6': arquivo.Consulta_Palavras();
break;
case '7': arquivo.Ordena_Palavras();
break;
}
} while (tecla not_eq '9');
}

// ----------------------------------------------- Construtor parametrizado

Arquivo :: Arquivo(char *s)


{
strcpy(nome,s);
aberto = false;
}

// ----------------------------------------------- Destrutor

Arquivo :: ~Arquivo(void)
{
if (aberto)
fclose(fp);
}

// ----------------------------------------------- Cria_Arquivo

void Arquivo :: Cria_Arquivo(void)


{
cout << "Arquivo: " << nome << endl;
fp = fopen(nome,"r+b");
if (fp not_eq NULL)
{
fclose(fp);
Erro(1);
}
else
{
cout << "Ok, Arquivo Criado" << endl;
fp = fopen(nome,"w+b");
if (fp == NULL)
Erro(2);
else
aberto = true;
}
}

// ----------------------------------------------- Abre_Arquivo

void Arquivo :: Abre_Arquivo(void)


{
cout << "Arquivo: " << nome << endl;
fp = fopen(nome,"r+b");
if (fp == NULL)
Erro(3);
cout << "Ok, Arquivo Aberto" << endl;
aberto = true;
}

// ----------------------------------------------- Erro

void Arquivo :: Erro(int erro)


{
switch (erro)
{
case 1: cout << "ERRO FATAL: Arquivo Existe" << endl;
break;
case 2: cout << "ERRO FATAL: Problema no Disco" << endl;
break;
case 3: cout << "ERRO FATAL: Arquivo Inexistente" << endl;
break;
}
exit(0);
}

// ----------------------------------------------- Tamanho_Arquivo

long int Arquivo :: Tamanho_Arquivo(void)


{
long int n = 0;

if (aberto)
{
rewind(fp);
fread(palavra,sizeof(palavra),1,fp);
while (not feof(fp))
{
n++;
fread(palavra,sizeof(palavra),1,fp);
}
}
return(n);
}

// ----------------------------------------------- Grava_Palavra

void Arquivo :: Grava_Palavras(void)


{
if (aberto)
{
rewind(fp);
do {
cout << "Palavra: ";
cin >> palavra;
fwrite(palavra,sizeof(palavra),1,fp);
do {
cout << "Continua [S/n]? ";
cin >> tecla;
} while (not strchr("SsNn",tecla));
} while (strchr("Ss",tecla));
}
else
cout << "ERRO: [1] Criar ou [2] Abrir um arquivo ... " << endl;
}

// ----------------------------------------------- Exibe_Palavras

void Arquivo :: Exibe_Palavras(void)


{
if (aberto)
{
rewind(fp);
fread(palavra,sizeof(palavra),1,fp);
while (not feof(fp))
{
cout << "Palavras: " << palavra << endl;
fread(palavra,sizeof(palavra),1,fp);
}
}
else
cout << "ERRO: [1] Criar ou [2] Abrir um Arquivo ... " << endl;
}

// ----------------------------------------------- Insere_Palavras

void Arquivo :: Insere_Palavras(void)


{
if (aberto)
{
fseek(fp,0,SEEK_END);
do {
cout << "Palavra: ";
cin >> palavra;
fwrite(palavra,sizeof(palavra),1,fp);
do {
cout << "Continua [S/n]? ";
cin >> tecla;
} while (not strchr("SsNn",tecla));
} while (strchr("Ss",tecla));
}
else
cout << "ERRO: [1] Criar ou [2] Abrir um arquivo ... " << endl;
}

// ----------------------------------------------- Consulta_Palavras

void Arquivo :: Consulta_Palavras(void)


{
long int n, posicao;
int pos;
char tecla;

if (aberto)
{
n = Tamanho_Arquivo();
do {
do {
cout << "Posicao [0.." << n << "]: ";
cin >> pos;
} while (pos < 0 or pos > n);
posicao = pos * sizeof(palavra);
fseek(fp,posicao,SEEK_SET);
fread(palavra,sizeof(palavra),1,fp);
cout << "PALAVRA: " << palavra << endl;
do {
cout << "Continua [S/n]? ";
cin >> tecla;
} while (not strchr("SsNn",tecla));
} while (strchr("Ss",tecla));
}
else
cout << "ERRO: [1] Criar ou [2] Abrir um arquivo ... " << endl;
}

// ----------------------------------------------- Ordena_Palavras

void Arquivo :: Ordena_Palavras(void)


{
long int n;
int i = 0,j;
char temp[31];

if (aberto)
{
n = Tamanho_Arquivo();
rewind(fp);
char vetor[n][31];
fread(&vetor[i],sizeof(vetor[i]),1,fp);
while (not feof(fp))
{
i++;
fread(&vetor[i],sizeof(vetor[i]),1,fp);
}
for (i = 0;i < n-1;i++)
for (j = i + 1;j < n;j++)
if (strcmp(vetor[i],vetor[j]) > 0)
{
strcpy(temp,vetor[i]);
strcpy(vetor[i],vetor[j]);
strcpy(vetor[j],temp);
}
rewind(fp);
for (i = 0;i < n;i++)
fwrite(&vetor[i],sizeof(vetor[i]),1,fp);
cout << "Ok, Arquivo Ordenado ..." << endl;
}
else
cout << "ERRO: [1] Criar ou [2] Abrir um Arquivo ... " << endl;
}

Lembrete: A vantagem em utilizar construtores parametrizados é evitar


a criação de métodos que inicializem atributos, tipo:
Inicializa_Atributos.

Observação: Como foi visto anteriormente, C++ possui um tipo de


dado chamado “bool” (booleam). É utilizado como flag, ou seja, aceita
apenas dois valores: true (verdadeiro) ou false (falso). As palavras true
e false são pré-definidas.
2.6 Quando construtores e destrutores são executados

A execução do construtor de um objeto depende de sua


declaração, ou seja, se é global ou local.

O construtor de um objeto local é executado quando a sua


declaração é encontrada. Quando mais de um objeto é declarado com a
mesma classe, seus construtores são executados da esquerda para a
direita. Os destrutores são executados na ordem inversa dos
construtores.

Construtores de objetos globais são executados antes da função


main. Destrutores globais são executados depois do main em ordem
inversa aos construtores.

Programa exemplo (58): O programa demonstra a execução dos


construtores e destrutores.

// construtor.cpp

#include <iostream>

using namespace std;

class Classe
{
public:
int quem;

Classe(int id);
~Classe(void);
} global1(1), global2(2); // objetos globais

Classe :: Classe(int id)


{
cout << "Construtor: " << id << endl;
quem = id;
}

Classe :: ~Classe(void)
{
cout << "Destrutor: " << quem << endl;
}

int main(void)
{
Classe local1(3); // objeto local

cout << "main" << endl;


Classe local2(4); // objeto local
}

Resultado do programa:

Construtor: 1
Construtor: 2
Construtor: 3
main
Construtor: 4
Destrutor: 4
Destrutor: 3
Destrutor: 2
Destrutor: 1

2.7 Operador resolução de escopo

O operador de resolução de escopo :: pode ser utilizado em duas


situações:

(a) Declarar um método fora de uma classe;


(b) Acessar uma variável fora do seu escopo, ou seja, acessar uma
variável global dentro de um método ou função que possui uma variável
local com o mesmo nome de uma variável global.

Programa exemplo (59): O programa demonstra a utilização do


operador de resolução de escopo.

// escopo.cpp

#include <iostream>

using namespace std;

int var = 5; // variável global

int main(void)
{
int var = 4; // variável local

cout << "Local: " << var << endl;


cout << "Global: " << :: var << endl; // operador de resolução de escopo
}

2.8 Passando objetos para funções

Em C++ é possível passar objetos (passagem de argumentos


por valor) como parâmetros de funções externas as classes.

Programa exemplo (60): O programa mostra a passagem de um


objeto via parâmetro para uma função externa.

// objeto.cpp

#include <iostream>

using namespace std;

// ----------------------------------------------- Classe

class Classe
{
int i;

public:
Classe (int n); // construtor
void Inicializa_Atributos(int n);
int Retorna_Atributo(void);
};

// ----------------------------------------------- função externa

void Exibe(Classe objeto) // parâmetro da função é um objeto


{
objeto.Inicializa_Atributos(2);
cout << "Atributo: " << objeto.Retorna_Atributo() << endl;
}

// ----------------------------------------------- Programa Principal

int main(void)
{
Classe objeto(1);

Exibe(objeto);
cout << "Atributo: " << objeto.Retorna_Atributo() << endl;
}

// ----------------------------------------------- construtor

Classe :: Classe (int n)


{
i = n;
}

// ----------------------------------------------- Inicializa_Atributos

void Classe :: Inicializa_Atributos(int n)


{
i = n;
}
// ----------------------------------------------- Retorna_Atributo

int Classe :: Retorna_Atributo(void)


{
return(i);
}

2.9 Retornando objetos

Em C++ é possível que uma função qualquer retorne um objeto.

Programa exemplo (61): O programa demonstra o retorno de um


objeto através de uma função externa.

// retorno.cpp

#include <iostream>

using namespace std;

// ----------------------------------------------- Classe

class Classe
{
int i;

public:
void Inicializa_Atributos(int n);
int Retorna_Atributo(void);
};

// ----------------------------------------------- função externa

Classe Exibe(void) // função retorna um objeto


{
Classe objeto;

objeto.Inicializa_Atributos(2);
return(objeto); // retorno do objeto
}

// ----------------------------------------------- Programa Principal

int main(void)
{
Classe objeto;

objeto = Exibe();
cout << "Atributo: " << objeto.Retorna_Atributo() << endl;
}
// ----------------------------------------------- Inicializa_Atributos

void Classe :: Inicializa_Atributos(int n)


{
i = n;
}

// ----------------------------------------------- Retorna_Atributo

int Classe :: Retorna_Atributo(void)


{
return(i);
}

2.10 Atribuição de objetos

C++ permite atribuição de objetos, ou seja, um objeto terá os


mesmos valores de outro objeto.

Programa exemplo (62): O programa demonstra uma atribuição entre


dois objetos.

// atrib.cpp

#include <iostream>

using namespace std;

// ----------------------------------------------- Classe

class Classe
{
int i;

public:
void Inicializa_Atributos(int n);
int Retorna_Atributo(void);
};

// ----------------------------------------------- Programa Principal

int main(void)
{
Classe objeto1, objeto2;

objeto1.Inicializa_Atributos(5);
cout << "Atributo Objeto 1: " << objeto1.Retorna_Atributo() << endl;
objeto2 = objeto1; // atribuição de objetos
cout << "Atributo Objeto 2: " << objeto2.Retorna_Atributo() << endl;
}

// ----------------------------------------------- Inicializa_Atributos

void Classe :: Inicializa_Atributos(int n)


{
i = n;
}

// ----------------------------------------------- Retorna_Atributo

int Classe :: Retorna_Atributo(void)


{
return(i);
}
3. Array, Ponteiros e Referências
3.1 Array de objetos

Em C++ é possível declarar vetores de objetos.

Programa exemplo (63): O programa demonstra um vetor de objetos.

// vetor.cpp

#include <iostream>

using namespace std;

const int MAX = 3;

// ----------------------------------------------- Classe

class Classe
{
int i;

public:
void Inicializa_Atributos(int n);
int Retorna_Atributo(void);
};

// ----------------------------------------------- Programa Principal

int main(void)
{
Classe objeto[MAX]; // vetor de três objetos
int i;

for (i = 0;i < MAX;i++)


{
objeto[i].Inicializa_Atributos(i+1);
cout << "Atributo Objeto [" << i << "]: " << objeto[i].Retorna_Atributo() << endl;
}
}

// ----------------------------------------------- Inicializa_Atributos

void Classe :: Inicializa_Atributos(int n)


{
i = n;
}

// ----------------------------------------------- Retorna_Atributo
int Classe :: Retorna_Atributo(void)
{
return(i);
}

Observação: Pode-se inicializar cada atributo do vetor na declaração do


vetor de objetos.

Programa exemplo (64): O programa demonstra um vetor de objetos


sendo inicializado na declaração.

// vetor2.cpp

#include <iostream>

using namespace std;

const int MAX = 3;

// ----------------------------------------------- Classe

class Classe
{
int i;

public:
Classe(int n) { i = n; } // construtor inicializa atributos
int Retorna_Atributo(void);
};

// ----------------------------------------------- Programa Principal

int main(void)
{
Classe objeto[MAX] = {1,2,3}; // vetor de objetos inicializado
int i;

for (i = 0;i < MAX;i++)


cout << "Atributo Objeto [" << i << "]: " << objeto[i].Retorna_Atributo() << endl;
}

// ----------------------------------------------- Retorna_Atributo

int Classe :: Retorna_Atributo(void)


{
return(i);
}

3.2 Ponteiros de Objetos


C++ permite também a utilização de ponteiros para objetos.

Programa exemplo (65): O programa demonstra a utilização de um


ponteiro para um objeto.

// pointer1.cpp

#include <iostream>

using namespace std;

// ----------------------------------------------- Classe

class Classe
{
int i;

public:
Classe (int n) { i = n; }
int Retorna_Atributo(void);
};

// ----------------------------------------------- Programa Principal

int main(void)
{
Classe objeto(10), *pobj;

pobj = &objeto;
cout << "Atributo Objeto: " << pobj->Retorna_Atributo() << endl;
cout << "Atributo: " << (*pobj).Retorna_Atributo() << endl;
}

// ----------------------------------------------- Retorna_Atributo

int Classe :: Retorna_Atributo(void)


{
return(i);
}

C++ permite ainda aritmética de ponteiros. O programa 66 mostra


um exemplo de aritmética de ponteiros para objetos.

Programa exemplo (66): O programa demonstra aritmética de


ponteiros para objetos.

// pointer2.cpp

#include <iostream>
using namespace std;

const int MAX = 3;

// ----------------------------------------------- Classe

class Classe
{
int i;

public:
Classe (int n) { i = n; }
int Retorna_Atributo(void);
};

// ----------------------------------------------- Programa Principal

int main(void)
{
Classe *pobj, objeto[MAX] = {10, 20, 30};
int i;

pobj = &objeto[0];
for (i = 0;i < MAX;i++)
{
cout << "Atributo Objeto: " << pobj->Retorna_Atributo() << endl;
pobj++;
}
}

// ----------------------------------------------- Retorna_Atributo

int Classe :: Retorna_Atributo(void)


{
return(i);
}

Programa exemplo (67): O programa demonstra acesso a um atributo


de um objeto através de um ponteiro para objeto.

// pointer3.cpp

#include <iostream>

using namespace std;

// ----------------------------------------------- Classe

class Classe
{
public:
int i; // atributo público
Classe (int n) { i = n; }
int Retorna_Atributo(void);
};

// ----------------------------------------------- Programa Principal

int main(void)
{
Classe objeto(100);
int *pobj;

pobj = &objeto.i; // ponteiro acessa atributo público do objeto


cout << "Atributo Objeto: " << *pobj << endl;

// ----------------------------------------------- Retorna_Atributo

int Classe :: Retorna_Atributo(void)


{
return(i);
}

3.3 O Ponteiro this

Quando um método qualquer é chamado, é passado


automaticamente um argumento que é um ponteiro para o objeto que
gerou a chamada. Este ponteiro é chamado this, ou seja, o ponteiro
this aponta para o objeto que chamou o método.

Programa exemplo (68): O programa demonstra a utilização do


ponteiro this.

// this.cpp

#include <iostream>

using namespace std;

// ----------------------------------------------- Classe

class Classe
{
int x;

public:
Classe Exibe(void)
{
this->x = 2;
return(*this);
}
int Retorna_Atributo(void)
{
return(x);
}
};

// ----------------------------------------------- Programa Principal

int main(void)
{
Classe objeto, objeto_temp;

objeto = objeto.Exibe();
objeto_temp = objeto;
cout << "Atributo: " << objeto_temp.Retorna_Atributo() << endl;
}

Programa exemplo (69): O programa demonstra a utilização do


ponteiro this.

// this.cpp

#include <iostream>

using namespace std;

// ----------------------------------------------- Classe

class Classe
{
int x,y;

public:
Classe Inicializa_Atributos(int tx, int ty)
{
this->x = tx;
this->y = ty;
return(*this);
}
void Retorna_Atributos(int &a, int &b) // referências
{
a = x;
b = y;
}
void Incrementa_Atributos(int n)
{
x = x + n;
y = y + n;
}
};
int main(void)
{
Classe objeto, temp;
int a, b;

objeto = objeto.Inicializa_Atributos(2, 3);


objeto.Retorna_Atributos(a, b);
cout << "a = " << a << endl;
cout << "b = " << b << endl;
temp = objeto;
temp.Incrementa_Atributos(7);
temp.Retorna_Atributos(a, b);
cout << "a = " << a << endl;
cout << "b = " << b << endl;
}

Observação: O ponteiro this é muito importante quando operadores


são sobrecarregados e podem auxiliar no gerenciamento de alguns tipos
de listas encadeadas.

Restrições: Funções amigas (friend) não são membros de uma classe,


portanto, não recebem ponteiro this. Métodos estáticos (sem retorno)
também não possuem ponteiro this.

3.4 Referências

C++ possui uma característica relativa a ponteiros chamada


referência, onde o operador & significa “referência a”. Uma referência
é um ponteiro implícito que não é alocado na memória, ou seja, não
ocupa espaço de memória.
int& x = y;

Na declaração acima, a variável x possui uma expressão de


inicialização “int& x = y;” desta forma a variável de referência x está
vinculada à localização de memória de y, ou seja, qualquer modificação
na variável y afeta diretamente a variável x.

Forma geral:

tipo& nome_da_variável = expressão_de_inicialização;

Restrições ao uso de referências: Não é possível:

1) Referenciar outra referência;


2) Obter o endereço de uma referência;
3)  Criar arrays (vetores) de referências;
4) Ter um ponteiro para uma referência;
5)  Referenciar campos de bits;
6) É sempre necessário inicializar uma referência na declaração da
referência, a não ser que seja membro de uma classe, parâmetro
formal de uma função ou retorno de uma função.

3.4.1 Parâmetros referenciados

Uma referência permite criar uma nova forma de fazer passagem


de parâmetros por referência sem o uso de ponteiros. Com o uso de
referências, no lugar de ponteiros, não é necessário acessar o conteúdo
do ponteiro (*p), ou seja, pode-se usar apenas o nome da variável de
referência.

Programa exemplo (70): O programa demonstra a utilização da


passagem de parâmetros utilizando-se referência e ponteiros.

// troca.cpp

#include <iostream>

using namespace std;

void Troca(int& a, int& b) // utilizando referências


{
int temp;

temp = a;
a = b;
b = temp;
}

void Troca(int *a, int *b) // utilizando ponteiros


{
int temp;

temp = *a;
*a = *b;
*b = temp;
}
int main(void)
{
int x = 3, y = 4;

cout << "x = " << x << " - y = " << y << endl;
Troca(x, y);
cout << "x = " << x << " - y = " << y << endl;
Troca(&x, &y);
cout << "x = " << x << " - y = " << y << endl;
}
3.4.2 Passando referências a objetos

Quando um objeto é passado como argumento para uma função,


uma cópia deste objeto é criada. Neste momento, o construtor deste
novo objeto não é executado, mas quando a função termina, o destrutor
é chamado. Se o objeto não precisa ser destruído, o objeto deve ser
passado utilizando-se uma “referência a (&)”, pois neste caso, não é
criada uma cópia do objeto passado para a função.

Programa exemplo (71): O programa demonstra a utilização da


passagem de parâmetros utilizando-se “referência a”.

// ref.cpp

#include <iostream>

using namespace std;

class Classe
{
int id;

public:
int i;
Classe(int num);
~Classe(void);
void Negativo(Classe &obj) { obj.i = -obj.i; } // experimente sem o &
};

int main(void)
{
Classe obj(1);

obj.i = 10;
obj.Negativo(obj);
cout << obj.i << endl;
}

Classe :: Classe(int num)


{
cout << "Construindo: " << num << endl;
id = num;
}

Classe :: ~Classe(void)
{
cout << "Destruindo: " << id << endl;
}

3.4.3 Retornando referências


Uma função pode retornar uma referência, possibilitando a
utilização da chamada da função à esquerda de uma atribuição.

Programa exemplo (72): O programa demonstra a utilização do


retorno de uma função através de uma referência.

// return.cpp

#include <iostream>

using namespace std;

char &troca(int i);

char str[20] = "Paulo";

int main(void)
{
cout << str << endl;
troca(4) = 'a';
cout << str << endl;
}

char &troca(int i)
{
return(str[i]);
}

3.5 Operadores C++ para alocação dinâmica

C++ possui dois operadores que permitem alocar memória


dinamicamente: new e delete.

O operador new permite a alocação de uma porção de memória


RAM (Random Access Memory – Memória de Acesso Aleatório) e
retorna o endereço de memória desta área alocada. Se não houver
memória suficiente livre para tal, o ponteiro recebe um NULL.

O operador delete libera a área de memória alocada pelo


operador new, para que esta área possa ser utilizada novamente.

C++ permite ainda, por questão de compatibilidade, a utilização


das funções padrões do C que permitam alocar memória
dinamicamente: malloc, calloc e free.

Como declarar um ponteiro:


tipo_base *nome_ponteiro;

Exemplos:

char *s;
int *x;
Classe *obj;
float *f;

Como alocar um ponteiro:

nome_ponteiro = new tipo_base;


nome_ponteiro = new (tipo_base)
nome_ponteiro = new tipo_base[número_de_elementos];

Exemplos:

p = new float;
q = new (float);
r = new float[7];

Como liberar um ponteiro:

delete nome_ponteiro; ou delete [] nome_ponteiro;

Observação: Pode-se declarar e alocar um ponteiro ao mesmo tempo.

int *i = new int;


float *f = new (float);
char *s = new char[7];

Programa exemplo (73): O programa demonstra a utilização dos


operadores new e delete para alocação dinâmica em C++.

// ptr1.cpp

#include <iostream>

using namespace std;

int main(void)
{
int *ptr; // declaração do ponteiro

ptr = new int;


if (ptr == NULL)
{
cout << "ERRO FATAL: Falta de Memória\n";
exit(EXIT_FAILURE); // pré-definido
}
*ptr = 1234; // incializa o ponteiro com o valor inteiro 1234
cout << "No endereço " << ptr << " existe o valor " << *ptr << endl;
delete ptr;
}

Resultado do Programa:

No endereço 0x804a008 existe o valor 1234

Forma geral de alocar arrays (vetores ou matrizes):


nome_ponteiro = new tipo_base
[número_de_elementos][número_de_elementos][número_de_elementos];

Observação: Arrays não podem ser inicializadas.

Programa exemplo (74): O programa demonstra a indexação de um


ponteiro de n elementos, ou seja, um array unidimensional (1D).

// ptr2.cpp

#include <iostream>

using namespace std;

int main(void)
{
int *ptr;
int n;

cout << "n = ";


cin >> n;
ptr = new int[n]; // [n] aloca “n” elementos inteiros
if (ptr == NULL)
{
cout << "ERRO FATAL: Falta de Memória\n";
exit(EXIT_FAILURE);
}
for (int i = 0;i < n;i++)
ptr[i] = i; // indexação do ponteiro
for (int i = 0;i < n;i++)
cout << "No endereço " << &ptr[i] << " existe o valor " << ptr[i] << endl;
delete [] ptr;
}

Programa exemplo (75): O programa demonstra uma forma


alternativa de alocar e inicializar um ponteiro ao mesmo tempo.
// ptr3.cpp
#include <iostream>

using namespace std;

int main(void)
{
int *ptr;

ptr = new int (100); // 100 é o valor inicial do ponteiro


if (ptr == NULL)
{
cout << "ERRO FATAL: Falta de Memória\n";
exit(EXIT_FAILURE);
}
cout << "No endereço " << ptr << " existe o valor " << *ptr << endl;
delete ptr;
}

3.5.1 Alocando objetos

C++ permite a alocação de objetos, ou seja, ponteiros para


objetos. O operador new aloca um ponteiro e retorna o endereço para o
objeto. Quando o objeto é alocado, seu construtor é executado. Quando
o objeto é desalocado, o destrutor do objeto é executado.

Programa exemplo (76): O programa demonstra alocação de um


objeto.
// pessoa1.cpp

#include <iostream>

using namespace std;

class Pessoa
{
int idade;

public:
char nome[41];
void Inicializa_Atributos(char *s, int id);
int Calcula_Ano_Nascimento(int ano_atual);
};

int main (void)


{
Pessoa *ptr;
int ano_atual, ano_nascimento, idade;

ptr = new Pessoa;


if (not ptr) // !NULL verdadeiro
{
cout << "ERRO FATAL: Falta de Memória\n";
exit(EXIT_FAILURE);
}
cout << "Ano Atual: ";
cin >> ano_atual;
cout << "Idade: ";
cin >> idade;
ptr->Inicializa_Atributos("Paulo Roberto Gomes Luzzardi", idade);
ano_nascimento = ptr->Calcula_Ano_Nascimento(ano_atual);
cout << ptr->nome;
cout << " nasceu em " << ano_nascimento << endl;
delete ptr;
}

void Pessoa :: Inicializa_Atributos(char *s, int id)


{
strcpy(nome,s);
idade = id;
}

int Pessoa :: Calcula_Ano_Nascimento(int ano_atual)


{
return(ano_atual - idade);
}

Resultado do programa:

Ano Atual: 2006 <enter>


Idade: 44 <enter>
Paulo Roberto Gomes Luzzardi nasceu em 1962

Programa exemplo (77): O programa demonstra alocação de um


objeto (Classe Pessoa possui construtor).
// pessoa2.cpp

#include <iostream>

using namespace std;

class Pessoa
{
int idade;

public:
char nome[41];
public:
Pessoa(char *s, int id);
int Calcula_Ano_Nascimento(int ano_atual);
};

int main (void)


{
Pessoa *ptr;
int ano_atual, ano_nascimento;
ptr = new Pessoa("Paulo Roberto Gomes Luzzardi", 44); // inicialização dos atributos
do objeto
if (not ptr) // !NULL verdadeiro
{
cout << "ERRO FATAL: Falta de Memória\n";
exit(EXIT_FAILURE);
}
cout << "Ano Atual: ";
cin >> ano_atual;
ano_nascimento = ptr->Calcula_Ano_Nascimento(ano_atual);
cout << ptr->nome << " nasceu em " << ano_nascimento << endl;
delete ptr;
}

Pessoa :: Pessoa (char *s, int id)


{
strcpy(nome,s);
idade = id;
}

int Pessoa :: Calcula_Ano_Nascimento(int ano_atual)


{
return(ano_atual - idade);
}

Resultado do programa:

Paulo Roberto Gomes Luzzardi nasceu em 1962

Programa exemplo (78): O programa demonstra alocação de um


objeto (Classe Pessoa possui construtor e destrutor).
// pessoa3.cpp

#include <iostream>

using namespace std;

class Pessoa
{
int idade;

public:
char *nome; // ponteiro
Pessoa(char *s, int id);
~Pessoa(void);
int Calcula_Ano_Nascimento(int ano_atual);
};

int main (void)


{
Pessoa *ptr;
int ano_atual, ano_nascimento;

ptr = new Pessoa("Paulo Roberto Gomes Luzzardi", 44); // inicialização dos atributos
do objeto
if (not ptr) // !NULL verdadeiro
{
cout << "ERRO FATAL: Falta de Memória\n";
exit(EXIT_FAILURE);
}
cout << "Ano Atual: ";
cin >> ano_atual;
ano_nascimento = ptr->Calcula_Ano_Nascimento(ano_atual);
cout << ptr->nome << " nasceu em " << ano_nascimento << endl;
delete ptr;
}

Pessoa :: Pessoa (char *s, int id) // construtor


{
int n = strlen(s);

nome = new char [n+1];


if (not nome)
{
cout << "ERRO FATAL: Falta de Memória\n";
exit(EXIT_FAILURE);
}
strcpy(nome,s);
idade = id;
}

Pessoa :: ~Pessoa(void) // destrutor


{
delete nome; // desalocação do atributo “nome”
}

int Pessoa :: Calcula_Ano_Nascimento(int ano_atual)


{
return(ano_atual - idade);
}

Resultado do programa:

Paulo Roberto Gomes Luzzardi nasceu em 1962

Programa exemplo (79): O programa demonstra alocação de um


vetor de objetos (Classe Pessoa possui construtor e destrutor).

// pessoa4.cpp

#include <iostream>

using namespace std;

const int N_ELEMENTOS = 3;

class Pessoa
{
int idade;

public:
char nome[81];
void Inicializa_Atributos(char *s, int id);
int Calcula_Ano_Nascimento(int ano_atual);
};

int main (void)


{
Pessoa *ptr;
int ano_atual, ano_nascimento[N_ELEMENTOS];

ptr = new Pessoa[N_ELEMENTOS]; // alocação do vetor de três objetos


if (not ptr) // !NULL verdadeiro
{
cout << "ERRO FATAL: Falta de Memória\n";
exit(EXIT_FAILURE);
}
ptr[0].Inicializa_Atributos("Paulo Roberto Gomes Luzzardi", 44);
ptr[1].Inicializa_Atributos("Adriane Maria Machado de Freitas Luzzardi", 37);
ptr[2].Inicializa_Atributos("Paola de Freitas Luzzardi", 7);
cout << "Ano Atual: ";
cin >> ano_atual;
for (int i = 0;i < N_ELEMENTOS;i++)
ano_nascimento[i] = ptr[i].Calcula_Ano_Nascimento(ano_atual);
for (int i = 0;i < N_ELEMENTOS;i++)
cout << ptr[i].nome << " nasceu em " << ano_nascimento[i] << endl;
delete [] ptr;
}

void Pessoa :: Inicializa_Atributos (char *s, int id)


{
strcpy(nome,s);
idade = id;
}

int Pessoa :: Calcula_Ano_Nascimento(int ano_atual)


{
return(ano_atual - idade);
}

Resultado do programa:

Paulo Roberto Gomes Luzzardi nasceu em 1962


Adriane Maria Machado de Freitas Luzzardi nasceu em 1969
Paola de Freitas Luzzardi nasceu em 1999

3.5.2 Alocação de memória

Dependendo da versão do compilador, talvez seja necessário, no


momento da liberação da memória alocada (delete), especificar o
número de elementos alocados pelo operador new. Algumas versões do
compilador não verificam a quantidade de elementos alocados e
desalocados, ou seja, tenha cuidado em alocar e liberar a mesma
quantidade de elementos.

Exemplo:

Objeto *ptr;
ptr = new Objeto[4];
...
delete [4]ptr;
4. Sobrecarga de Operadores e Funções
4.1 Sobrecarga de operadores

Em C++ alguns operadores (quase todos, com exceção destes: . .*


:: ?: sizeof) podem ser sobrecarregados da mesma forma que as
funções podem ser. Quando um operador é sobrecarregado, ele não
perde suas características normais, por exemplo: se numa pilha os
operadores '+' e '–' forem sobrecarregados para '+' inserir na pilha
(push) e '–' retirar da pilha (pop), eles continuam somando e subtraindo,
respectivamente, da mesma forma que antes, ou seja, a partir deste
momento eles executam novas operações (push e pop).

A sobrecarga de operadores é realizada através de funções


operadoras (operator), as quais definem as operações específicas
relativas à classe especificada. Estas funções podem ser membros ou
não da classe que terá os operadores sobrecarregados. Funções não-
membros da classe devem ser quase sempre funções amigas da classe.

4.2 Criando uma função-operador membro

A forma geral para declarar uma função operadora é:

tipo_retorno nome_da_classe :: operator@(lista_de_parâmetros)


{
corpo_da_função;
}

Onde: @ é o operador que será sobrecarregado.

Quando um operador unário é sobrecarregado (-, ++, --), a lista


de parâmetros deve ser vazia (void). Quando for binário (+, -, *, /, %),
deve possuir um parâmetro.

Programa exemplo (80): O programa demonstra a sobrecarga do


operador '+' em um objeto “Soma”.

// soma.cpp

#include <iostream>

using namespace std;

class Soma
{
double valor;
public:
Soma(void) {}; // construtor é necessário para declarar um objeto temporário Soma
Soma (double val)
{
valor = val;
}
void Exibe(char *mensagem)
{
cout << mensagem << valor << endl;
}
Soma operator+(Soma t) // operator+
{
Soma temp;

temp.valor = t.valor + valor;


return(temp);
}
};

// -------------------------------------- Programa Principal

int main(void)
{
Soma objeto1(1.23), objeto2(2.34), objeto3(0.0);

objeto1.Exibe("Valor do Objeto 1: ");


objeto2.Exibe("Valor do Objeto 2: ");
objeto3.Exibe("Valor do Objeto 3: ");

objeto3 = objeto1 + objeto2; // sobrecarga do operador '+'


objeto3.Exibe("Soma dos Valores dos Objetos 1 e 2: ");
}

Programa exemplo (81): O programa demonstra a sobrecarga dos


operadores '+' e '-' em uma fila alocada em um vetor.

// fila.cpp
// Sobrecarga dos operadores '+' e '-' em uma fila em vetor

#include <iostream>
#include <cctype>

using namespace std;

const int TAM = 5;

typedef int TDADOS;

// -------------------------------------- Definição da Classe Fila

class Fila
{
TDADOS fila[TAM];
int inic,fim;

public:
void Cria_Fila(void);
void operator+(TDADOS dado); // insere na fila
void operator-(TDADOS *dado); // retira da fila
TDADOS Consulta_Fila(void);
void Exibe_Fila(void);
};

// -------------------------------------- Cria_Fila

void Fila :: Cria_Fila(void)


{
inic = 0;
fim = 0;
}

// -------------------------------------- operator+

void Fila :: operator+(TDADOS dado)


{
if (fim == TAM)
{
cout << "Erro: Fila Cheia" << endl;
return;
}
fila[fim] = dado;
fim++;
}

// -------------------------------------- operator-

void Fila :: operator-(TDADOS *dado)


{
if (fim == 0)
{
cout << "Erro: Fila Vazia" << endl;
return;
}
inic++;
if (inic >= fim)
fim = 0;
*dado = fila[inic-1];
}

// -------------------------------------- Consulta_Fila

TDADOS Fila :: Consulta_Fila(void)


{
if (fim == 0)
{
cout << "Erro: Fila Vazia" << endl;
return 0;
}
return(fila[inic]);
}

// -------------------------------------- Exibe_Fila

void Fila :: Exibe_Fila(void)


{
cout << "Fila: ";
if (fim == 0)
{
cout << "VAZIA" << endl;
return;
}
for (int i = inic;i < fim;i++)
cout << fila[i] << " ";
cout << endl;
}

// -------------------------------------- Programa Principal

int main(void)
{
Fila fila;
char tecla;
TDADOS valor;

fila.Cria_Fila();
do {
fila.Exibe_Fila();
cout << "[I]nclui, [E]xclui, [C]onsulta ou [F]im: ";
do {
tecla = toupper(getchar());
} while (not strchr("IECF", tecla));
switch (tecla)
{
case 'I': cout << "Valor: ";
cin >> valor;
fila+(valor); // Insere na Fila (operador +)
break;
case 'E': fila-(&valor); // Retira da Fila (operador -)
if (valor not_eq 0)
cout << "Valor Excluído da Fila: " << valor << endl;
break;
case 'C': valor = fila.Consulta_Fila();
if (valor not_eq 0)
cout << "Valor Consultado: " << valor << endl;
break;
}
} while (tecla not_eq 'F');
}

Observação: Note que nas chamadas dos operadores sobrecarregados,


ambas possuem apenas um parâmetro, pois os operadores '+' e '-' são
operadores binários.

Operadores Lógicos:

Além dos operadores aritméticos e relacionais, o C++ possui os


operadores lógicos e operadores bit à bit.

Observação: Todos os operadores do C padrão podem ser utilizados em


programas escritos em C++.

A seguir as próximas três tabelas mostram os operadores lógicos,


relacionais e bit à bit:
Operadores Lógicos: &&, || e !

C C++ Ação
&& and true quando a condição_A e condição_B forem true
|| or true quando a condição_A ou condição_B forem true
! not negação (não) inverte a condição

Operadores Relacionais: !=

C C++ Ação
!= not_eq diferente, ou seja, não igual

Operadores bit à bit: &, &=, |, |=, ^, ^= e ~

C C++ Ação
& bitand (e) true quando bit_A e bit_b forem true (1) and (1)
&= and_eq (e igual)
| bitor (ou) true quando bit_A ou bit_B forem true: (1) ou (0) / (0) ou (1) / (1) ou (1) |-> (0) ou (0)
false
|= or_eq (ou igual)
^ xor (ou exclusivo) somente quando um dos bits for true: (1) ou (0) | (0) ou (1)
^= xor_eq (ou exclusivo igual)
~ compl (complemento de um)

4.3 Sobrecarga de operadores utilizando uma função friend

Em C++ é possível sobrecarregar operadores em relação a uma


classe amiga (friend). Lembre que uma função amiga não possui o
ponteiro this, pois ela não é membro de uma classe base, ou seja, é
necessário passar um ou dois parâmetros para ela: (a) dois operandos
se o operador for binário (+, -, *, /) e (b) apenas um se o operador for
unário (++, --).
Programa exemplo (82): O programa demonstra a sobrecarga do
operador '+' através de uma função amiga (friend).

// local.cpp

#include <iostream>

using namespace std;

class Local
{
int objeto; // identificação do objeto
int latitude, longitude;

public:
Local(void) {};
Local(int obj, int la, int lo)
{
objeto = obj;
latitude = la;
longitude = lo;
}
void Exibe(void)
{
cout << "Objeto (" << objeto << "): Latitude: " << latitude << " -> Longitude: " <<
longitude << endl;
}
friend Local operator+(Local op1, Local op2); // função amiga
Local operator-(Local op2);
Local operator=(Local op2);
Local operator++(void);
};

int main(void)
{
Local objeto1(1, 10, 20), objeto2(2, 30, 40), objeto3(3, 50, 60);

++objeto1;
objeto1.Exibe();
objeto2.Exibe();
objeto2 = ++objeto1;
objeto1.Exibe();
objeto2.Exibe();
objeto2 = objeto3;
objeto2.Exibe();
}

Local operator+(Local op1, Local op2) // função amiga (friend)


{
Local tmp;

tmp.latitude = op1.latitude + op2.latitude;


tmp.longitude = op1.longitude + op2.longitude;
return(tmp);
}

Local Local :: operator-(Local op2)


{
Local tmp;

tmp.latitude = latitude - op2.latitude;


tmp.longitude = longitude - op2.longitude;
return(tmp);
}

Local Local :: operator=(Local op2)


{
latitude = op2.latitude;
longitude = op2.longitude;
return(*this);
}

Local Local :: operator++(void)


{
(latitude)++;
(longitude)++;
return(*this);
}

Resultado do Programa:

Objeto(1): Latitude: 11 -> Longitude: 21


Objeto(2): Latitude: 30 -> Longitude: 40
Objeto(1): Latitude: 12 -> Longitude: 22
Objeto(2): Latitude: 12 -> Longitude: 22
Objeto(2): Latitude: 50 -> Longitude: 60

Existem algumas restrições quanto à utilização de funções amigas


como operadores sobrecarregados:

(a) Os operadores =, (), [] ou -> não podem ser sobrecarregados em funções


amigas;
(b) Com os operadores unários ++ e --, os operandos devem ser referências.

Programa exemplo (83): O programa demonstra a sobrecarga dos


operadores '++' e '--' através de funções amigas (friend).

// local.cpp

#include <iostream>

using namespace std;

class Local
{
int objeto;
int latitude, longitude;

public:
Local(void) {};
Local(int obj)
{
objeto = obj;
}
Local(int obj, int la, int lo)
{
objeto = obj;
latitude = la;
longitude = lo;
}
void Exibe(void)
{
cout << "Objeto (" << objeto << "): Latitude: " << latitude << " -> Longitude: " <<
longitude << endl;
}
Local operator=(Local op2);
friend Local operator++(Local &op2);
friend Local operator--(Local &op2);
};

int main(void)
{
Local objeto1(1, 10, 20), objeto2(2);

objeto1.Exibe();
++objeto1;
objeto1.Exibe();
objeto2.Exibe();
objeto2 = ++objeto1;
objeto1.Exibe();
objeto2.Exibe();
--objeto2;
objeto2.Exibe();
}

Local Local :: operator=(Local op2)


{
latitude = op2.latitude;
longitude = op2.longitude;
return(*this);
}

Local operator++(Local &op2)


{
op2.latitude++;
op2.longitude++;
return(op2);
}
Local operator--(Local &op2)
{
op2.latitude--;
op2.longitude--;
return(op2);
}

Resultado do Programa:

Objeto(1): Latitude: 10 -> Longitude: 20


Objeto(1): Latitude: 11 -> Longitude: 21
Objeto(2): Latitude: 134514985 -> Longitude: 134513662 // lixo
Objeto(1): Latitude: 12 -> Longitude: 22
Objeto(2): Latitude: 12 -> Longitude: 22
Objeto(2): Latitude: 11 -> Longitude: 21
5. Herança
5.1 Controle de acesso em classes base

Quando uma classe derivada herda as características de uma


classe base, os membros da classe base (públicos e protegidos) tornam-
se membros da classe derivada.

O tipo de acesso aos membros da classe base dependem do


especificador de acesso da classe derivada. Os especificadores de
acesso de uma classe derivada podem ser públicos ou privados. Se o
especificador de acesso não for explicitado, por default a classe derivada
é privada.

Quando é utilizado um especificador de acesso público (public)


em uma classe base todos os membros públicos se tornam públicos da
classe derivada.

Quando os membros são protegidos (protected) da classe base


eles podem ser acessados na classe derivada e tornam-se protegidos da
classe derivada. Os membros privados (private) da classe base não
podem ser acessados pela classe derivada.

Forma geral:

class nome_da_classe_derivada : especificador_acesso nome_classe_base


{
// atributos e métodos;
};

Programa exemplo (84): O programa demonstra a utilização de uma


classe derivada, ou seja, herança simples.

// heranca1.cpp

#include <iostream>

using namespace std;

class Base
{
protected:
int x, y;
private:
void seta_atributos(int tx, int ty)
{
x = tx;
y = ty;
}
public:
void Inicializa(int tx, int ty)
{
seta_atributos(tx,ty);
}
void Exibe(void)
{
cout << "x = " << x << " | y = " << y << endl;
}
};

class Derivada : public Base


{
public:
void Move(int tam)
{
x = x + tam;
y = y + tam;
}
};

int main(void)
{
Derivada d;

// d.seta_atributos(1,2); .... erro, pois este método é privado da classe base


d.Inicializa(1,2);
d.Exibe();
d.Move(10);
d.Exibe();
}

Resultado do Programa:

x=1|y=2
x = 11 | y = 12

Nota: No programa exemplo 84, acima, troque o especificador de


acesso da classe derivada de public para private e tente compilar o
programa.

Quando o especificador de acesso de uma classe derivada é


privada (private) todos os membros públicos e protegidos da classe
base tornam-se privados da classe derivada.

5.2 Herança e membros protegidos

Quando um membro (atributo ou método) de uma classe base é


declarado como protegido (protected) somente estes podem ser
acessados por uma classe derivada.
Quando um membro é declarado como protegido em uma classe
base ele torna-se acessível a qualquer classe derivada, inclusive se a
classe derivada torna-se derivada de outra classe derivada.

Programa exemplo (85): O programa demonstra a utilização de duas


classes derivadas através de uma classe base.

// heranca2.cpp

#include <iostream>

using namespace std;

class Base
{
protected:
int x, y;
private:
void seta_atributos(int tx, int ty)
{
x = tx;
y = ty;
}
public:
void Inicializa(int tx, int ty)
{
seta_atributos(tx,ty);
}
void Exibe(void)
{
cout << "x = " << x << " | y = " << y << endl;
}
};

class Derivada1 : public Base


{
public:
void Move(int tam)
{
x = x + tam;
y = y + tam;
}
};

class Derivada2 : public Derivada1


{
public:
void Retorna(int tam)
{
x = x - tam;
y = y - tam;
}
};
int main(void)
{
Derivada1 d1;
Derivada2 d2;

d1.Inicializa(1,2);
d1.Exibe();
d1.Move(10);
d1.Exibe();
d2.Inicializa(2,3);
d2.Exibe();
d2.Move(10);
d2.Exibe();
d2.Retorna(15);
d2.Exibe();
}

Resultado do Programa:

x = 1|y=2
x = 11 | y = 12
x = 2|y=3
x = 12 | y = 13
x = -3 | y = -2

Se o especificador de acesso da segunda classe derivada for


privado (private) alguns métodos (Inicializa, Move e Exibe) não
podem ser acessados na função main, somente na classe derivada2
(veja programa 86, abaixo).

Programa exemplo (86): O programa demonstra a utilização de duas


classes derivadas através de uma classe base (segunda classe derivada
tem acesso privado).

// heranca3.cpp

#include <iostream>

using namespace std;

class Base
{
protected:
int x, y;
private:
void seta_atributos(int tx, int ty)
{
x = tx;
y = ty;
}
public:
void Inicializa(int tx, int ty)
{
seta_atributos(tx,ty);
}
void Exibe(void)
{
cout << "x = " << x << " | y = " << y << endl;
}
};

class Derivada1 : public Base


{
public:
void Move(int tam)
{
x = x + tam;
y = y + tam;
}
};

class Derivada2 : private Derivada1


{
public:
void Retorna(int tam)
{
Inicializa(2,3); // pública na base – privada a classe derivada2
Move(10); // pública na classe derivada – privada a classe derivada2
x = x – tam; // protegida na base acessível a classe derivada2
y = y – tam; // protegida na base acessível a classe derivada2
Exibe(); // pública na base – privada a classe derivada2
}
};

int main(void)
{
Derivada1 d1;
Derivada2 d2;

d1.Inicializa(1,2);
d1.Exibe();
d1.Move(10);
d1.Exibe();
d2.Retorna(15);
}

Resultado do Programa:

x=1|y=2
x = 11 | y = 12
x = -3 | y = -2

5.3 Herança múltipla de classes base

Quando uma classe herda as características de mais de uma


classe base este tipo de herança é chamado de Herança Múltipla.

Programa exemplo (87): O programa demonstra a utilização de


herança múltipla, ou seja, uma classe é derivada de duas classes base.

// multipla.cpp

#include <iostream>

using namespace std;

class Base1
{
protected:
int x;
public:
void Exibe_Atributo_X(void)
{
cout << "x = " << x << endl;
}
};

class Base2
{
protected:
int y;
public:
void Exibe_Atributo_Y(void)
{
cout << "y = " << y << endl;
}
};

class Derivada : public Base1 , public Base2 // herança múltipla


{
public:
void Seta(int tx, int ty)
{
x = tx;
y = ty;
}
};

int main(void)
{
Derivada d;

d.Seta(1,2); // derivada
d.Exibe_Atributo_X(); // base1
d.Exibe_Atributo_Y(); // Base2
}
5.4 Passando parâmetros para os construtores das classes base

Para passar parâmetros para uma classe base através de uma


classe derivada, utiliza-se a sintaxe abaixo dentro da classe derivada
(veja exemplo 88):

Sintaxe:

class nome_da_classe_derivada : especificador_acesso nome_da_classe_base


{
//atributos
construtor_derivado (lista_de_argumentos) : base1 (lista_de_argumentos), base2 (lista_de_argumentos)
{
}
};

Programa exemplo (88): O programa demonstra a utilização de


construtores para uma classe base através de uma classe derivada em
herança simples.

// heranca.cpp

#include <iostream>

using namespace std;

class Base
{
protected:
int x;
public:
Base(int tx) // construtor
{
x = tx;
cout << "Construtor Base, Ok " << endl;
}
~Base(void) // destrutor
{
cout << "Destrutor Base, Ok" << endl;
}
};

class Derivada : public Base // herança simples


{
private:
int y;
public:
Derivada (int ty, int tx) : Base(tx) // passando argumentos para a classe base
{
y = ty;
cout << "Construtor Derivada, Ok" << endl;
}
~Derivada (void) //destrutor
{
cout << "Destrutor Derivada, Ok" << endl;
}
void Exibe(void)
{
cout << "| x = " << x << " | y = " << y << " |" << endl;
}
};

int main(void)
{
Derivada d(3,4);

d.Exibe();
}

Resultado do Programa:

Construtor Base, Ok
Construtor Derivada, Ok
|x=4|y=3|
Destrutor Derivada, Ok
Destrutor Base, Ok

Programa exemplo (89): O programa demonstra a utilização de


construtores para classes bases através de uma classe derivada em
herança múltipla.

// heranca.cpp

#include <iostream>

using namespace std;

class Base1
{
protected:
int x;
public:
Base1(int tx)
{
x = tx;
cout << "Construtor Base1, Ok " << endl;
}
~Base1(void)
{
cout << "Destrutor Base1, Ok" << endl;
}
};

class Base2
{
protected:
int y;
public:
Base2(int ty)
{
y = ty;
cout << "Construtor Base2, Ok " << endl;
}
~Base2(void)
{
cout << "Destrutor Base2, Ok" << endl;
}
};

class Derivada : public Base1 , public Base2


{
private:
int z;
public:
Derivada (int tz, int ty, int tx) : Base2(ty) , Base1(tx)
{
z = tz;
cout << "Construtor Derivada, Ok" << endl;
}
~Derivada (void)
{
cout << "Destrutor Derivada, Ok" << endl;
}
void Exibe(void)
{
cout << "| x = " << x << " | y = " << y << " | z = " << z << " |" << endl;
}
};

int main(void)
{
Derivada d(3,4,5);

d.Exibe();
}

Resultado do Programa:

Construtor Base1, Ok
Construtor Base2, Ok
Construtor Derivada, Ok
|x=5|y=4|z=3|
Destrutor Derivada, Ok
Destrutor Base2, Ok
Destrutor Base1, Ok

5.5 Garantindo acesso

Quando uma classe derivada herda uma classe base com


especificador de acesso private, todos seus membros (public, private
ou protected) tornam-se membros privados da classe derivada. Quando
é necessário restaurar o acesso aos membros da classe base, utiliza-se
uma declaração de acesso.

Forma de usar: nome_da_classe_base :: membro;

Observação: Uma declaração de acesso não funciona para atributos ou


métodos declarados como private.

Programa exemplo (90): O programa demonstra a utilização de


declaração de acesso em uma classe derivada declarada como
privada.

// heranca.cpp

#include <iostream>

using namespace std;

class Base
{
protected:
int x, y;
public:
void Inicializa(int tx, int ty)
{
x = tx;
y = ty;
}
void Exibe(void)
{
cout << "x = " << x << " | y = " << y << endl;
}
};

class Derivada : private Base


{
public:
Base :: Inicializa; // declaração de acesso, método “Inicializa” tornou-se público
Base :: Exibe; // declaração de acesso, método “Exibe” tornou-se público
void Move(int tam)
{
x = x + tam;
y = y + tam;
}
};

int main(void)
{
Derivada d;
d.Inicializa(1,2);
d.Exibe();
d.Move(10);
// d.x = 7; ... erro, pois x é protegido, a não ser que seja feito Base :: x; na classe Derivada
d.Exibe();
}

5.6 Classes base virtuais

Na herança múltipla pode haver problema de ambigüidade, pois


quando uma classe derivada herda duas outras classes derivadas que
herdaram uma mesma classe base, existe duas cópias desta classe base
na classe derivada múltipla. Desta forma, quando se tenta acessar um
atributo de uma classe das classes derivadas, o compilador não sabe a
qual das classes derivadas o atributo pertence, dois existem duas cópias
da classe base. Existem duas formas de resolver este problema. A
primeira é através do operador de resolução de escopo (veja
programas exemplos 91 e 92).

Programa exemplo (91): O programa demonstra a utilização do


operação de resolução de escopo em herança múltipla para resolver
o problema citado acima.

// multipla.cpp

#include <iostream>

using namespace std;

class Base
{
public:
int i;
};

class Derivada1 : public Base


{
public:
int j;
};

class Derivada2 : public Base


{
public:
int k;
};

class Derivada3 : public Derivada1 , public Derivada2


{
public:
int soma;
public:
void Exibe(void)
{
cout << "Soma = " << soma << endl;
}
};

int main(void)
{
Derivada3 d3;

d3.Derivada1 :: i = 1; // operador de resolução de escopo


d3.Derivada2 :: i = 2; // operador de resolução de escopo
d3.j = 3;
d3.k = 4;
d3.soma = d3.Derivada1::i + d3.Derivada2::i + d3.j + d3.k;
d3.Exibe();
}

Resultado do Programa:

Soma = 10

Programa exemplo (92): O programa demonstra a utilização do


operação de resolução de escopo em herança múltipla para resolver
o problema citado acima.

// multipla.cpp

#include <iostream>

using namespace std;

class Base
{
public:
int x;
public:
void Inicializa_Base(int tx)
{
x = tx;
}
void Exibe_Base(void)
{
cout << "x = " << x << " |" << endl;
}
int Retorna_Base(void)
{
return(x);
}
};
class Derivada1 : public Base
{
public:
int y;
public:
void Inicializa(int ty, int tx)
{
y = ty;
Inicializa_Base(tx);
Exibe_Base();
}
void Exibe(void)
{
cout << "y = " << y << " |" << endl;
}
};

class Derivada2 : public Base


{
public:
int z;
public:
void Inicializa(int tz, int tx)
{
z = tz;
Inicializa_Base(tx);
Exibe_Base();
}
void Exibe(void)
{
cout << "z = " << z << " |" << endl;
}
};

class Derivada3 : public Derivada1 , public Derivada2


{
public:
int soma;
public:
void Exibe(void)
{
cout << "Soma = " << soma << endl;
}
};

int main(void)
{
Derivada1 d1;
Derivada2 d2;
Derivada3 d3;

d1.Inicializa(1,2);
d1.Exibe();
d2.Inicializa(3,4);
d2.Exibe();
d3.soma = d1.Derivada1::x + d2.Derivada2::x; // diferença entre os programas 70 e
71
d3.Exibe();
d3.soma = d3.soma + (d1.y + d2.z);
d3.Exibe();
}

Resultado do Programa:

x=2|
y=1|
x=4|
z=3|
Soma = 6
Soma = 10

Outra forma de resolver o problema citado acima é a utilização de


classes virtuais, pois quando se utiliza herança múltipla através de
classes bases virtuais não são criadas cópias múltiplas da classe base,
ou seja, é criado apenas uma cópia da classe base (veja os programas
exemplo 93 e 94).

Programa exemplo (93): O programa demonstra a utilização de


classes virtuais em herança múltipla para resolver o problema citado
acima.

// multipla.cpp

#include <iostream>

using namespace std;

class Base
{
public:
int i;
};

class Derivada1 : virtual public Base


{
public:
int j;
};

class Derivada2 : virtual public Base


{
public:
int k;
};
class Derivada3 : public Derivada1 , public Derivada2
{
public:
int soma;
public:
void Exibe(void)
{
cout << "Soma = " << soma << endl;
}
};

int main(void)
{
Derivada3 d3;

d3.i = 2;
d3.j = 3;
d3.k = 4;
d3.soma = d3.i + d3.j + d3.k;
d3.Exibe();
}

Resultado do Programa:

Soma = 9

Programa exemplo (94): O programa demonstra a utilização de


classes virtuais em herança múltipla para resolver o problema citado
acima.

// multipla.cpp

#include <iostream>

using namespace std;

class Base
{
public:
int x;
public:
void Inicializa_Base(int tx)
{
x = tx;
}
void Exibe_Base(void)
{
cout << "x = " << x << endl;
}
int Retorna_Base(void)
{
return(x);
}
};

class Derivada1 : virtual public Base


{
public:
int y;
public:
void Inicializa(int ty, int tx)
{
y = ty;
Inicializa_Base(tx);
Exibe_Base();
}
void Exibe(void)
{
cout << "y = " << y << endl;
}
};

class Derivada2 : virtual public Base


{
public:
int z;
public:
void Inicializa(int tz, int tx)
{
z = tz;
Inicializa_Base(tx);
Exibe_Base();
}
void Exibe(void)
{
cout << "z = " << z << endl;
}
};

class Derivada3 : public Derivada1 , public Derivada2


{
public:
int soma;
public:
void Exibe(void)
{
cout << "Soma = " << soma << endl;
}
};

int main(void)
{
Derivada1 d1;
Derivada2 d2;
Derivada3 d3;

d1.Inicializa(1,2);
d1.Exibe();
d2.Inicializa(3,4);
d2.Exibe();
d3.soma = d1.x + (d1.y + d2.z); // Soma = 6
d3.Exibe();
d3.soma = d2.x + (d1.y + d2.z); // Soma = 8
d3.Exibe();
}

Resultado do Programa:

x=2
y=1
x=4
z=3
Soma = 6
Soma = 8
6. Funções Virtuais e Polimorfismo
6.1 Funções virtuais

Uma função é dita virtual quando é declarada com o especificador


virtual em uma classe base e depois é redefinida em classes derivadas.

A redefinição da função na classe derivada precede a função da


classe base, ou seja, a declaração da função virtual na classe base
demonstra o funcionamento básico do método virtual, enquanto que as
redefinições funcionam como funcionamento específico do método
virtual.

Observação: Uma função virtual em OOP é chamado de método virtual.

Programa exemplo (95): O programa demonstra a utilização de uma


função virtual em herança simples.

// virtual.cpp

#include <iostream>

using namespace std;

class Base
{
protected:
int x;
public:
Base(int tx)
{
x = tx;
}
virtual void Exibe(void)
{
cout << "x = " << x << " |" << endl;
}
};

class Derivada1 : public Base


{
public:
int y;
public:
Derivada1(int ty, int tx) : Base(tx)
{
y = ty;
}
void Exibe(void) // redefinição da função virtual
{
cout << "x = " << x << " | y = " << y << " | " << endl;
}
};

class Derivada2 : public Base


{
public:
int z;
public:
Derivada2(int tz, int tx) : Base(tx)
{
z = tz;
}
void Exibe(void) // redefinição da função virtual
{
cout << "x = " << x << " | z = " << z << " |" << endl;
};

int main(void)
{
Base base(1);
Derivada1 d1(4,2); // 2 é um valor para a variável x
Derivada2 d2(5,3); // 3 é um valor para a variável x

base.Exibe();
d1.Exibe();
d2.Exibe();
}

Resultado do Programa:

x=1|
x=2|y=4|
x=3|z=5|

O acesso a funções virtuais pode ser feita através de ponteiros. O


programa exemplo abaixo demonstra a utilização de ponteiros para
funções virtuais (métodos virtuais).

Programa exemplo (96): O programa demonstra a utilização de uma


função virtual em herança simples com ponteiros.

// virtual.cpp

#include <iostream>

using namespace std;

class Base
{
protected:
int x;
public:
Base(int tx)
{
x = tx;
}
virtual void Exibe(void)
{
cout << "x = " << x << " |" << endl;
}
};

class Derivada1 : public Base


{
public:
int y;
public:
Derivada1(int ty, int tx) : Base(tx)
{
y = ty;
}
void Exibe(void)
{
cout << "x = " << x << " | y = " << y << " | " << endl;
}
};

class Derivada2 : public Base


{
public:
int z;
public:
Derivada2(int tz, int tx) : Base(tx)
{
z = tz;
}
void Exibe(void)
{
cout << "x = " << x << " | z = " << z << " |" << endl;
};

int main(void)
{
Base *pt, base(1);
Derivada1 d1(4,2);
Derivada2 d2(5,3);

pt = &base;
pt->Exibe();
pt = &d1;
pt->Exibe();
pt = &d2;
pt->Exibe();
}
Resultado do Programa:

x=1|
x=2|y=4|
x=3|z=5|

Restrições na utilização de funções virtuais:

a) Se o protótipo de uma função virtual nas classes derivadas é


modificado, a função virtual é considerada sobrecarga de funções;
b) As funções virtuais devem ser membros das classes a que pertencem;
c) Não podem ser funções amigas (friend);
d) Construtores não podem ser virtuais, mas destrutores podem.

6.2 Funções virtuais puras

O objetivo de uma função virtual pura é que quando uma função


virtual não for redefinida por uma classe derivada, a função virtual pura
declarada na classe base é executada.

Uma função virtual pura não possui nenhuma definição no seu


interior. Ela é declarada assim:

virtual tipo_de_retorno_do_método nome_do_método_virtual (lista_de_argumentos)


= 0;

Quando uma função virtual pura é declarada em uma classe base,


todas as classes derivadas devem obrigatoriamente redefinir a função
virtual.

Programa exemplo (97): O programa demonstra a utilização de uma


função virtual pura em herança simples.

// virtualpura.cpp

#include <iostream>

using namespace std;

class Base
{
protected:
int valor;
public:
Base(int x) { valor = x; }
virtual void Exibe(void) = 0; // função virtual pura
};

class Hexadecimal : public Base


{
public:
Hexadecimal(int x): Base(x) { }
void Exibe(void)
{
cout << "Valor em Hexadecimal = " << uppercase << hex << valor << endl;
}
};

class Decimal : public Base


{
public:
Decimal(int x): Base(x) { }
void Exibe(void)
{
cout << "Valor em Decimal = " << dec << valor << endl;
}
};

class Octal : public Base


{
public:
Octal(int x): Base(x) { }
void Exibe(void)
{
cout << "Valor em Octal = " << oct << valor << endl;
}
};

const int num = 26;

int main(void)
{
Hexadecimal hexadecimal(num);
Decimal decimal(num);
Octal octal(num);

hexadecimal.Exibe();
decimal.Exibe();
octal.Exibe();
}

Resultado do Programa:

Valor em Hexadecimal = 1A
Valor em Decimal = 26
Valor em Octal = 32

6.3 Classes abstratas

Uma classe é abstrata quando possui pelo menos uma função


virtual pura. Uma classe abstrata não pode criar objetos (veja
observação abaixo). Uma classe abstrata é considerada uma classe
incompleta que é utilizada apenas como base para classes derivadas.
Apesar de não ser possível criar objetos neste tipo de classe, pode-se
criar ponteiros que apontem para este tipo de classe, isto fornece
suporte a polimorfismo em tempo de execução.

Observação: No programa exemplo anterior (97) tente inserir a


seguinte linha na função main: Base base(5); Note que dará um erro
de compilação.

6.4 Usando funções virtuais

Uma das características mais importantes da orientação à objetos


é a capacidade de polimorfismo (“... uma interface, vários métodos ...”).
Para tanto pode-se declarar uma classe base como interface, ou seja,
utilizada para definir a natureza da interface e cada classe derivada
implementa operações específicas a esta interface.

Para criar hierarquias de classes que representem este contexto


“... uma interface, vários métodos ...”, deve-se utilizar: funções
virtuais, classes abstratas e polimorfismo em tempo de
execução. Desta forma, define-se todas as características comuns e a
interface na classe base e as ações sobre a interface nas classes
derivadas.

Programa exemplo (98): O programa demonstra a utilização de


funções virtuais em herança simples.

// abstrata.cpp

#include <iostream>

using namespace std;

class Base
{
protected:
double valor, celsius, fahrenheit;
public:
Base(double temperatura) { valor = temperatura; }
void Exibe(void)
{
cout << "Celsius = " << celsius << endl;
cout << "Fahrenheit = " << fahrenheit << endl << endl;
}
virtual void Converte(void) = 0;
};

class Celsius_Fahrenheit : public Base


{
public:
Celsius_Fahrenheit(double temperatura): Base(temperatura) { }
void Converte(void)
{
fahrenheit = (9 * valor) / 5 + 32;
celsius = valor;
}
};

class Fahrenheit_Celsius : public Base


{
public:
Fahrenheit_Celsius(double temperatura): Base(temperatura) { }
void Converte(void)
{
celsius = ((valor - 32) / 9) * 5;
fahrenheit = valor;
}
};

int main(void)
{
Celsius_Fahrenheit celsius(40.0);
Fahrenheit_Celsius fahrenheit(104.0);

celsius.Converte();
celsius.Exibe();
fahrenheit.Converte();
fahrenheit.Exibe();
}

Resultado do Programa:

Celsius = 40
Fahrenheit = 104

Celsius = 40
Fahrenheit = 104
7. Utilização Básica do Sistema de I/O do
C++
7.1 Fluxos do C++

Um fluxo (stream) é um dispositivo lógico de entrada e saída (io –


input output) que está ligado a um dispositivo físico, normalmente a
entrada está ligada ao teclado e a saída ao monitor de vídeo. Além
destes dispositivos, pode-se ainda utilizar uma impressora ou ler e
gravar em arquivos.

7.2 Classes básicas dos streams

C++ permite acessar os fluxos de entrada e saída através do


arquivo de cabeçalho (header) “iostream.h” ou simplesmente
“iostream”. Neste arquivo é definida uma hierarquia de classes de
entrada e saída.

Hierarquia das classes (fluxos):

streambuf: Métodos para buffers de memória. Esta classe base é a de mais baixo
nível, proporcionando operações básicas de entrada e saída para as outras classes
derivadas.

ios: Manipula o estado das variáveis dos fluxos e erros.


istream: Manipula conversões formatadas e não formatadas da classe
streambuf.
ostream: Manipula conversões formatadas e não formatadas da classe
streambuf.
iostream: istream e ostream juntas para manipular operações bi-direcionais
em um único fluxo.
istream_withassign: Fornece construtores e operadores de atribuição para o
fluxo cin.
ostream_withassign: Fornece construtores e operadores de atribuição para os
fluxos cout, cerr e clog.
iostream_withassign: Fornece construtores e operadores de atribuição para
os fluxos cin, cout, cerr e clog.

7.3 Streams pré-definidos do C++

Quando um programa em C++ começa a ser executado quatro


fluxos são abertos: cin, cout, cerr e clog.

cin: Entrada padrão via teclado.


cout: Saída padrão via monitor de vídeo.
cerr: Saída padrão de erro via tela.
clog: Saída padrão de erro “bufferizada” via tela.

7.4 Entrada e saída formatada

Todas as formatações possíveis feitas em C padrão pelas funções


printf e scanf podem ser realizadas pelos métodos cin e cout e pelos
operadores << e >>.

C++ permite a utilização das funções printf e scanf, mas por outro
lado possui duas formas de formatar dados através das funções cin e
cout:

1) Acessando diretamente os membros da classe ios (atributos ou


métodos) ou seja, é possível configurar os flags de formatação (veja
item 7.5 a seguir);
2) Utilizando manipuladores (funções especiais) nos métodos cin e
cout (veja item 7.7 logo abaixo).

7.5 Formatando utilizando os membros de entrada e saída

Existe um conjunto de flags, associados a cada fluxo, que


permitem controlar a forma que a informação é tratada em cada fluxo.
Os flags de formatação são armazenados em um inteiro longo (long
int). Na classe ios existe a seguinte enumeração:

enum
{
skipws = 0x0001;
left = 0x0002;
right = 0x0004;
internal = 0x0008;
dec = 0x0010;
oct = 0x0020;
hex = 0x0040;
showbase = 0x0080;
showpoint = 0x0100;
uppercase = 0x0200;
showpos = 0x0400;
scientific = 0x0800;
fixed = 0x1000;
unitbuf = 0x2000;
stdio = 0x4000;
};

flags Significado
ios::skipws Ignorar espaços em branco na entrada
ios::left Alinhar à esquerda na saída
ios::right Alinhar à direita na saída
ios::internal Preencher após o sinal ou indicador de base
ios::dec Imprimir saída como decimal
ios::oct Imprimir saída como octal
ios::hex Imprimir saída como hexadecimal
ios::showbase Exibir indicador de base na saída
ios::showpoint Exibir ponto decimal (ponto flutuante)
ios::uppercase Exibir saída hex em maiúsculo
ios::showpos Exibir '+' com inteiros positivos
ios::scientific Exibir em notação científica (1.23e+00 ou 1.23E+00 se usar uppercase)
ios::fixed Utilizar a notação em ponto flutuante (123.45)
ios::unitbuf Apagar todos os fluxos após inserção
ios::stdio Apagar os fluxos stdout e stderr após inserção

7.6 Setando flags de formato

Para configurar um flag de formato utiliza-se o método setf(). Este


método pertence a classe ios.

Sintaxe: long setf(long flags);

Funcionamento: O método retorna o valor corrente dos flags e seta os


flags especificados por flags, não afetando os demais flags.

Forma de usar: fluxo.setf(ios:flag);

Exemplo: cout.setf(ios:flag);

Programa exemplo (99): O programa demonstra a utilização da


função setf para formatar o método cout.

// setf.cpp

#include <iostream>

using namespace std;

int main(void)
{
cout.setf(ios::uppercase);
cout.setf(ios::hex);
for (int i = 0;i <= 10000;i++)
cout << i << endl;
}

7.7 Formatando usando manipuladores

Como foi dito anteriormente, existe uma segunda forma de


formatar o fluxo cout, a utilização de manipuladores.
Existem vários manipuladores de entrada e saída que permitem
formatar o que será impresso na tela com o método cout. Estes
manipuladores estão definidos em iomanip e são: dec, endl, ends,
flush, hex, oct, resetiosflag, setbase, setfill, setiosflags,
setprecision, setw, ws, left, right, uppercase e scientific.

dec: Exibe um número em decimal (saída).


endl: Pula uma linha (saída).
ends: Envia um NULL (saída).
flush: Esvazia o fluxo (saída).
hex: Exibe um número em hexadecimal (saída).
oct: Exibe um número em octal (saída).
resetiosflag(long flag): Apaga os flags especificados por flag (entrada e
saída).
setbase(int base): Seta a base numérica para base (saída).
setfill(char ch): Indica que caracter será impresso no lugar de um
número (saída).
setiosflags(long flag): Liga os flags especificados por flag (entrada e
saída).
setprecision(int n): Especifica o número de dígitos (n) que serão
impressos, antes e depois do ponto (saída).
setw(int n): Indica quantos dígitos (n) serão impressos na tela (saída).
ws: Salta espaços em branco ao final (entrada).
left: Alinha pela esquerda. Deve ser usado antes do setw (saída).
right: Alinha pela direita. Deve ser usado antes do setw (saída).
uppercase: Exibe os caracteres maiúsculos (saída).
scientific: Exibe um número em notação científica (saída).

Programa exemplo (100): O programa demonstra a utilização do


manipulador setprecision para formatar o método cout.

// setprecision.cpp

#include <iostream>
#include <iomanip>

using namespace std;

int main (void)


{
double pi = 3.14159;

cout << setprecision (3) << pi << endl;


cout << setprecision (4) << pi << endl;
}

Programa exemplo (101): O programa demonstra a uso dos


manipuladores setfill e setw para formatar o método cout.

// formata.cpp

#include <iostream>
#include <iomanip>

using namespace std;

int main (void)


{
for (int i = 0;i <= 10000;i++)
cout << setfill('0') << setw(5) << i << endl;
}

Programa exemplo (102): O programa demonstra a uso dos


manipuladores right e setw para formatar o método cout.

// right.cpp

#include <iostream>
#include <iomanip>

using namespace std;

int main (void)


{
for (int i = 0;i <= 10000;i++)
cout << "|" << right << setw(10) << i << "|" << endl;
}

Programa exemplo (103): O programa demonstra a uso dos


manipuladores uppercase e hex para formatar o método cout.

// hex.cpp

#include <iostream>
#include <iomanip>

using namespace std;

int main (void)


{
for (int i = 0;i <= 10000;i++)
cout << uppercase << hex << i << endl;
}
8. Tratamento de Exceções
Uma exceção é um erro que ocorre em tempo de execução e pode ou não ser tratado 
pela aplicação. 

O tratamento de exceções especifica uma ou mais soluções para uma situação de 
erro quando o programa está sendo executado. 

Quando é registrado uma situação de exceção (ou seja, um erro é detectado) ocorre 
um desvio para um local que irá tratá­lo diretamente, cruzando as fronteiras de funções e do 
controle do fluxo do programa.

Exceções são executadas quando ocorre alguma falha. Exceções


executadas são capturadas e tratadas.

Sintaxe:

try: Delimita o início do bloco com código protegido.


catch: Delimita o final de um bloco protegido e o início das instruções
de tratamento de exceções.
throw: Gera novas exceções ou propaga uma já existente.

try {
// código a ser protegido de um erro;
} catch (variável inteiro) {
// código de tratamento do erro;
}

Vantagens no uso do tratamento de exceções:

Com o uso de exceções há uma separação entre o código que


identifica uma condição de erro do código que reporta o erro;
O código da aplicação não precisa ficar cheio de pontos que
verifiquem erros (substitui diversos if's);
O programador não tem como fugir das exceções geradas, ele têm
que tratá-las;
Aumento da confiabilidade da aplicação;
Se o programador deseja tratar algum tipo de exceção ele adiciona
na aplicação o código necessário para tal, senão ele pode fornecer
um tratamento padrão para as todas as exceções;
A geração de uma exceção chama destrutores.

Observação: Podem haver vários blocos catch para cada comando try.
Podem haver vários comandos throw.
Programa exemplo (104): O programa demonstra a utilização dos
comandos try, throw e catch.

// catch1.cpp

#include <iostream>
#include <limits>

using namespace std;

float div(float a, float b)


{
if (b not_eq 0) // b != 0
return(a/b);
else
throw 100;
}

int main(void)
{
float x, y, resp;

try {
cout << "Digite um valor: ";
cin >> x;
cout << "Digite outro valor: ";
cin >> y;
resp = div(x, y);
cout << "Resposta: " << resp << endl;
} catch (int i) {
if (i == 100)
cout << "Erro: Divisão por Zero" << endl;
else
cout << "Erro desconhecido" << endl;
}
}

Observação: Quando não for especificado uma variável inteira no


comando catch ele é genérico. Veja exemplo abaixo:

Programa exemplo (105): O programa demonstra a utilização dos


comandos try, throw e com um comando catch genérico.

// catch2.cpp

#include <iostream>
#include <limits>

using namespace std;

float div(float a, float b)


{
if (b not_eq 0)
return(a/b);
else
throw 100;
}

int main(void)
{
float x, y, resp;

try {
cout << "Digite um valor: ";
cin >> x;
cout << "Digite outro valor: ";
cin >> y;
resp = div(x, y);
cout << "Resposta: " << resp << endl;
} catch (...) { // (...) catch genérico
cout << "Erro: Divisão por Zero" << endl;
}
}
9. Jogo escrito em C++
Para demonstrar a capacidade da linguagem de programação
C++, será mostrado o programa fonte de um jogo da forca escrito em
C++ utilizando a biblioteca ncurses.

Tela do Jogo da Forca

Programa exemplo (106): O programa demonstra a utilização da


biblioteca ncurses em um do jogo da forca escrito em C++.

// JogoForca.cpp (Ubuntu 6.06 Dapper- Anjuta)


// Autor: Paulo Roberto Gomes Luzzardi
// Data: 07/08/2006

// --------------------------------------------------------- includes

#include <iostream>
#include <string>
#include <curses.h>

using namespace std;

// --------------------------------------------------------- constantes

const char ESC = 27;


const char ENTER = 13;
const char SPACE = 32;

const int LEFT = 260;


const int RIGHT = 261;

const char BLACK = COLOR_BLACK;


const char RED = COLOR_BLUE;
const char GREEN = COLOR_GREEN;
const char BROWN = COLOR_YELLOW;
const char BLUE = COLOR_BLUE;
const char MAGENTA = COLOR_MAGENTA;
const char CYAN = COLOR_CYAN;
const char WHITE = COLOR_WHITE;

const char COR_TEXTO = GREEN;


const char COR_TELA = BROWN;
const char COR_TEMPO = RED;
const char COR_RELOGIO = BROWN;
const char COR_WINNER = CYAN;
const char COR_LETRAS = BLUE;
const char COR_SELECAO = RED;
const char COR_TITULO = MAGENTA;
const char COR_STATUS = WHITE;
const int NPAL = 30;
const int PSORT = 8;
const int NTIPOS = 4;

// ----------------------------------------------- Palavras

string nomes[NTIPOS] = {"Cidades","Países","Carros","Frutas"};


string cidades[NPAL] = {"pelotas", "alegrete", "uruguaiana", "livramento", "chui",
"rivera", "chuy", "piratini", "candiota", "marau", "erechin", "cachoerinha",
"caxias", "gramado", "canela", "itaqui", "cacequi", "formigueiro", "parati", "buzios",
"torres", "mostarda", "tapes", "agudo",
"candiota","chiapeta","cassino","casca","cristal","cidreira"};
string paises[NPAL] = {"brasil", "peru", "uruguai", "argentina", "bolivia", "chile",
"guatemala", "cuba", "alemanha", "suecia", "inglaterra", "china", "russia",
"montenegro", "tibet", "nepal", "servia", "noruega", "portugal", "espanha",
"grecia", "mongolia", "escocia", "palestina", "israel",
"iraqui","australia","jamaica","egito","congo"};
string carros[NPAL] = {"mercedes", "fusca", "dodge", "palio", "omega", "kombi", "fiat",
"ford", "dakota", "bmw", "ka", "elba", "gol", "golf", "vectra", "sportage", "idea", "corcel",
"parati", "saveiro", "peuget", "citroen", "toyota", "nissan", "renaut", "frontier",
"honda", "subaru", "corrola", "civic"};
string frutas[NPAL] = {"abacaxi", "banana", "ameixa", "pera", "goiaba", "amora",
"bergamota", "morango", "lima", "abacate", "carambola", "laranja", "kiwi", "tangerina",
"figo", "pitanga", "framboesa", "acerola", "cereja", "nectarina", "pomelo", "caqui",
"caju", "marmelo", "uva","nectarina","damasco","manga","jaca","jabuticaba"};

// --------------------------------------------------------- Classe: Janela

class Janela
{
public:
Janela(void);
~Janela(void);
void clrscr(void);
void gotoxy(int c, int l);
void flushall(void);
int Random(int n);
void randomize(void);
void textcolor(int cor);
void textcolorlight(int cor);
void tempo(int c, int l);
};

// --------------------------------------------------------- Construtor

Janela :: Janela(void)
{
initscr();
keypad(stdscr, TRUE);
(void) nonl();
(void) cbreak();
(void) echo();
if (has_colors())
{
start_color();
init_pair(1,COLOR_RED,COLOR_BLACK);
init_pair(2,COLOR_GREEN,COLOR_BLACK);
init_pair(3,COLOR_YELLOW,COLOR_BLACK);
init_pair(4,COLOR_BLUE,COLOR_BLACK);
init_pair(5,COLOR_CYAN,COLOR_BLACK);
init_pair(6,COLOR_MAGENTA,COLOR_BLACK);
init_pair(7,COLOR_WHITE,COLOR_BLACK);
attrset(COLOR_PAIR(A_BOLD));
}
}

// --------------------------------------------------------- Destrutor

Janela :: ~Janela(void)
{
endwin();
system("clear");
}

// --------------------------------------------------------- Método: clrscr

void Janela :: clrscr(void)


{
clear();
refresh();
}

// --------------------------------------------------------- Método: gotoxy

void Janela :: gotoxy(int c, int l)


{
move(l-1,c-1);
refresh();
}

// --------------------------------------------------------- Método: flushall

void Janela :: flushall(void)


{
getchar();
}

// --------------------------------------------------------- Método: Random

int Janela :: Random(int n)


{
int t = rand() % n;
return(t);
}

// --------------------------------------------------------- Método: randomize


void Janela :: randomize(void)
{
srand((unsigned int)time((time_t *)NULL));
}

// --------------------------------------------------------- Método: textcolor

void Janela :: textcolor(int cor)


{
attrset(COLOR_PAIR(cor));
}

// --------------------------------------------------------- Método: textcolorlight

void Janela :: textcolorlight(int cor)


{
attrset(COLOR_PAIR(cor)+A_BOLD);
}

// --------------------------------------------------------- tempo

void Janela :: tempo(int c, int l)


{
time_t now;
char s[30];

time(&now);
strcpy(s,ctime(&now));
textcolor(COR_RELOGIO);
gotoxy(c,l);
printw("%s",s);
}

// --------------------------------------------------------- Classe: Boneco

class Boneco
{
Janela janela;
int col, lin;

public:
Boneco(int c, int l)
{
col = c;
lin = l;
}
void Monta_Boneco(int erro)
{
switch (erro)
{
case 1: janela.gotoxy(col,lin);
printw(" O");
break;
case 2: janela.gotoxy(col,lin+1);
printw("/|");
break;
case 3: janela.gotoxy(col,lin+1);
printw("/|\\");
break;
case 4: janela.gotoxy(col,lin+2);
printw("/");
break;
case 5: janela.gotoxy(col,lin+2);
printw("/ \\");
break;
}
}
};

// --------------------------------------------------------- Classe: Tela

class Tela
{
public:
void Monta_Tela(void);
void Relogio(int *h, int *m, int *s);
};

// --------------------------------------------------------- Monta_Tela

void Tela :: Monta_Tela(void)


{
Janela janela;

janela.textcolor(COR_TITULO);
janela.gotoxy(33,1);
printw("Jogo da Forca",199);
janela.gotoxy(2,22);
printw("[ESC] Abandona");
refresh();
janela.textcolorlight(COR_LETRAS);
janela.gotoxy(16,20);
printw("A B C D E F G H I J K L M N O P Q R S T U V W X Y Z");
janela.tempo(56,1);
}

// --------------------------------------------------------- Relogio

void Tela :: Relogio(int *h, int *m, int *s)


{
time_t now;
char st[30],temp[5];

time(&now);
strcpy(st,ctime(&now));
int x = 0;
for (int i = 11;i <= 12;i++)
{
temp[x] = st[i];
x++;
}
temp[x] = (char) NULL;
*h = atoi(temp);
x = 0;
for (int i = 14;i <= 15;i++)
{
temp[x] = st[i];
x++;
}
temp[x] = (char) NULL;
*m = atoi(temp);
x = 0;
for (int i = 17;i <= 18;i++)
{
temp[x] = st[i];
x++;
}
temp[x] = (char) NULL;
*s = atoi(temp);
}

// ---------------------------------------------------- Classe: Jogo

class Jogo
{
Janela janela;
Tela tela;
public:
void Jogar(void);
};

// ---------------------------------------------------- Método: Jogar

void Jogo :: Jogar(void)


{
Boneco boneco(60,10);
int tecla;
int hi, mi, si;
int ma, sa;
int ht, mt, st;
string palavra;
char vetor[26],s[10];
int row, col;

getmaxyx(stdscr, row, col);// tamanho do terminal


do {
char ch = 'A';
int acertos = 0;
int total = 0;
int erros = 0;
bool sai = false;
bool incrementa = false;
bool click = false;
int c = 16;
int l = 20;
hi = mi = si = 0;
janela.clrscr();
janela.textcolor(WHITE);
janela.gotoxy(60,24);
printw("| row: %d | col: %d |",row,col);
janela.randomize();
janela.textcolor(COR_TEXTO);
tela.Monta_Tela();
for (int i = 0;i <= 25;i++)
vetor[i] = '*';
tela.Relogio(&hi,&mi,&si);
int ma = 0;
int j = janela.Random(NPAL);
int m = janela.Random(NTIPOS);
switch (m)
{
case 0: palavra = cidades[j];
break;
case 1: palavra = paises[j];
break;
case 2: palavra = carros[j];
break;
case 3: palavra = frutas[j];
break;
}
janela.textcolor(GREEN);
janela.gotoxy(1,1);
printw("Tipo: ");
janela.textcolorlight(GREEN);
janela.gotoxy(7,1);
cout << nomes[m];
int n = palavra.length();
janela.gotoxy(20,10);
cout << "PALAVRA: ";
for (int i = 0;i < n;i++)
printw("_ ");
janela.textcolorlight(BROWN);
janela.gotoxy(1,4);
printw("Acertos: ");
janela.gotoxy(1,5);
printw(" Erros: ");
do {
tela.Relogio(&ht,&mt,&st);
janela.textcolorlight(COR_STATUS);
janela.gotoxy(10,4);
printw("%d",acertos);
janela.gotoxy(10,5);
printw("%d",erros);
sa = st - si;
if (sa < 0)
sa = sa + 60;
if (sa == 58)
incrementa = true;
if (sa == 0 and incrementa)
{
ma++;
incrementa = false;
}
janela.textcolor(COR_TEMPO);
janela.gotoxy(30,22);
printw("Tempo Gasto: %02d:%02d\n",ma,sa);
janela.gotoxy(c,l);
tecla = getch();
if (tecla == ESC)
sai = true;
janela.textcolor(COR_TEMPO);
janela.gotoxy(30,22);
printw("Tempo Gasto: %02d:%02d\n",ma,sa);
janela.textcolor(COR_RELOGIO);
janela.tempo(56,1);
switch (tecla)
{
case LEFT: c-=2;
ch--;
if (c < 16)
{
c = 66;
ch = 'Z';
}
break;
case RIGHT: c+=2;
ch++;
if (c > 66)
{
c = 16;
ch = 'A';
}
break;
case ENTER:
case SPACE: janela.textcolor(COR_LETRAS);
janela.gotoxy(34,18);
printw("Caracter: [%c]",ch);
janela.textcolorlight(GREEN);
janela.gotoxy(c,l);
printw("%c",ch);
janela.textcolor(COR_SELECAO);
col = 29;
int lin = 10;
bool acertou = false;
int k = ch - 65;
for (int i = 0;i < n;i++)
{
if (toupper(palavra[i]) == ch)
{
janela.gotoxy(col,lin);
printw("%c",ch);
if (not acertou and vetor[k] == '*')
acertos++;
total++;
vetor[k] = '#';
acertou = true;
}
col = col + 2;
}
if (not acertou and vetor[k] == '*')
{
erros++;
vetor[k] = '#';
}
boneco.Monta_Boneco(erros);
if (total == n)
{
janela.textcolor(COR_WINNER);
janela.gotoxy(50,10);
printw("(Winner)");
janela.gotoxy(30,24);
sai = true;
printw("Jogar Novamente [S/n]? ");
do {
tecla = getch();
} while(not strchr("SsNn",tecla) and tecla not_eq ESC);
}
break;
}
if (erros == 5)
{
janela.textcolorlight(RED);
janela.gotoxy(34,14);
cout << palavra;
janela.textcolor(COR_WINNER);
janela.gotoxy(50,10);
printw("(Looser)");
janela.gotoxy(30,24);
sai = true;
printw("Jogar Novamente [S/n]? ");
do {
tecla = getch();
} while(not strchr("SsNn",tecla) and tecla not_eq ESC);
}
} while (not sai);
} while (strchr("Ss",tecla) and tecla not_eq ESC);
}

// ------------------------------------------ Programa Principal

int main(void)
{
Jogo jogo;
jogo.Jogar();
}

10. Classes pré-definidas do C++


10.1 Classe <string>

C++ possui uma classe string que permite a manipulação de


cadeias de caracteres através de um conjunto de métodos e operadores
sobrecarregados desta classe.

Formas de declarar uma string:

Programa exemplo (108): O programa string8.cpp, a seguir, mostra


várias formas de declarar e inicializar um objeto string.

// string8.cpp

#include <iostream>
#include <string>

using namespace std;

int main(void)
{
string s; // s foi inicializada com ""
string r("UCPel"); // r foi inicializado com "UCPel"
string t("UCPel",10); // t foi inicializada com "UCPel" , total de 10 caracteres
string w = "Universidade"; // w foi inicializado com "Universidade"
string s1(r); // s1 foi inicializada com "UCPel"
string s2(r.begin(), r.end()); // s2 foi inicializada com "UCPel"
string s3(10,'x'); // s3 foi inicializada com "xxxxxxxxxx"

s = "flor"; // C++ aceita atribuição para string (ATRIBUIÇÃO)


cout << s << endl; // imprime "flor"
s = s + "es"; // C++ aceita concatenação de strings (CONCATENAÇÃO)
cout << s << endl; // imprime "flores"
cout << r << endl; // imprime "UCPel"
cout << t << endl; // imprime "UCPel" + lixo
cout << w << endl; // imprime "Universidade"
cout << s1 << endl; // imprime "UCPel"
cout << s2 << endl; // imprime "UCPel"
cout << s3 << endl; // imprime "xxxxxxxxxx"
}

Resultado do Programa:
flor
flores
UCPel
UCPelUniv
Universidade
UCPel
UCPel
xxxxxxxxxx

Programa exemplo (109): O programa string9.cpp, a seguir, mostra


a utilização dos métodos: size (exibe o número de caracteres da string),
length (exibe o número de caracteres da string) e max_size (exibe o
tamanho máximo de uma string pode ter) pertencentes a classe string.

Sintaxe: int nome_string.size(void);


Retorno: Número de caracteres da string.

Sintaxe: int nome_string.length(void);


Retorno: Número de caracteres da string.

Sintaxe: int nome_string.max_size(void);


Retorno: Número máximo de caracteres permitido para uma string.

// string9.cpp

#include <iostream>
#include <string>

using namespace std;

int main(void)
{
string s("Universidade");

cout << s.size() << endl; // 12


cout << s.length() << endl; // 12
cout << s.max_size() << endl; // 1073741820
}

Resultado do Programa:

12
12
1073741820

Programa exemplo (110): O programa string10.cpp, a seguir,


mostra a utilização dos métodos: insert (insere caracteres na string na
posição especificada) e length (exibe o número de caracteres da string)
pertencentes a classe string.
Sintaxe: void nome_string.insert(int pos, string str);
Onde: pos é a posição da inserção e str é a string que será inserida na
posição.

// string10.cpp

#include <iostream>
#include <string>

using namespace std;

int main(void)
{
string s("Universdade");

cout << s << endl;


s.insert(7,"i");
cout << s << endl;
s.insert(s.length(),"s");
cout << s << endl;
}

Resultado do Programa:

Universdade
Universidade
Universidades

Programa exemplo (111): O programa string11.cpp, a seguir,


mostra a utilização do método: replace (troca n caracteres da string)
pertencente a classe string.

Sintaxe: void nome_string.replace(int pos, int n, string str);


Onde: pos é a posição da troca, n é número de caracteres trocados e
str é a string que será colocada na posição da troca.

// string11.cpp

#include <iostream>
#include <string>

using namespace std;

int main(void)
{
string s("Universidade");

cout << s << endl;


s.replace(7,5,"o");
cout << s << endl;
}
Resultado do Programa:

Universidade
Universo

Programa exemplo (112): O programa string12.cpp, a seguir,


mostra a utilização do método: c_str (converte string C++ para string C)
pertencente a classe string.

Sintaxe: char *nome_string.c_str(void);


Retorno: String C padrão.

// string12.cpp

#include <iostream>
#include <string>

using namespace std;

int main(void)
{
string s("Universidade");
char st[30]; // vetor de caracteres – string C padrão

strcpy(st,s.c_str()); // converte string C++ para string padrão C


cout << st << endl;
}

Resultado do Programa:

universidade

Programa exemplo (113): O programa string13.cpp, a seguir,


mostra a utilização dos métodos: find (encontrar a posição de uma
string dentro de outra string – procura da esquerda para direita) e rfind
(encontrar a posição de uma string dentro de outra string – procura da
direita para esquerda) pertencentes a classe string.

Sintaxe: int nome_string.find (string str, int pos);


Onde: str é a string a ser procurada e pos é a posição inicial da busca
(opcional).
Retorno: posição da string str dentro da string (-1 se não for
encontrado).

Sintaxe: int nome_string.rfind(string str, int pos);


Onde: str é a string a ser procurada e pos é a posição inicial da busca
(opcional).
Retorno: posição onde a string str não se encontra na string (-1 se não
for encontrado).

// string15.cpp

#include <iostream>
#include <string>

using namespace std;

int main(void)
{
string s("Universidade");
int i = s.find("a"); // retorna a posição da vogal 'a' (esquerda para direita)
cout << i << endl; // 9
int j = s.rfind("bcd",3); // retorna a posição da primeira destas consoantes (direita para
esquerda)
cout << j << endl; // -1
int k = s.rfind("a"); // retorna a posição da vogal 'a' (direita para esquerda)
cout << k << endl; // 9
}

Resultado do Programa:

9
-1 // fora da faixa
9

Programa exemplo (114): O programa string14.cpp, a seguir,


mostra a utilização dos métodos: find_first_of (encontrar a posição de
uma string dentro de outra string – procura da esquerda para direita) e
find_first_not_of (encontrar a posição de uma string não está dentro de
outra string - procura da esquerda para direita), find_last_of (encontrar
a posição de uma string dentro de outra string – procura da direita para
esquerda) e find_last_not_of (encontrar a posição de uma string não
está dentro de outra string - procura da direita para esquerda)
pertencentes a classe string.

Sintaxe: int nome_string.find_first_of (string str, int pos);


Onde: str é a string a ser procurada e pos é a posição inicial da busca
(opcional).
Retorno: posição da string str dentro da string (-1 se não for
encontrado).

Sintaxe: int nome_string.find_first_not_of (string str, int pos);


Onde: str é a string a ser procurada e pos é a posição inicial da busca
(opcional).
Retorno: posição onde a string str não se encontra na string (-1 se não
for encontrado).
Sintaxe: int nome_string.find_last_of (string str, int pos);
Onde: str é a string a ser procurada e pos é a posição inicial da busca
(opcional).
Retorno: posição da string str dentro da string (-1 se não for
encontrado).

Sintaxe: int nome_string.find_last_not_of (string str, int pos);


Onde: str é a string a ser procurada e pos é a posição inicial da busca
(opcional).
Retorno: posição onde a string str não se encontra na string (-1 se não
for encontrado).

// string14.cpp

#include <iostream>
#include <string>

using namespace std;

int main(void)
{
string s("Universidade");
int i = s.find_first_of("a"); // retorna a posição da vogal 'a'
cout << i << endl; // 9
int j = s.find_first_of("bcd",3); // retorna a posição da primeira consoante a partir da posição 3
'd'
cout << j << endl; // 8
int k = s.find_first_not_of("a"); // exibe a posição do primeiro caracter que não é "aeio" é 'U'
cout << k << endl; // 0
}

Resultado do Programa:

9
8
0

Programa exemplo (115): O programa string15.cpp, a seguir,


mostra a utilização do método: resize (redimensiona uma string
completando com n caracteres) pertencente a classe string.

Sintaxe: void nome_string.resize(int n, char ch);


Onde: n é o novo número de caracteres da string e ch é o caracter que
será usado para completar o tamanho da string (ch é opcional).

// string15.cpp

#include <iostream>
#include <string>
using namespace std;

int main(void)
{
string s(10, 'a');

cout << s << endl;


cout << s.size() << endl << endl;
s.resize(15, 't');
cout << s << endl;
cout << s.size() << endl;
}

Resultado do Programa:

aaaaaaaaaa
10

aaaaaaaaaattttt
15

Programa exemplo (116): O programa string16.cpp, a seguir,


mostra a utilização dos métodos: empty (verifica se uma string está
vazia ou não) e getline (permite a entrada de uma string via teclado)
pertencentes a classe string.

Sintaxe: void nome_string.getline(fluxo, string str);


Onde: fluxo (cin) é um fluxo e str é a string que será lida.

Sintaxe: bool nome_string.empty(void);


Retorno: true vazia e false não vazia.

// string16.cpp

#include <iostream>
#include <string>

using namespace std;

int main(void)
{
string s; // string vazia

if (s.empty()) // verifica se a string está vazia ""


cout << "Digite seu nome: ";
{
// cin >> s; // não aceita espaços
getline(cin, s);
cout << "String: " << s << " -> Tamanho: " << s.size() << endl;
}
else
cout << "String não está vazia" << endl;
// cin.getline(s,80); não funciona para string
}

Resultado do Programa:

Digite seu nome: Paulo Roberto


String: Paulo Roberto -> Tamanho: 13

Programa exemplo (117): O programa string17.cpp, a seguir,


mostra a utilização do método: swap (permite fazer uma troca de
valores entre duas strings) pertencente a classe string.

Sintaxe: nome_string.swap(string str);


Onde: str é uma das strings que serão trocadas (a outra é
nome_string).

// string17.cpp

#include <iostream>
#include <string>

using namespace std;

int main(void)
{
string s("Paulo"),r("Roberto");

cout << "s é " << s << " -> r é " << r << endl;
r.swap(s);
cout << "s é " << s << " -> r é " << r << endl;
}

Resultado do Programa:

s é Paulo -> r é Roberto


s é Roberto -> r é Paulo

Programa exemplo (118): O programa string18.cpp, a seguir,


mostra a utilização do método: substr (permite criar uma substring de
uma string) pertencente a classe string, além de demonstrar que uma
string pode ser acessada caracter a caracter, ou seja, como se fosse um
vetor de caracteres.

Sintaxe: string nome_string.substr(int pos);


Onde: pos é a posição aonde começa a substring.

// string18.cpp
#include <iostream>
#include <string>

using namespace std;

int main(void)
{
string s("C++ for Linux");
string r;

for (int i = 0;i < s.length();i++)


cout << s[i];
cout << endl;
r = s.substr(4);
cout << r << endl;
}

Resultado do Programa:

C++ for Linux


for Linux

10.2 Classe <vector>

A classe vector é um tipo de container que faz parte da STL


(Standart Template Library). A STL é uma biblioteca de objetos que
tem as seguintes características: a) não usar polimorfismo por causa do
desempenho; b) utiliza templates (classes genéricas, também chamados
de gabaritos) e c) possui três conceitos básicos: container’s,
iteradores (ponteiros inteligentes para os container's) e código
genérico (templates).

Container é um grupo de objetos do mesmo tipo.

Existem três diferentes tipos de containers: seqüenciais,


associativos e adaptativos. Cada container possui: nome,
características básicas e iteradores.

Seqüenciais: vector, list e deque.


Associativos: set, multiset, map e multimap.
Adaptativos: stack e queue.

vector: Vetores.
list: Lista duplamente encadeada.
deque: Fila de duas extremidades.
set: Conjunto de chaves sem repetição.
multiset: Conjunto de chaves com repetição.
map: Conjunto de pares [chave, objeto] sem repetições.
multimap: Conjunto de pares [chave, objeto] com repetições.
stack: Pilha.
queue: Fila.

Programa exemplo (119): O programa vector1.cpp, a seguir, mostra


a utilização dos métodos comuns a todos os containers: size,
push_back, front, back, empty, max_size e clear pertencentes a
classe vector.

size: Retorna o número de elementos utilizados.


Sintaxe: int nome_container.size(void);
Retorno: Número de elementos.

push_back: Insere um elemento no final do vetor.


Sintaxe: void nome_container.push_back(tipo data);

front: Retorna o primeiro elemento do vetor.


Sintaxe: tipo_vetor nome_container.front(void);
Retorno: Primeiro elemento do vetor

back: Retorna o último elemento do vetor.


Sintaxe: tipo_vetor nome_container.back(void);
Retorno: Último elemento do vetor

empty: Retorna true se o container estiver vazio.


Sintaxe: bool nome_container.empty(void);
Retorno: true se vazio e false se não estiver vazio

max_size: Retorna o número máximo de elementos do container.


Sintaxe: int nome_container.max_size(void);
Retorno: Número máximo de elementos do vetor.

clear: Apaga todos os elementos do container.


Sintaxe: void nome_container.clear(void);

// vector.cpp

#include <iostream>
#include <vector>

using namespace std;

int main (void)


{
vector <float> v; // declaração de um vetor
float data ;
cout << "[0] - Abandonar" << endl;
do {
cout << "Vetor [" << v.size() << "]: "; // 0, 1, 2, 3 ...
cin >> data;
cin.ignore(1,'\n'); // eliminar o enter
if (cin.good() and data not_eq 0)
v.push_back(data);
} while (cin.good() and data not_eq 0.0);
cout << "Primeiro elemento do vetor = " << v.front() << endl;
cout "Último elemento do vetor = " << v.back() << endl;
cout << "Elementos: ";
for (int i = 0; i < v.size();i++)
cout << "v[" << i << "]= " << v[i] << ' '; // indexando um vetor
cout << endl;
cout << (v.empty() ? "Status: Vetor Vazio " : "Status: Vetor não Vazio ") << endl ;
v.clear(); // igual a v.erase(v.begin(),v.end());
cout << (v.empty() ? "Status: Vetor Vazio " : "Status: Vetor não vazio ") << endl ;
cout << endl;
}

Demais métodos básicos utilizados pelos container's:

begin: Retorna um iterador para o primeiro elemento do vetor.


Sintaxe: tipo_container nome_container.begin(void);
Retorno: Ponteiro para o primeiro elemento.

end: Retorna um iterador para o último elemento do vetor.


Sintaxe: tipo_container nome_container.end(void);
Retorno: Ponteiro para o último elemento.

erase: Apaga um ou mais elementos do vetor.


Sintaxe: void nome_container.erase(begin, end);
Exemplo: vetor.erase(vetor.begin(),vetor.end());

pop_back: Remove o último elemento do vetor.


Sintaxe: void nome_container.pop_back(void);

Programa exemplo (120): O programa vector2.cpp, a seguir,


demonstra a utilização da classe vector para armazenar strings da
classe string.

// vector2.cpp

#include <iostream>
#include <string>
#include <vector>

using namespace std;


int main (void)
{
vector <string> v;
string data;

cout << "[enter] parar" << endl;


do {
cout << "Palavra: ";
getline(cin,data);
if (cin.good() and data not_eq "")
v.push_back(data);
} while (cin.good() and data not_eq "");
cout << "Palavras Digitados: " << endl;
for (int i = 0; i < v.size();i++)
cout << v[i] << endl;
int n = v.size();
cout << "Número de Palavras: " << n << endl;
int u = n - 1;
bool trocou;
string tmp;
do {
trocou = false;
for (int i = 0;i < u;i++)
if (v[i] > v[i+1])
{
tmp = v[i];
v[i] = v[i+1];
v[i+1] = tmp;
trocou = true;
}
u--;
} while (trocou);
cout << "Palavras Ordenadas: " << endl;
for (int i = 0; i < v.size();i++)
cout << v[i] << endl;
}

Resultado do Programa:

[enter] parar
Palavra: Carla
Palavra: Debora
Palavra: Ana
Palavra: Beatriz
Palavra:
Palavras Digitados:
Carla
Debora
Ana
Beatriz
Número de Palavras: 4
Palavras Ordenadas:
Ana
Beatriz
Carla
Debora
11. Tabela ASCII
ASCII: Americam Standard Code for Information Interchange.
url: http://www.asciitable.com

Para imprimir caracteres especiais através do C++ for Linux é


necessário enviar para a tela, com a função printf ou cout, o seguinte:

Função: printf("%c%c%c\n", 14, 106, 15);

Função: cout << (char) 14 << (char) cod << (char) 15;

Programa exemplo (121): O programa exemplo asctable.cpp, abaixo,


exibe toda a tabela ascii, inclusive com os caracteres espaciais.

// asctable.cpp

#include <iostream>

using namespace std;

int main(void)
{
for (int cod = 32;cod <= 255;cod++)
{
cout << "Código: " << cod << "-> Caracter: " << (char) 14 << (char) cod <<
(char) 15;
cin.get();
}
}

Programa exemplo (122): O programa exemplo table.cpp, abaixo,


mostra como imprimir um retângulo (moldura) na tela em modo texto
utilizando caracteres espaciais e utilizando a biblioteca ncurses.

// table.cpp (Ubuntu 6.06 Dapper- Anjuta)

// --------------------------------------------------------- includes

#include <iostream>
#include <string>
#include <curses.h>

using namespace std;

// --------------------------------------------------------- constantes

const int LEFT = 260;


const int RIGHT = 261;

const char BLACK = COLOR_BLACK;


const char RED = COLOR_BLUE;
const char GREEN = COLOR_GREEN;
const char BROWN = COLOR_YELLOW;
const char BLUE = COLOR_BLUE;
const char MAGENTA = COLOR_MAGENTA;
const char CYAN = COLOR_CYAN;
const char WHITE = COLOR_WHITE;

// --------------------------------------------------------- Classe: Janela

class Janela
{
public:
Janela(void);
~Janela(void);
void clrscr(void);
void gotoxy(int c, int l);
void flushall(void);
int Random(int n);
void randomize(void);
void textcolor(int cor);
void textcolorlight(int cor);
void Moldura(int ci, int li, int cf, int lf, int cor);
};

// --------------------------------------------------------- Construtor

Janela :: Janela(void)
{
initscr();
keypad(stdscr, TRUE);
(void) nonl();
(void) cbreak();
(void) echo();
if (has_colors())
{
start_color();
init_pair(1,COLOR_RED,COLOR_BLACK);
init_pair(2,COLOR_GREEN,COLOR_BLACK);
init_pair(3,COLOR_YELLOW,COLOR_BLACK);
init_pair(4,COLOR_BLUE,COLOR_BLACK);
init_pair(5,COLOR_CYAN,COLOR_BLACK);
init_pair(6,COLOR_MAGENTA,COLOR_BLACK);
init_pair(7,COLOR_WHITE,COLOR_BLACK);
attrset(COLOR_PAIR(A_BOLD));
}
}

// --------------------------------------------------------- Destrutor

Janela :: ~Janela(void)
{
endwin();
system("clear");
}

// --------------------------------------------------------- Método: clrscr

void Janela :: clrscr(void)


{
clear();
refresh();
}

// --------------------------------------------------------- Método: gotoxy

void Janela :: gotoxy(int c, int l)


{
move(l-1,c-1);
refresh();
}

// --------------------------------------------------------- Método: flushall

void Janela :: flushall(void)


{
getchar();
}

// --------------------------------------------------------- Método: Random

int Janela :: Random(int n)


{
int t = rand() % n;
return(t);
}

// --------------------------------------------------------- Método: randomize

void Janela :: randomize(void)


{
srand((unsigned int)time((time_t *)NULL));
}

// --------------------------------------------------------- Método: textcolor

void Janela :: textcolor(int cor)


{
attrset(COLOR_PAIR(cor));
}

// --------------------------------------------------------- Método: textcolorlight


void Janela :: textcolorlight(int cor)
{
attrset(COLOR_PAIR(cor)+A_BOLD);
}

// --------------------------------------------------------- Método: Moldura

void Janela :: Moldura(int ci, int li, int cf, int lf, int cor)
{
textcolor(cor);
for (int l = li+1;l < lf;l++)
{
gotoxy(ci,l);ldur
printf("%c%c%c",14,120,15);
gotoxy(cf,l);
printf("%c%c%c",14,120,15);
refresh();
}
for (int c = ci+1;c < cf;c++)
{
gotoxy(c,li);
printf("%c%c%c",14,113,15);
gotoxy(c,lf);
printf("%c%c%c",14,113,15);
refresh();
}
gotoxy(ci,li);
printf("%c%c%c",14,108,15);
gotoxy(cf,li);
printf("%c%c%c",14,107,15);
gotoxy(cf,lf);
printf("%c%c%c",14,106,15);
gotoxy(ci,lf);
printf("%c%c%c",14,109,15);
refresh();
}

// --------------------------------------------------------- main

int main(void)
{
Janela janela;

janela.Moldura(10, 10, 20, 20, BLUE);


getch();
}

Programa exemplo (123): O programa exemplo TiroAlvo.cpp,


abaixo, demonstra um jogo de tiro ao alvo escrito em C++ utilizando a
biblioteca ncurses.

Tela do Jogo
// TiroAlvo.cpp (Ubuntu 6.06 Dapper- Anjuta)
// Autor: Paulo Roberto Gomes Luzzardi
// Data: 11/08/2006

// --------------------------------------------------------- includes

#include <iostream>
#include <string>
#include <curses.h>

using namespace std;

// --------------------------------------------------------- constantes

const char ESC = 27;


const char SPACE = 32;

const int DOWN = 258;


const int UP = 259;
const int LEFT = 260;
const int RIGHT = 261;

const char BLACK = COLOR_BLACK;


const char RED = COLOR_BLUE;
const char GREEN = COLOR_GREEN;
const char BROWN = COLOR_YELLOW;
const char BLUE = COLOR_BLUE;
const char MAGENTA = COLOR_MAGENTA;
const char CYAN = COLOR_CYAN;
const char WHITE = COLOR_WHITE;

// --------------------------------------------------------- Classe: Janela

class Janela
{
public:
Janela(void);
~Janela(void);
void clrscr(void);
void gotoxy(int c, int l);
void flushall(void);
int Random(int n);
void randomize(void);
void textcolor(int cor);
void textcolorlight(int cor);
};

// --------------------------------------------------------- Construtor

Janela :: Janela(void)
{
initscr();
keypad(stdscr, TRUE);
(void) nonl();
(void) cbreak();
(void) echo();
if (has_colors())
{
start_color();
init_pair(1,COLOR_RED,COLOR_BLACK);
init_pair(2,COLOR_GREEN,COLOR_BLACK);
init_pair(3,COLOR_YELLOW,COLOR_BLACK);
init_pair(4,COLOR_BLUE,COLOR_BLACK);
init_pair(5,COLOR_CYAN,COLOR_BLACK);
init_pair(6,COLOR_MAGENTA,COLOR_BLACK);
init_pair(7,COLOR_WHITE,COLOR_BLACK);
attrset(COLOR_PAIR(A_BOLD));
}
}

// --------------------------------------------------------- Destrutor

Janela :: ~Janela(void)
{
endwin();
system("clear");
}

// --------------------------------------------------------- Método: clrscr

void Janela :: clrscr(void)


{
clear();
refresh();
}

// --------------------------------------------------------- Método: gotoxy

void Janela :: gotoxy(int c, int l)


{
move(l-1,c-1);
refresh();
}

// --------------------------------------------------------- Método: flushall

void Janela :: flushall(void)


{
getchar();
}

// --------------------------------------------------------- Método: Random

int Janela :: Random(int n)


{
int t = rand() % n;
return(t);
}

// --------------------------------------------------------- Método: randomize

void Janela :: randomize(void)


{
srand((unsigned int)time((time_t *)NULL));
}

// --------------------------------------------------------- Método: textcolor

void Janela :: textcolor(int cor)


{
attrset(COLOR_PAIR(cor));
}

// --------------------------------------------------------- Método: textcolorlight

void Janela :: textcolorlight(int cor)


{
attrset(COLOR_PAIR(cor)+A_BOLD);
}

// --------------------------------------------------------- Classe: Tela

class Tela
{
public:
void Monta_Tela(void);
};

// --------------------------------------------------------- Monta_Tela

void Tela :: Monta_Tela(void)


{
Janela janela;

janela.textcolor(CYAN);
janela.gotoxy(33,1);
printw("Tiro ao Alvo",199);
janela.gotoxy(2,22);
printw("[ESC] Abandona");
refresh();
}

// ---------------------------------------------------- Classe: Jogo

class Jogo
{
int c, l; // torre
int coluna, linha; // alvo
Janela janela;

public:
Jogo(int col, int lin)
{
c = col;
l = lin;
}
void Jogar(void);
void Insere_Alvo(void);
bool Testa_Alvo(void);
};

// ---------------------------------------------------- Método: Jogar

void Jogo :: Jogar(void)


{
Tela tela;
int row, col;
bool sai;
int tecla;

getmaxyx(stdscr, row, col);// tamanho do terminal


do {
janela.textcolor(WHITE);
janela.gotoxy(60,23);
printw("| Lin: %d | Col: %d |",l,c);
janela.gotoxy(60,24);
printw("| row: %d | col: %d |",row,col);
refresh();
tela.Monta_Tela();
sai = false;
Insere_Alvo();
janela.textcolor(WHITE);
janela.gotoxy(20,23);
printw("Status: ");
do {
janela.gotoxy(c,l);
do {
tecla = getch();
} while (tecla not_eq LEFT and tecla not_eq RIGHT and tecla not_eq ESC and tecla not_eq
SPACE);
for (int j = l-1;j >= 3;j--)
{
janela.textcolor(RED);
janela.gotoxy(c,j);
printw(" ");
}
janela.gotoxy(60,23);
printw("| Lin: %d | Col: %d |",l,c);
janela.gotoxy(c,l);
if (tecla == ESC)
sai = true;
switch (tecla)
{
case LEFT: c--;
if (c < 1)
c = 80;
break;
case RIGHT: c++;
if (c > 80)
c = 1;
break;
case SPACE: for (int j = l-1;j >= 2;j--)
{
janela.textcolor(RED);
janela.gotoxy(c,j);
printw(".");
}
if (Testa_Alvo())
{
janela.textcolor(BROWN);
janela.gotoxy(30,23);
printw("Acertou o Alvo");
Insere_Alvo();
}
else
{
janela.textcolor(RED);
janela.gotoxy(30,23);
printw("Errou o Alvo ");
}
break;
}
} while (not sai);
janela.gotoxy(20,22);
printw("Jogar Novamente [S/n]? ");
do {
tecla = getch();
} while(not strchr("SsNn",tecla) and tecla not_eq ESC);
} while (strchr("Ss",tecla) and tecla not_eq ESC);
}

// --------------------------------------------------------- Insere_Alvo

void Jogo :: Insere_Alvo(void)


{
int col, row;

getmaxyx(stdscr, row, col); // tamanho do terminal


coluna = 1 + janela.Random(col);
linha = 2;
janela.textcolor(RED);
janela.gotoxy(coluna,linha);
printf("%c%c%c",14,97,15);
refresh();
}
// --------------------------------------------------------- Testa_Alvo

bool Jogo :: Testa_Alvo(void)


{
if (coluna == c)
return(true);
else
return(false);
}

// ------------------------------------------ Programa Principal

int main(void)
{
Janela janela;
Jogo jogo(40,20);

jogo.Jogar();
}
12. Glossário
Objetos: São entidades lógicas que possuem atributos
(variáveis) e métodos (funções) que manipulam estas
propriedades.

Atributos: São variáveis definidas e declaradas para cada classe que


definem as propriedades ou características de um objeto.

Métodos: São funções definidas pelo programador que servirão para


manipular os atributos de uma classe.

Classe: É um tipo de dado definido por class ou struct.

Mensagens: São as chamadas dos métodos (chamada das funções), ou


seja, solicitações enviadas à objetos para alterar seu estado ou retornar
um valor.

Instância: Os objetos são instâncias de uma classe.

Abstração: Característica onde os objetos devem representar dados do


mundo real.

Encapsulamento: Característica onde os objetos possuem


internamente atributos e métodos agrupados no mesmo local, onde os
métodos manipulam os atributos.

Herança: Processo pelo qual uma classe de objetos pode adquirir as


propriedades de outra classe de objetos, podendo ser: simples ou
múltipla.

Herança simples: Quando uma classe herda as propriedades de


uma única classe base.

Herança múltipla: Quando uma classe herda as propriedades de mais


de uma classe base.

Polimorfismo: É a capacidade de objetos diferentes reagirem segundo


a sua função a uma ordem padrão, ou seja, o nome de um objeto pode
ser utilizado para vários propósitos ligeiramente diferentes. “ ... uma
interface, vários métodos ... ” . O polimorfismo ocorre na sobrecarga
de funções e sobrecarga de operadores.

Templates (gabaritos): É uma função genérica em que o tipo dos dados


(dos parâmetros e do retorno da função) são definidos em tempo de
compilação.

Argumentos: Parâmetros formais de funções ou métodos.

Construtor: Método especial, que tem o mesmo nome da classe, que é


executado quando o objeto é declarado servindo para inicializar os
atributos de um objeto.

Destrutor: Método especial, que tem o mesmo nome da classe mais um


~, que é executado quando o programa termina ou quando o objeto é
desalocado.

Classe base: Classe principal que possui as características básicas de


uma classe de objetos (propriedades básicas).

Classe derivada: Classe construída a partir de uma ou mais classes


básicas. Possui as demais características de uma determinada classe de
objetos (propriedades diferentes).

Sobrecarga de funções: Duas ou mais funções, com mesmo nome,


recebem parâmetros de tipos diferente podendo ainda ter retorno
diferentes.

Sobrecarga de operadores: Característica da orientação à objetos


onde um operador (aritmético, relacional, lógico ou bit à bit) passa a ter
novas funções (características) sem perder a função básica.

Ponteiros: Variável que possui como valor um endereço de memória.

Referências: São variáveis que ficam vinculadas diretamente à


localização de memória de uma expressão. Uma referência não é
alocada na memória, ou seja, não ocupa espaço de memória.

Hierarquia de objetos: É um diagrama que exibe o relacionamento


entre objetos ou classes de objetos.

Funções amigas: Permitem o compartilhamento de métodos e


atributos para métodos que não fazem parte de uma classe.

Função virtual: Método especial executado por meio de uma referência


a uma classe base e carregado dinamicamente em tempo de execução
em classes derivadas.

this: Ponteiro criado automaticamente que aponta para cada método de


uma classe. É utilizado para solucionar conflitos entre identificadores.
Threads: Representam uma seqüência de instruções única (processo),
executada paralelamente a outras seqüências de instruções, tanto por
particionamento do tempo, como por multiprocessamento (ou
multithread). Uma thread é uma forma de um programa dividir a si
mesmo em duas ou mais tarefas simultâneas.
13. Arquivos em C++
Em C++, um arquivo é tratado como um fluxo de bytes, ou seja,
não possui formato definido, o programador deve criar um formato aos
dados. O fluxo para trabalhar com arquivos é <fstream.h> ou
simplesmente <fstream>.

Modo Descrição
ios :: app Insere no fim do arquivo.
ios :: ate Abre um arquivo para gravação no fim do arquivo.
ios :: in Abre um arquivo de entrada.
ios :: out Abre um arquivo de saída.
ios :: trunc Elimina o contéudo do arquivo, se ele existe.
ios :: binary Abre um arquivo binário para entrada ou saída.

Programa exemplo (124): O programa exemplo gravar.cpp, abaixo,


demonstra a gravação de palavras (strings) em um arquivo qualquer.

// gravar.cpp

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

int main (void)


{
ofstream file; // cria o arquivo file para gravação (out)
string palavra;
char nome[256];

cout << "Nome do Arquivo: ";


cin >> nome;
file.open(nome, ios::app); // abre o arquivo, insere no fim
if (file.fail())
{
cout << "ERRO: Arquivo Inexistente" << endl;
return(1);
}
cin.ignore(1,'\n'); // limpa o buffer de teclado
do {
cout << "Palavra: ";
getline(cin,palavra); // leitura de uma string via teclado
if (not palavra.empty())
file << palavra << endl; // grava uma palavra no arquivo
} while (not palavra.empty());
file.close() ; // fecha o arquivo
}
Programa exemplo (125): O programa exemplo ler.cpp, abaixo,
demonstra a leitura de palavras (string) de um arquivo qualquer.

// ler.cpp

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

int main (void)


{
ifstream file; // liga o arquivo file para leitura (in)
string palavra;
char nome[256];

cout << "Nome do Arquivo: ";


cin >> nome;
file.open(nome);
if (file.fail())
{
cout << "ERRO: Arquivo Inexistente" << endl;
return(1);
}
cin.ignore(1,'\n');
do {
getline(file,palavra); // leitura de uma string do arquivo file
cout << "Palavra: " << palavra << endl;
} while (not palavra.empty());
file.close() ;
}

Programa exemplo (126): O programa exemplo gravar_texto.cpp,


abaixo, demonstra a gravação de texto (linha a linha) em um arquivo
qualquer.

// gravar_texto.cpp

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

#define end_of_line '\a'

int main (void)


{
ofstream file; // cria o arquivo file para gravação (out)
string linha;
char nome[256];

cout << "Nome do Arquivo: ";


cin >> nome;
file.open(nome, ios::app); // abre o arquivo, insere no fim
if (file.fail())
{
cout << "ERRO: Arquivo Inexistente" << endl;
return(1);
}
cin.ignore(1,'\n'); // limpa o buffer de teclado
cout << "Digite um texto qualquer: " << endl;
do {
getline(cin, linha); // leitura de uma string via teclado
if (not linha.empty())
file << linha << end_of_line << endl; // grava uma palavra no arquivo
} while (not linha.empty());
file.close() ; // fecha o arquivo
}

Programa exemplo (127): O programa exemplo ler_texto.cpp,


abaixo, demonstra a leitura de um arquivo contento texto, caracter por
caracter.

// ler_texto.cpp

#include <iostream>
#include <fstream>
#include <string>

#define end_of_line '\a' // caracter finalizador, escolher um

using namespace std;

int main (void)


{
ifstream file; // liga o arquivo file para leitura (in)
string linha;
char nome[256], str[256];

cout << "Nome do Arquivo: ";


cin >> nome;
file.open(nome);
if (file.fail())
{
cout << "ERRO: Arquivo Inexistente" << endl;
return(1);
}
cin.ignore(1,'\n');
do {
getline(file,linha); // leitura de uma linha do arquivo
strcpy(str,linha.c_str());
for (int i = 0;i < strlen(str);i++)
if (str[i] == end_of_line)
cout << endl;
else
cout << str[i];
} while (not linha.empty());
file.close() ;
}

Programa exemplo (128): O programa exemplo gravar_string.cpp,


abaixo, demonstra a gravação de strings (classe string) em um
arquivo qualquer.

// gravar_string.cpp

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

int main (void)


{
ofstream file; // cria o arquivo file para gravação (out)
char nome[256], palavra[31];

cout << "Nome do Arquivo: ";


cin >> nome;
file.open(nome); // abre o arquivo
if (file.fail())
{
cout << "ERRO: Arquivo Inexistente" << endl;
return(1);
}
cin.ignore(1,'\n'); // limpa o buffer de teclado
do {
cout << "Palavra: ";
cin.getline(palavra, 30); // leitura de uma string via teclado
if (strcmp(palavra,"") not_eq 0)
file << palavra << endl; // grava uma palavra no arquivo
} while (strcmp(palavra,"") not_eq 0);
file.close() ; // fecha o arquivo
}

Resultado do Programa:

Nome do Arquivo: palavra.dat


Palavra: abacate
Palavra: abacaxi
Palavra: ameixa
Palavra: laranja
Palavra: bergamota
Palavra: pitanga
Palavra:

Programa exemplo (129): O programa exemplo ler_string.cpp,


abaixo, demonstra a leitura de strings (classe string) exibindo a
posição do ponteiro get em um arquivo qualquer (existe um ponteiro
put (para o fluxo ofstream) e o ponteiro get (para o fluxo ifstream)).

// ler_string.cpp

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

int main (void)


{
ifstream file; // abre o arquivo file para leitura (in)
char nome[256],palavra[31];

cout << "Nome do Arquivo: ";


cin >> nome;
file.open(nome); // abre o arquivo
if (file.fail())
{
cout << "ERRO: Arquivo Inexistente" << endl;
return(1);
}
cin.ignore(1,'\n'); // limpa o buffer de teclado
long pos_get;
do {
pos_get = file.tellg(); // retorna a posição do ponteiro get
file >> palavra;
if (file)
cout << "Posição: " << pos_get << " -> Palavra: " << palavra << endl;
} while (file);
file.close() ; // fecha o arquivo
}

Resultado do Programa:

Nome do Arquivo: palavra.dat


Posição: 0 -> Palavra: abacate
Posição: 7 -> Palavra: abacaxi
Posição: 15 -> Palavra: ameixa
Posição: 22 -> Palavra: laranja
Posição: 30 -> Palavra: bergamota
Posição: 40 -> Palavra: pitanga

Programa exemplo (130): O programa exemplo gravar_int.cpp,


abaixo, demonstra a gravação de números inteiros em um arquivo
qualquer.

// gravar_int.cpp

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

int main (void)


{
ofstream file; // fluxo de gravação (out)
int idade;
char nome[256];

cout << "Nome do Arquivo: ";


cin >> nome;
file.open(nome, ios::app); // abre e anexa no fim do arquivo
if (file.fail())
{
cout << "ERRO: Arquivo não Existe" << endl;
return(1);
}
cin.ignore(1,'\n'); // elimina um enter do buffer de teclado
do {
cout << "Idade: ";
cin >> idade; // leitura de uma idade via teclado
if (idade not_eq 0)
file << idade << endl; // grava uma idade no arquivo
} while (idade not_eq 0);
file.close() ;
}

Programa exemplo (131): O programa exemplo ler_int.cpp, abaixo,


demonstra a leitura de números inteiros em um arquivo qualquer.

// ler_int.cpp

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

int main (void)


{
ifstream file; // fluxo de leitura
int idade;
char nome[256];
cout << "Nome do Arquivo: ";
cin >> nome;
file.open(nome);
if (file.fail())
{
cout << "ERRO: Arquivo Inexistente" << endl;
return(1);
}
cin.ignore(1,'\n');
do {
file >> idade; // leitura de uma idade do arquivo
if (file)
cout << "Idade: " << idade << endl;
} while (file);
file.close() ;
}

Programa exemplo (132): O programa exemplo gravar_float.cpp,


abaixo, demonstra a gravação de números reais (float) em um arquivo
qualquer.

// gravar_float.cpp

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

int main (void)


{
ofstream file; // fluxo de gravação (out)
float salario;
char nome[256];

cout << "Nome do Arquivo: ";


cin >> nome;
file.open(nome, ios::app); // abre e anexa no fim do arquivo
if (file.fail())
{
cout << "ERRO: Arquivo não Existe" << endl;
return(1);
}
cin.ignore(1,'\n');
do {
cout << "Salário: ";
cin >> salario;
if (salario not_eq 0.0)
file << salario << endl;
} while (salario not_eq 0.0);
file.close() ;
}
Programa exemplo (133): O programa exemplo ler_float.cpp,
abaixo, demonstra a leitura de números reais (float) em um arquivo
qualquer.

// ler_float.cpp

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

int main (void)


{
ifstream file; // fluxo de leitura
float salario;
char nome[256];

cout << "Nome do Arquivo: ";


cin >> nome;
file.open(nome);
if (file.fail())
{
cout << "ERRO: Arquivo Inexistente" << endl;
return(1);
}
cin.ignore(1,'\n');
do {
file >> salario;
if (file)
cout << "Salário: " << salario << endl;
} while (file); // verdadeiro enquanto existir dados
file.close() ;
}

Programa exemplo (134): O programa exemplo gravar_struct.cpp,


abaixo, demonstra a gravação de uma estrutura (struct) com: nome
(string), idade (int), mesada (float) e sexo (char) em um arquivo
qualquer.

// gravar_struct.cpp

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

struct REG {
string nome;
int idade;
float mesada;
char sexo; // [M]asculino ou [F]eminino
} reg;

int main (void)


{
ofstream file; // fluxo de gravação (out)
char nome[256], ch;

cout << "Nome do Arquivo: ";


cin >> nome;
file.open(nome, ios::app); // abre e anexa no fim do arquivo
if (file.fail())
{
cout << "ERRO: Arquivo não Existe" << endl;
return(1);
}
cin.ignore(1,'\n');
do {
cout << "Nome: ";
getline(cin,reg.nome);
cout << "Idade: ";
cin >> reg.idade;
cout << "Mesada: ";
cin >> reg.mesada;
cout << "Sexo [M]asculino ou [F]eminino: ";
do {
reg.sexo = cin.get();
} while (not strchr("FfMm",reg.sexo));
file << reg.nome << endl;
file << reg.idade << endl;
file << reg.mesada << endl;
file << reg.sexo << endl;
cout << "Continua [S/N]? ";
do {
ch = cin.get();
} while (not strchr("SsNn",ch));
cin.ignore(5,'\n');
} while (strchr("Ss",ch));
file.close() ;
}

Resultado do Programa:

Nome do Arquivo: pessoas.dat <enter>


Nome: Paulo Roberto <enter>
Idade: 44 <enter>
Mesada: 1234.56 <enter>
Sexo: m
Continua [S/N/? s
Nome: Adriane Maria <enter>
Idade: 37 <enter>
Mesada: 2345.67 <enter>
Sexo: f
Continua [S/N/? s
Nome: Paola de Freitas Luzzardi <enter>
Idade: 7 <enter>
Mesada: 12.34 <enter>
Sexo: f
Continua [S/N/? n

Programa exemplo (135): O programa exemplo ler_struct.cpp,


abaixo, demonstra a leitura de uma estrutura (struct) com: nome
(string), idade (int), mesada (float) e sexo (char) em um arquivo
qualquer.

// lerr_struct.cpp

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

struct REG {
string nome;
int idade;
float mesada;
char sexo; // [M]asculino ou [F]eminino
} reg;

int main (void)


{
ifstream file; // fluxo de leitura (in)
char nome[256], ch;

cout << "Nome do Arquivo: ";


cin >> nome;
file.open(nome); // abre o arquivo
if (file.fail())
{
cout << "ERRO: Arquivo não Existe" << endl;
return(1);
}
cin.ignore(1,'\n');
do {
getline(file,reg.nome);
file >> reg.idade;
file >> reg.mesada;
file >> reg.sexo;
file.ignore(1,'\n');
cout << "Nome: " << reg.nome << endl;
cout << "Idade: " << reg.idade << endl;
cout << "Mesada: " << reg.mesada << endl;
cout << "Sexo: " << reg.sexo << endl;
} while (file); // verdadeiro enquanto tiver dados
file.close() ;
}

Resultado do Programa:
Nome do Arquivo: pessoas.dat
Nome: Paulo Roberto
Idade: 44
Mesada: 1234.56
Sexo: m
Nome: Adriane Maria
Idade: 37
Mesada: 2345.67
Sexo: f
Nome: Paola de Freitas Luzzardi
Idade: 7
Mesada: 12.34
Sexo: f

Programa exemplo (136): O programa exemplo gravar_object.cpp,


abaixo, demonstra a gravação de um objeto (class) que possui dois
atributos inteiros: x e y em um arquivo qualquer.

// gravar_objeto.cpp

#include <iostream>
#include <fstream>
#include <string>
#include <vector>

using namespace std ;

class Data
{
int x,y;
public :
Data(int tx, int ty)
{
x = tx;
y = ty;
}
friend istream &operator >> (istream &file, Data &data);
friend ofstream &operator << (ofstream &file, Data *&data);
};

int main (void)


{
cout << "Nome do Arquivo: ";
string nome; // ou char nome[256];
getline(cin, nome);
ofstream file(nome.c_str()); // converte string para char *
if (not file)
{
cout << "ERRO: Arquivo não Existe\n";
exit(1) ;
}
vector <Data> data;
Data objeto(0,0);
Data *pobjeto ;
pobjeto = &objeto;
cout << "[CTRL] + [D] para Sair" << endl;
while (cin >> objeto)
{
file << pobjeto;
data.push_back(objeto);
};
file.close();
}

// ---------------------------------------------------- Sobrecarga do operador >> (cin)

istream &operator >> (istream &file, Data &data)


{
cout << "x: ";
file >> data.x;
cout << "y: ";
file >> data.y;
return(file);
}

// ---------------------------------------------------- Sobrecarga do operador << (cout)

ofstream &operator << (ofstream &file, Data *&data)


{
file.write((char*) data, sizeof(Data));
return(file);
}

Resultado do Programa:

Nome do Arquivo: objeto.dat


[CTRL] + [D] para Sair
x: 1
y: 2
x: 3
y: 4
x: 5
y: 6
x: 7
y: 8
... CTRL+D

Programa exemplo (137): O programa exemplo ler_object.cpp,


abaixo, demonstra a leitura de um objeto que possui dois atributos
inteiros: x e y em um arquivo qualquer.

// carrega_objeto.cpp

#include <iostream>
#include <fstream>
#include <string>
#include <vector>

using namespace std;


class Data
{
int x, y;
public :
Data(int tx, int ty)
{
x = tx;
y = ty;
}
friend ostream &operator << (ostream &file, Data &data);
friend ifstream &operator >> (ifstream &file, Data *&data);
};

int main (void)


{
vector <Data> data;
Data objeto(0,0);
Data * ptobjeto = &objeto;

cout << "Nome do Arquivo de Objetos: ";


string nome;
getline (cin, nome);
ifstream file (nome.c_str());
if (not file)
{
cout << "ERRO: Arquivo não Existe\n";
exit (1);
}
while (file >> ptobjeto)
{
cout << objeto;
data.push_back(objeto);
}
file.close();
}

// ------------------------------------------------- Sobrecarga do Operador << (cout)

ostream &operator << (ostream &file, Data &data)


{
file << "(x = " << data.x;
file << " ,y = " << data.y << ")" << endl;
return(file);
}

// ------------------------------------------------- Sobrecarga do Operador >> (cin)

ifstream &operator >> (ifstream &file, Data *&data)


{
file.read ((char*)data , sizeof(Data));
return(file);
}
Resultado do Programa:

Nome do Arquivo de Objetos: objeto.dat


(x = 1 ,y = 2)
(x = 3 ,y = 4)
(x = 5 ,y = 6)
(x = 7 ,y = 8)
14. Programas em C++
Programa exemplo (138): O programa exemplo calc.cpp, abaixo,
demonstra a definição de uma classe Calculadora que possui as
seguintes operações:
[+] Adição
[-] Subtração
[*] Multiplicação
[/] Divisão
[R] Raiz Quadrada
[P] Potência
[I] Inverso
[S] Seno
[C] Cosseno
[T] Tangente

// Calc.cpp

#include <iostream>
#include <iomanip>
#include <math.h>

using namespace std;

#define PI 4*atan(1)

class Calculadora
{
private:
double x,y,resp;
char op;
int erro;
private:
void Add(void)
{
resp = x + y;
erro = 0;
}
void Sub(void)
{
resp = x - y;
erro = 0;
}
void Mult(void)
{
resp = x * y;
erro = 0;
}
void Div(void)
{
if (y not_eq 0)
{
resp = x / y;
erro = 0;
}
else
erro = 1; // Divisão por zero
}
void Raiz(void)
{
if (x >= 0)
{
resp = sqrt(x);
erro = 0;
}
else
erro = 2; // Raiz Negativa
}
void Pot(void)
{
resp = pow(x,y);
erro = 0;
}
void Inv(void)
{
if (x not_eq 0)
{
resp = 1 / x;
erro = 0;
}
else
erro = 1; // Divisão por zero
}
void Sen(void)
{
float rads = x * PI / 180.0; // converte de graus para radianos
resp = sin(rads);
erro = 0;
}
void Cos(void)
{
float rads = x * PI / 180.0;
resp = cos(rads);
erro = 0;
}
void Tan(void)
{
float rads = x * PI / 180.0;
if (x == 90.0 or x == 270.0)
erro = 3; // Tangente Infinita
else
{
resp = tan(rads);
erro = 0;
}
}

public:
void Entrada(void)
{
cout << "Digite um valor: ";
cin >> x;
cout << "Operação:\n[+] Adição\n[-] Subtração\n[*] Multiplicação\n[/] Divisão\n";
cout << "[R] Raiz Quadrada\n[P] Potência\n[I] Inverso\n";
cout << "[S] Seno\n[C] Cosseno\n[T] Tangente\n";
cout << "Qual a sua opção? ";
do {
op = cin.get();
} while (not strchr("+-*/RrPpIiSsCcTt",op));
if (strchr("+-*/Pp",op))
{
cout << "Digite outro valor: ";
cin >> y;
}
}
void Calcula(void)
{
switch (op)
{
case '+': Add();
break;
case '-': Sub();
break;
case '*': Mult();
break;
case '/': Div();
break;
case 'R':
case 'r': Raiz();
break;
case 'P':
case 'p': Pot();
break;
case 'I':
case 'i': Inv();
break;
case 'S':
case 's': Sen();
break;
case 'C':
case 'c': Cos();
break;
case 'T':
case 't': Tan();
break;
}
}
void Exibe(void)
{
if (not erro)
cout << "Resposta: " << setprecision(4) << resp << endl;
else
if (erro == 1)
cout << "ERRO: Divisão por Zero" << endl;
else
if (erro == 2)
cout << "ERRO: Raiz Negativa" << endl;
else
if (erro == 3)
cout << "ERRO: Tangente Infinita" << endl;
}
};

int main(void)
{
Calculadora calc;
char tecla;

do {
calc.Entrada();
calc.Calcula();
calc.Exibe();
cin.ignore(1,'\n');
cout << "Novo Cálculo [S/N]? ";
do {
tecla = cin.get();
} while (not strchr("SsNn",tecla));
} while (strchr("Ss",tecla));
}

Resultado do Programa:

Digite um valor: 45
Operação:
[+] Adição
[-] Subtração
[*] Multiplicação
[/] Divisão
[R] Raiz Quadrada
[P] Potência
[I] Inverso
[S] Seno
[C] Cosseno
[T] Tangente
Qual a sua opção? s
Resposta: 0.7071
Novo Cálculo [S/N]? s
Digite um valor: 45
Operação:
[+] Adição
[-] Subtração
[*] Multiplicação
[/] Divisão
[R] Raiz Quadrada
[P] Potência
[I] Inverso
[S] Seno
[C] Cosseno
[T] Tangente
Qual a sua opção? c
Resposta: 0.7071
Novo Cálculo [S/N]? s
Digite um valor: -16
Operação:
[+] Adição
[-] Subtração
[*] Multiplicação
[/] Divisão
[R] Raiz Quadrada
[P] Potência
[I] Inverso
[S] Seno
[C] Cosseno
[T] Tangente
Qual a sua opção? r
ERRO: Raiz Negativa
Novo Cálculo [S/N]? s
Digite um valor: 90
Operação:
[+] Adição
[-] Subtração
[*] Multiplicação
[/] Divisão
[R] Raiz Quadrada
[P] Potência
[I] Inverso
[S] Seno
[C] Cosseno
[T] Tangente
Qual a sua opção? t
ERRO: Tangente Infinita
Novo Cálculo [S/N]? s
Digite um valor: 2
Operação:
[+] Adição
[-] Subtração
[*] Multiplicação
[/] Divisão
[R] Raiz Quadrada
[P] Potência
[I] Inverso
[S] Seno
[C] Cosseno
[T] Tangente
Qual a sua opção? i
Resposta: 0.5
Novo Cálculo [S/N]? s
Digite um valor: 3
Operação:
[+] Adição
[-] Subtração
[*] Multiplicação
[/] Divisão
[R] Raiz Quadrada
[P] Potência
[I] Inverso
[S] Seno
[C] Cosseno
[T] Tangente
Qual a sua opção? p
Digite outro valor: 2
Resposta: 9
Novo Cálculo [S/N]? n

Programa exemplo (139): O programa exemplo juliano.cpp, abaixo,


demonstra o Cálculo do Dia Juliano, ou seja, por este cálculo é
possível descobrir que dia da semana (segunda, terça, quarta, quinta,
sexta, sábado ou domingo) caiu ou cairá uma determinada data (dia,
mes e ano).

Como calcular o Dia Juliano: http://www.rio.rj.gov.br/planetario/cent_pesq_calc.htm

// juliano.cpp

// --------------------------- Prototypes

#include <iostream>
#include <string>

using namespace std;

// --------------------------- Classe: Data

class Data
{
int dia, mes, ano;

public:
void Entrada_Data(void);
void Exibe_Data_Extenso(void);
int Calcula_Dia_Juliano(void);
void Exibe_Dia_Semana(int resto);
};

// -------------------------------- Método: Le_Atributos

void Data :: Entrada_Data(void)


{
do {
cout << "Dia [1..31]: ";
cin >> dia;
} while (dia < 1 or dia > 31);
do {
cout << "Mes [1..12]: ";
cin >> mes;
} while (mes < 1 or mes > 12);
do {
cout << "Ano [1900..2999]: ";
cin >> ano;
} while (ano < 1900 or ano > 2999);
}

// -------------------------------- Método: Calcula_Dia_Juliano

int Data :: Calcula_Dia_Juliano(void)


{
int a, b, c;
long int d, e, dj;
int dd = dia, mm = mes, aa = ano;
double resp;
if (mm < 3)
{
aa--;
mm += 12;
}
a = aa / 100;
b = a / 4;
c = 2 - a + b;
resp = 365.25 * (aa + 4716);
d = (long int) resp;
resp = 30.6001 * (mm + 1);
e = (long int) resp;
dj = d + e + dd + c - 1524;
int resto = dj % 7;
return(resto);
}

// -------------------------------- Método: Exibe_Dia_Semana

void Data :: Exibe_Dia_Semana(int resto)


{
string nome[] = {"SEGUNDA-FEIRA","TERÇA-FEIRA","QUARTA-FEIRA",
"QUINTA-FEIRA","SEXTA-FEIRA","SÁBADO","DOMINGO"};
cout << "\nDia da Semana: " << nome[resto] << endl;
}

// -------------------------------- Método: Exibe_Data_Extenso

void Data :: Exibe_Data_Extenso(void)


{
string nome[] = {"janeiro","fevereiro","março","abril","maio","junho","julho",
"agosto","setembro","outubro","novembro","dezembro"};
cout << "Data: " << dia << " de " << nome[mes - 1] << " de " << ano;
}

// --------------------------- Programa Principal

int main(void)
{
Data data;
char tecla;

cout << "Cálculo do Dia Juliano (Dia da Semana)" << endl;


do {
data.Entrada_Data();
data.Exibe_Data_Extenso();
int resto = data.Calcula_Dia_Juliano();
data.Exibe_Dia_Semana(resto);
cout << "Novo Cálculo [S/n]?";
do {
tecla = cin.get();
} while (not strchr("SsNn", tecla));
} while (strchr("Ss", tecla));
}

Resultado do Programa:

Cálculo do Dia Juliano (Dia da Semana)


Dia [1..31]: 16
Mes [1..12]: 8
Ano [1900..2999]: 2006
Data: 16 de agosto de 2006
Dia da Semana: QUARTA-FEIRA
Novo Cálculo [S/n]?s
Dia [1..31]: 10
Mes [1..12]: 2
Ano [1900..2999]: 1962
Data: 10 de fevereiro de 1962
Dia da Semana: SÁBADO
Novo Cálculo [S/n]?n

Programa exemplo (140): O programa exemplo cpf.cpp, abaixo,


demonstra como calcular os dígitos verificadores de um cpf qualquer.

Como calcular o CPF: http://www.geocities.com/CapeCanaveral/4274/cgcancpf.htm

// cpf.cpp

#include <iostream>
#include <string>
#include <cctype>

using namespace std;

// -------------------------------- classe: CPF

class CPF
{
char cpf[15];
int n, final;

public:
void Entrada_CPF(void);
int Valida_CPF(void);
void Exibe_CPF(void);
};

// -------------------------------- Método: Entrada_CPF

void CPF :: Entrada_CPF(void)


{
do {
cout << "Cpf [99999999999]: ";
cin.getline(cpf,12);
n = strlen(cpf);
if (n not_eq 11 and n not_eq 10)
cout << "Formato: 9 ou 11 d¡gitos numéricos" << endl;
if (n == 10)
{
n--;
cpf[n] = (char) NULL;
}
} while (n not_eq 11 and n not_eq 10);
}

// -------------------------------- Método: Valida_CPF

int CPF :: Valida_CPF(void)


{
int valor = 0, fator;

for (int i = 0;i < 9;i++)


valor = valor + (cpf[i] - 48) * (10 - i);
fator = valor / 11;
fator = fator * 11;
valor = valor - fator;
int digit1 = valor < 2 ? 0 : 11 - valor;
valor = 0;
for (int i = 0;i < 9;i++)
valor = valor + (cpf[i] - 48) * (11 - i);
valor = valor + digit1 * 2;
fator = valor / 11;
fator = fator * 11;
valor = valor - fator;
int digit2 = valor < 2 ? 0 : 11 - valor;
final = digit1 * 10 + digit2;
if (digit1 == cpf[9] - 48 and digit2 == cpf[10] - 48)
return(1);
else
return(0);
}

// -------------------------------- Método: Exibe_CPF

void CPF :: Exibe_CPF(void)


{
int t = 0;

cout << "Dígito Verificador: ";


if (final >= 10)
cout << final << endl;
else
cout << "0" << final << endl;
if (n == 11)
{
cout << "Cpf Digitado: ";
for (int i = 0;i <= 7;i++)
{
cout << cpf[i];
t++;
if (t == 3)
{
t = 0;
cout << ".";
}
}
cout << cpf[8] << "-";
for (int i = 9;i <= 10;i++)
cout << cpf[i];
cout << endl;
}
}

// -------------------------------- Programa Principal

int main(void)
{
CPF cpf;
char tecla;

do {
cpf.Entrada_CPF();
if (cpf.Valida_CPF())
cout << "Status: CPF Válido" << endl;
else
cout << "Status: CPF Inválido" << endl;
cpf.Exibe_CPF();
cout << "Continua [S/n]?";
do {
tecla = cin.get();
} while (not strchr("SsNn",tecla));
cout << endl;
cin.ignore(1,'\n');
} while (strchr("Ss",tecla));
}

Resultado do Programa:

Cpf [99999999999]: 123456789


Formato: 9 ou 11 d¡gitos numéricos
Status: CPF Inválido
Dígito Verificador: 09
Continua [S/n]?s

Cpf [99999999999]: 12345678909


Status: CPF Válido
Dígito Verificador: 09
Cpf Digitado: 123.456.789-09
Continua [S/n]?n
15. Outros conceitos em C++
15.1 Métodos const

Se o programador quiser definir um método que não possa alterar


os atributos do objeto, ele deve ser declarado como const. Desta forma,
o compilador não permite que o método altere o estado do objeto, ou
seja, o método não pode alterar os atributos do objeto.

Modo de usar:

class Teste
{
int n;
public:
Teste(int tn)
{
n = tn;
}
void Exibe(void) const // método constante
{
cout << “n = “ << n << endl;
}
};

15.2 Métodos static

Existem dois tipos de atributos: da classe e de objeto. Para


trabalhar com um método que só acessa atributos estáticos da classe,
pode-se declará-lo como sendo um método estático. Desta forma é
possível passar informações de um objeto para outro através de
atributos e métodos estáticos da classe.

Se um método é estático e público, pode ser acessado sem que


exista um objeto da classe, basta apenas referenciar: nome da classe,
operador de resolução de escopo (::) e o nome do método.

tipo_variável variável = nome_classe :: nome_método_estático();

Programa exemplo (141): O programa exemplo metodo_static.cpp,


abaixo, demonstra a utilização de um método estático.
// metodo_static.cpp

#include <iostream>

using namespace std;

class Math
{
static int n; // ... atributo da classe, coletivo para todos os objetos
public:
static int Consulta(void)
{
return(n);
}
};

int Math :: n = 7; // inicialização do atributo da classe (tem que ser fora da classe)

int main(void)
{
int x;

x = Math :: Consulta(); // acessando um atributo estático através de um método estático


cout << "x = " << x << endl; // sem ser através de um objeto
}

15.3 Referências para Ponteiros

Em C++ é possível utilizar referências para ponteiros, ou seja, a


referência não é alocada na memória, é apenas uma referência a uma
posição de memória.

Programa exemplo (142): O programa exemplo ref.cpp, abaixo,


demonstra a utilização de referência para ponteiro.

// ref.cpp

#include <iostream>

using namespace std;

int main(void)
{
int n = 7; // variável comum
int *p = &n; // ponteiro aponta para uma variável comum
int &ref_n = n; // referência para uma variável comum
int *&ref_p = p; // referência para ponteiro

cout << "n = " << n << endl;


cout << "*p = " << *p << endl;
cout << "ref_n = " << ref_n << endl;
cout << "ref_p = " << ref_p << endl;
cout << "ref_p = " << *ref_p << endl; // conteúdo da referência para ponteiro
}

Resultado do Programa:
n=7
*p = 7
ref_n = 7
ref_p = 0xbfb35cc8
ref_p = 7

15.4 Arquivos “conio.c” e “conio.h” em C++

Aqui é mostrado uma forma alternativa de utilizar as funções:


clrscr, gotoxy, getche, getch e kbhit sem utilização da biblioteca
ncurses.

Programa exemplo (143): O programa exemplo conio.cpp, abaixo,


demonstra a utilização da biblioteca conio.h.

// conio.cpp

#include <iostream>
#include "conio.h" // arquivo conio.h contém as funções citadas acima

using namespace std;

#define ESC 27

int main(void)
{
int tecla;

clrscr();
do {
textcolor(BLUE);
gotoxy(10,5);
cout << "Tecla: ";
tecla = getche(); // troque por tecla = getch();
textbackcolor(CYAN);
gotoxy(10,7);
cout << "Código: " << tecla << " -> Caracter: " << tecla;
} while (tecla != ESC);
}

// conio.h

#include <termios.h>
#include <unistd.h>
#include <sys/time.h>

#define BLACK 0
#define RED 1
#define GREEN 2
#define BROWN 3
#define BLUE 4
#define MAGENTA 5
#define CYAN 6
#define DARKGRAY 7
#define SUBLINHA 8

#define black 0
#define red 1
#define green 2
#define brown 3
#define blue 4
#define magenta 5
#define cyan 6
#define darkgray 7
#define sublinha 8

// ---------------------------- função: clrscr

void clrscr(void)
{
printf("\x1B[2J");
}
// ---------------------------- função: gotoxy

void gotoxy(int c, int l)


{
printf("\033[%d;%df",l, c);
}

// --------------------------- função: getch

int getch(void)
{
struct termios oldt, newt;
int ch;

tcgetattr(STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
ch = getchar();
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
return(ch);
}

// --------------------------- função: getche

int getche(void)
{
struct termios oldt, newt;
int ch;

tcgetattr(STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
ch = getchar();
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
putchar(ch);
return(ch);
}

// --------------------------- função: kbhit

int kbhit(void)
{
struct timeval tv;
fd_set read_fd;

tv.tv_sec=0;
tv.tv_usec=0;
FD_ZERO(&read_fd);
FD_SET(0,&read_fd);
if (select(1, &read_fd, NULL, NULL, &tv) == -1)
return(0);
if (FD_ISSET(0,&read_fd))
return(1);
return(0);
}

// --------------------------- função: textcolor

void textcolor(int cor)


{
printf("\033[0m");
switch (cor)
{
case BLACK: printf("\033[30m");
break;
case RED: printf("\033[31m");
break;
case GREEN: printf("\033[32m");
break;
case BROWN: printf("\033[33m");
break;
case BLUE: printf("\033[34m");
break;
case MAGENTA: printf("\033[35m");
break;
case CYAN: printf("\033[36m");
break;
case DARKGRAY: printf("\033[37m");
break;
case SUBLINHA: printf("\033[38m");
break;
}
}

// --------------------------- função: textbackcolor


void textbackcolor(int cor)
{
switch (cor)
{
case BLACK: printf("\033[40m");
break;
case RED: printf("\033[41m");
break;
case GREEN: printf("\033[42m");
break;
case BROWN: printf("\033[43m");
break;
case BLUE: printf("\033[44m");
break;
case MAGENTA: printf("\033[45m");
break;
case CYAN: printf("\033[46m");
break;
case DARKGRAY: printf("\033[47m");
break;
}
}

// --------------------------- função: random

int random(int n)
{
int t = rand() % n;
return(t);
}

// --------------------------- função: randomize

void randomize(void)
{
srand(time(NULL));
}

Programa exemplo (144): O programa exemplo cores.cpp, abaixo,


demonstra a utilização da biblioteca conio.h em relação as cores, ou
seja, funções textcolor e textbackcolor.

// cores.cpp

#include <iostream>
#include "conio.h"

using namespace std;

int main(void)
{
textcolor(BLACK);
cout << "Black" << endl;
textcolor(RED);
cout <<"Red" << endl;
textcolor(GREEN);
cout << "Green" << endl;
textcolor(BROWN);
cout << "Brown" << endl;
textcolor(BLUE);
cout << "Blue" << endl;
textcolor(MAGENTA);
cout << "Magenta" << endl;
textcolor(CYAN);
cout << "Cyan" << endl;
textcolor(DARKGRAY);
cout << "DarkGray" << endl;
textcolor(SUBLINHA);
cout << "Sublinha" << endl;
textbackcolor(BLACK);
cout << " Black " << endl;
textbackcolor(RED);
cout << " Red " << endl;
textbackcolor(GREEN);
cout << " Green " << endl;
textbackcolor(BROWN);
cout << " Brown " << endl;
textbackcolor(BLUE);
cout << " Blue " << endl;
textbackcolor(MAGENTA);
cout << " Magenta " << endl;
textbackcolor(CYAN);
cout << " Cyan " << endl;
textbackcolor(DARKGRAY);
cout << " DarkGray " << endl;
getchar();
}

Programa exemplo (145): O programa exemplo abaixo quebra.cpp


demonstra a utilização da biblioteca conio.h (listada acima) em relação
ao sorteio de números aleatórios através de um jogo chamado Quebra-
Cabeças.

// quebra.cpp

#include <iostream>
#include "conio.h"

using namespace std;

const int UP = 65;


const int LEFT = 68;
const int RIGHT = 67;
const int DOWN = 66;
// ------------------------------------- Função: Imprime

void Imprime(int c, int l, int cod, int cor)


{
textcolor(cor);
gotoxy(c,l);
cout << (char) 14 << (char) cod << (char) 15;
}

// ------------------------------------- Função: Moldura

void Moldura(int ci, int li, int cf, int lf, int cor)
{
for (int c = ci+1;c < cf;c++)
{
Imprime(c,li,113,cor);
Imprime(c,lf,113,cor);
}
for (int l = li+1;l < lf;l++)
{
Imprime(ci,l,120,cor);
Imprime(cf,l,120,cor);
}
Imprime(ci,li,108,cor);
Imprime(cf,li,107,cor);
Imprime(cf,lf,106,cor);
Imprime(ci,lf,109,cor);
}

// ------------------------------------- Classe Grade

class Grade
{
private:
int ci, li, cf, lf, grade, numeros;
char vetor[3][3];
int jogadas, tecla;
private:
bool Testa_Jogada(void);
void troca(int &x, int &y)
{
int temp = x;
x = y;
y = temp;
}
public:
Grade(int c, int l, int cor_grade, int cor_numeros) // construtor
{
ci = c;
li = l;
cf = ci + 12;
lf = li + 6;
grade = cor_grade;
numeros = cor_numeros;
}
void Desenha_Grade(void);
void Sorteia_Numeros(void);
void Exibe_Numeros(void);
void Jogar(int total_jogadas);
void Posiciona_Cursor(int col, int lin);
};

// ------------------------------------- Método: Desenha_Grade (público)

void Grade :: Desenha_Grade(void)


{
Moldura(ci, li, cf, lf, grade);
for (int c = ci+1;c < cf;c++)
{
Imprime(c,li+2,113,grade);
Imprime(c,li+4,113,grade);
}
for (int l = li+1;l < lf;l++)
{
Imprime(ci+4,l,120,grade);
Imprime(ci+8,l,120,grade);
}
int c = ci + 4;
for (int i = 1;i <= 2;i++)
{
Imprime(c,li,119,grade);
Imprime(c,li,119,grade);
Imprime(c,lf,118,grade);
Imprime(c,lf,118,grade);
c = c + 4;
}
int l = li + 2;
for (int i = 1;i <= 2;i++)
{
Imprime(ci,l,116,grade);
Imprime(ci,l,116,grade);
Imprime(cf,l,117,grade);
Imprime(cf,l,117,grade);
l = l + 2;
}
c = ci + 4;
for (int i = 1;i <= 2;i++)
{
Imprime(c,li+2,110,grade);
Imprime(c,li+2,110,grade);
Imprime(c,li+4,110,grade);
Imprime(c,li+4,110,grade);
c = c + 4;
}
}

// ------------------------------------- Método: Sorteia_Numeros (público)


void Grade :: Sorteia_Numeros(void)
{
int n = 0;
int c, l;

randomize();
for (l = 0;l <= 2;l++)
for (c = 0;c <= 2;c++)
vetor[l][c] = -1;
do {
c = random(3);
l = random(3);
if (vetor[l][c] == -1)
{
vetor[l][c] = n + 48;
n++;
}
} while (n <= 8);
}

// ------------------------------------- Método: Exibe_Numeros (público)

void Grade :: Exibe_Numeros(void)


{
int i = 0, j = 0;

textcolor(numeros);
for (int l = 6;l <= 10;l=l+2)
{
for (int c = 12;c <= 20;c=c+4)
{
gotoxy(c,l);
cout << " ";
gotoxy(c,l);
if (vetor[i][j] not_eq '0')
cout << vetor[i][j];
j++;
}
i++;
j = 0;
}
if (Testa_Jogada()) // testa fim do jogo
{
textcolor(BROWN);
gotoxy(12,14);
cout << "Winner";
getch();
exit(0);
}
}

// ------------------------------------- Método: Testa_Jogada (privado)


bool Grade :: Testa_Jogada(void)
{
char correto[3][3] = {{'1','2','3'},
{'4','5','6'},
{'7','8','0'}};

for (int l = 0;l <= 2;l++)


for (int c = 0;c <= 2;c++)
if (vetor[l][c] != correto[l][c])
return(false);
return(true);
}

// ------------------------------------- Método: Jogo (público)

void Grade :: Jogar(int total_jogadas)


{
int col, lin;
int c, l;

jogadas = total_jogadas;
for (l = 0;l <= 2;l++) // descobrir a posição do ZERO
for (c = 0;c <= 2;c++)
if (vetor[l][c] == '0')
{
col = c;
lin = l;
break;
}
textcolor(MAGENTA);
gotoxy(9,4);
cout << "Quebra Cabeças";
textcolor(numeros);
gotoxy(11,12);
cout << "Jogadas: ";
textcolor(grade);
gotoxy(11,13);
cout << "Tecla: ";
c = col;
l = lin;
do {
textcolor(RED);
gotoxy(20,12);
cout << jogadas;
Posiciona_Cursor(col,lin);
tecla = getch();
gotoxy(18,13);
switch (tecla)
{
case UP: cout << "Up ";
if (l >= 0 and l <= 1)
{
l = lin + 1;
int temp = vetor[lin][col];
vetor[lin][col] = vetor[l][c];
vetor[l][c] = temp;
lin = l;
jogadas--;
Exibe_Numeros();
}
break;
case DOWN: cout << "Down ";
if (l >= 1 and l <= 2)
{
l = lin - 1;
int temp = vetor[lin][col];
vetor[lin][col] = vetor[l][c];
vetor[l][c] = temp;
lin = l;
jogadas--;
Exibe_Numeros();
}
break;
case LEFT: cout << "Left ";
if (c >= 0 and c <= 1)
{
c = col + 1;
int temp = vetor[lin][col];
vetor[lin][col] = vetor[l][c];
vetor[l][c] = temp;
col = c;
jogadas--;
Exibe_Numeros();
}
break;
case RIGHT: cout << "Right";
if (c >= 1 and c <= 2)
{
c = col - 1;
int temp = vetor[lin][col];
vetor[lin][col] = vetor[l][c];
vetor[l][c] = temp;
col = c;
jogadas--;
Exibe_Numeros();
}
break;
}
} while (jogadas != 0);
}

// ------------------------------------- Método: Posiciona_Cursor (público)

void Grade :: Posiciona_Cursor(int col, int lin)


{
int c, l;

c = 12 + col * 4;
l = 6 + lin * 2;
gotoxy(c,l);
}

// ------------------------------------- Programa Principal

int main(void)
{
Grade grade(10, 5, BLUE, CYAN);

clrscr();
Moldura(1,1,32,17,GREEN);
grade.Desenha_Grade();
grade.Sorteia_Numeros();
grade.Exibe_Numeros();
grade.Jogar(99);
}
Tela do Jogo

15.5 Templates em C++

Templates ou gabaritos são funções ou classes genéricas em que


o tipo dos dados, ou seja, parâmetros (argumentos) e/ou retorno das
funções ou métodos são definidos em tempo de compilação.

Os templates podem aparecer de várias formas, por exemplo: (a)


funções templates; (b) classes templates; (c) especificação
template e (e) parâmetros não tipados para templates.

Funções templates: Permite definir uma função template, ou seja, uma


função que aceita “qualquer” tipo de parâmetro ou retorno da função,
ou seja, é uma forma eficiente de polimorfismo.
Classes templates: Permite declarar uma classe genérica, ou seja, os
atributos e métodos podem aceitar “qualquer” tipos.
Especificação template: Permite definir uma diferente implementação
para um template quando um tipo específico é passado para este como
parâmetro.
Parâmetros não tipados para templates: Os parâmetros dos
templates podem ser precedidos por classes tipadas, os templates
podem ter parâmetros tipados ou não-tipados.

Programa exemplo (146): O programa exemplo template1.cpp,


abaixo, demonstra a utilização de funções do tipo template em C++.

// template1.cpp

#include <iostream>

using namespace std;

// ----------------------------- função template: Max

template <class Type>


Type Max (Type x, Type y)
{
if (x > y)
return(x);
else
return(y);
}

// ----------------------------- função template: Min

template <class Type>


Type Min (Type x, Type y)
{
if (x < y)
return(x);
else
return(y);
}

// ----------------------------- Programa Principal

int main (void)


{
int a = 3, b = 4;
float x = 1.2, y = 3.4;

cout << "a = 3e b = 4, maior é " << Max <int> (a, b) << endl;
cout << "x = 1.2 e y = 3.4, maior é " << Max <float> (x, y) << endl;
cout << "a = 3e b = 4, maior é " << Min <int> (a, b) << endl;
cout << "x = 1.2 e y = 3.4, maior é " << Min <float> (x, y) << endl;
}

Resultado do Programa:
a =3e b = 4, maior é 4
x = 1.2 e y = 3.4, maior é 3.4
a =3e b = 4, maior é 3
x = 1.2 e y = 3.4, maior é 1.2

Programa exemplo (147): O programa exemplo template2.cpp,


abaixo, demonstra a utilização de classes do tipo template em C++.

// template2.cpp

#include <iostream>

using namespace std;

// --------------------------- Classe template: Imprime

template <class Type>


class Imprime
{
private:
Type inic, fim;
public:
Imprime(Type ti, Type tf)
{
inic = ti;
fim = tf;
}
void Exibe(void);
};

// --------------------------- Função template: Imprime

template <class Type>


void Imprime <Type> :: Exibe(void)
{
for (Type i = inic;i <= fim;i++)
cout << i << " ";
cout << endl;
}

// --------------------------- Programa Principal

int main (void)


{
Imprime <int> inteiro (1, 10); // objeto inteiro
inteiro.Exibe();
Imprime <char> real ('A', 'Z'); // objeto real
real.Exibe();
}

Resultado do Programa:

1 2 3 4 5 6 7 8 9 10
ABCDEFGHIJKLMNOPQRSTUVWXYZ

Programa exemplo (148): O programa exemplo template3.cpp,


abaixo, demonstra a utilização de especificação do tipo template em
C++.

// template3.cpp

#include <iostream>

using namespace std;

template <class Type>


class Classe
{
private:
Type atributo;
public:
Classe(Type argumento)
{
atributo = argumento;
}
Type Add(void)
{
atributo++;
return(atributo);
}
};

template <> // especificação da classe template para char


class Classe <char>
{
private:
char caracter;
public:
Classe (char argumento)
{
caracter = argumento;
}
char Tolower(void)
{
if (caracter >= 'A' and caracter <= 'Z')
caracter = caracter + 32;
return(caracter);
}
char Add(void)
{
caracter++;
return(caracter);
}
};

int main (void)


{
Classe <int> inteiro (3);
cout << "Inteiro: " << inteiro.Add() << endl;
Classe <char> caracter ('A');
cout << "Caracter: " << caracter.Tolower() << endl;
cout << "Caracter: " << caracter.Add() << endl;
}

Resultado do Programa:

Inteiro: 4
Caracter: a
Caracter: b

Programa exemplo (149): O programa exemplo template4.cpp,


abaixo, demonstra a utilização de parâmetros não tipados do tipo
template em C++.

// template4.cpp

#include <iostream>

using namespace std;

// ---------------------------------------------- Classe Template: Vetor

template <class Type, int n>


class Vetor
{
Type vetor[n];
public:
void Gera_Vetor(int t, Type value);
void Exibe_Vetor(int t);
};

// ---------------------------------------------- Método Template: Gera_Vetor

template <class Type, int n>


void Vetor <Type, n> :: Gera_Vetor(int t, Type valor)
{
for (int i = 0;i < t;i++)
vetor[i] = valor++;
}

// ---------------------------------------------- Método Template: Exibe_Vetor

template <class Type, int n>


void Vetor <Type, n> :: Exibe_Vetor(int t)
{
for (int i = 0;i < t;i++)
cout << vetor[i] << ' ';
cout << endl;
}
// ---------------------------------------------- Programa Principal

int main(void)
{
const int n1 = 5;
const int n2 = 4;
Vetor <int, n1> inteiro;
Vetor <char, n2> caracter;

inteiro.Gera_Vetor(n1, 1);
inteiro.Exibe_Vetor(n1);
caracter.Gera_Vetor(n2,'a');
caracter.Exibe_Vetor(n2);
}

Resultado do Programa:

12345
abcd
16. Composição

Na composição de objetos, uma classe pode ter como membros


objetos de outras classes. Desta forma:

• Membros-objeto são inicializados antes dos objetos de que fazem


parte.
• Os argumentos para os construtores dos membros objeto são
indicados através da sintaxe dos inicializadores de membros.

Exemplo:

class Pessoa
{
public:
Pessoa(char *n, int d, int m, int a); // construtor
private:
char *nome;
Data nascimento; // membro-objeto
};

Pessoa :: Pessoa(char *n, int d, int m, int a) : nascimento(d, m, a)


{
}

A reutilização na orientação a objetos pode ser de duas formas:

Herança de classes: Chamada de reutilização tipo caixa-branca,


definição estática (tempo de compilação), simples, mas expõe classe
base.

Composição de objetos: Chamada de reutilização tipo caixa-preta,


definição dinâmica (obter referência durante execução), mais complexo
de compreender.

Para o próximo programa exemplo, relembre os seguintes


conceitos vistos anteriormente:

Métodos const

Quando um método da classe não altera o estado do objeto, ou


seja, não altera nenhum atributo do objeto, ele deve ser declarado como
método const. Desta forma, o compilador sabe que este método não
pode alterar nenhum atributo (proteção aos dados).

Objetos const
Objetos const só podem executar métodos const, por isto, é necessário
que o objeto declarado como const tenha métodos const e construtores
que inicializem os atributos.

Programa exemplo (150): O programa exemplo composicao.cpp,


abaixo, demonstra a utilização de composição em C++.

// composicao.cpp

#include <iostream>

using namespace std;

class Date
{
private:
int day, month, year;
public:
Date(int dd = 1, int mm = 1, int yy = 1900);
void Print (void) const
{
cout << "Data: " << day << "/" << month << "/" << year << endl;
}
};

Date :: Date(int dd, int mm, int yy)


{
day = dd;
month = mm;
year = yy;
}

class Empregado
{
private:
char first[25],last[25];
const Date dataNasc, dataInic;
public:
Empregado(char *f, char *l, int d, int m, int a, int dd, int mm, int aa) :
dataNasc(d,m,a) , dataInic(dd,mm,aa)
{
int length = strlen(f);
length = (length < 25 ? length : 24);
strncpy(first,f,length);
first[length] = (char) NULL;

length = strlen(l);
length = (length < 25 ? length : 24);
strncpy(last,l,length);
last[length] = (char) NULL;
cout << "Construtor Empregado: " << first << " " << last << endl;
}
void Print(void)
{
cout << "Nome: " << first << " " << last << endl;
cout << "Data da Contratação: ";
dataInic.Print();
cout << "Data de Nascimento: ";
dataNasc.Print();
}
};

int main(void)
{
Empregado empregado("Paulo", "Roberto", 24, 7, 1949, 3, 12, 1988);

empregado.Print();
cin.get();
}

Vous aimerez peut-être aussi