Sei sulla pagina 1di 33

Treinamento em Linguagem C++

Declaração de Classes
⇒ Visibilidade de Membros de Classes
⇒ Enumerações
⇒ Referências
⇒ Funções inline
⇒ Passagem de parâmetros para funções
⇒ Classes e Objetos
⇒ Operadores de dados
⇒ Utilização do especificador const
⇒ Objetos como membros de dados de uma classe
⇒ Operador de inicialização de membro
⇒ Estruturas e classes (observações)
⇒ Sobrecarga de funções
⇒ Funções membro que retornam um objeto
⇒ Membros de dados private static
⇒ Objetos criados dinamicamente
⇒ Herança
⇒ Herança pública e privada
⇒ Reescrevendo funções-membro da classe base
⇒ Classe Abstratas
⇒ Níveis de Herança
⇒ Herança múltipla
⇒ Ponteiros
⇒ Alocação dinâmica em C/C++
⇒ Sobrecarga de operadores
⇒ Operadores unários sobrecarregados pré e pós fixados
⇒ Conversões
⇒ Listas encadeadas
⇒ Ponteiros para funções
⇒ Gravando uma linha por vez no arquivo de saída
⇒ Lendo uma linha por vez do arquivo de entrada
⇒ Identificando o fim de arquivo (eof)
⇒ A função open()
⇒ Lendo um caracter por vez do arquivo de entrada
⇒ Gravando um caracter por vez no arquivo de saída
⇒ Exemplo de operações com arquivos em C++
⇒ Gravando objetos
⇒ Lendo objetos
⇒ Os métodos seekp(), seekg(), tellp() e tellg()
Declaração de Classes

a) Em C++, as classes permitem ao programador definir novos tipos de dados.

b) As classes podem ser declaradas pelas palavras-chave STRUCT, UNION e CLASS

c) As estruturas em C++ podem ter membros de dados e de função; seus membros são
public por default.

d) As uniões em C++ podem ter membros de dados e de função; seus membros são
públicos por default; todos os mebros de uma união ocupam a mesma posição de
memória.

e) As classes (propriamente ditas) tem membros de dados (variáveis de instância) e


membros de função cuja visibilidade é private por default.

f) Uma instância de estrutura ou união é dita uma variável; uma instância de classe é
dita um objeto. Ou seja, um objeto é uma variável do tipo classe.

Visibilidade de Membros de Classes

a) private: os membros private podem ser acessados apenas pelas funções-membro da


classe

b) public: os membros public podem ser acessados por qualquer função

c) protected: os membros protected podem ser acessados por qualquer função-membro


da classe-base e de suas classes derivadas.

Enumerações

a) As enumerações permitem ao usuário criar variáveis às quais podem ser atribuídos


valores constantes.

b) Estes valores constantes estão listados na instrução de definição do tipo enumerado.

c) exemplo:
enum CORES { AZUL=1,VERDE=2,CINZA=31};

// declara a variável cor como do tipo CORES


CORES cor;

cor = VERDE ; // ok
cor = 1 ;// errado - cor é do tipo CORES e 1 é do tipo inteiro
cor=(CORES)1;// foi necessário utilizar o operador de molde

Referências

a) Forma alternativa de passar parâmetros para uma função

b) A função chamada cria referências para os argumentos fornecidos pela função


chamadora, que ocupam a mesma posição de memória destes argumentos.

c) A função chamada não cria cópias locais dos argumentos recebidos; logo, qualquer
alteração nestes será refletida na funçoão chamadora.

d) A passagem de argumentos por referência é também uma forma de permitir à função


chamada retornar mais de um valor à função chamadora.

Exemplo:

int x;
int &xref = x; // cria referência para x; &x = &x1

Funções inline

a) O especificador inline sugere ao compilador substituir o código da função na posição


em que foi chamada, ao invés de executar o processo de chamada de função.

b) As funções inline são tratatadas com macros, o que pode aumentar a velocidade de
execução.

c) Esta sugestão (ver item a) pode ser aceita ou não, baseado em critérios que variam de
um compilador para outro (usualmente apenas funções pequenas) .
Passagem de parâmetros para funções

a) A passagem de parâmetros para fun'ções pode ser feita por valor, por referência ou
por ponteiro.

b) Na chamada por valor, a função chamada cria uma cópia local do argumento passado
pela função chamadora.

c) Na chamada por referência, a função chamada não fria uma nova variável, mas
apenas uma referência (ALIAS) do parâmetro fornecido. Quaisquer alterações de
valor nesta referência serão refletidas na função chamadora, a menos que o
especificador CONST seja incluído no protótipo da função. Por exemplo:

int MyFunction_ByRef (const int& MyVariable) {


i +=1 ; // esta instrução gera um erro em temnpo de compilação }

d) A passagem de parâmetros por ponteiro ou por referência permite à função retornar


mais de um valor para a função chamadora.

e) As chamadas de funções com passagem de argumentos por referência ou por valor


são idênticas.

f) Na chamada de funções com passagem de argumentos por ponteiros devemos


fornecer o endereço da variável-parâmetro. A função chamada criará um ponteiro
para o endereço fornecido.

int MyFunction_ByPtr (int *p); // protótipo da função

void main()
{
int MyVariable=10;
MyFunction_ByPtr(&MyVariable);
}

g) O tipo de um ponteiro corresponde ao tipo do valor aramazenado no endereço por ele


apontado. Logo, como p aponta para o endereço de MyVaraiable, que é inteira,
dizemos que p é um ponteiro do tipo int ou ponteiro para inteiro.

Classes e Objetos
a) Os membros declarados na seção private são encapsulados. Estes membros(de dados
ou de função) só podem ser acessados por funções mebros da mesma classe.

b) Os membros de dados são normalmente declarados na seção private.

c) As funções-membro declaradas na seção public fazem a interface entre o


programador e a classe. Normalmente são as funções d emanipulação de dados.

d) Uma classe pode ter membros de dados ou variáveis de instância e membros de


função ou função-membro ou métodos.

e) Se o corpo da função-membro é declarado dentro da classe, esta função é considerada


inline por default, sendo desnecessário a utilização do especificador inline.

f) Instrução de chamada a uma função-membro:

ClassName.FunctionName();

g) A instrução de chamada a uma função membro é chamada de MENSAGEM.

h) Declaração do corpo da função for a da classe:

[tipo] [ClassName] :: [function_name]()

i) O operador (::) é o operador de resolução de escopo. Este operador informa que


[function_name] é membro da classe [ClassName].

j) Função construtora ou construtor : função que tem o mesmo nome da classe e é


chamada automaticamente quando o objeto é declarado.

k) O construtor não retorna nenhum tipo de valor, logo a declaração da função


construtora não deve ser precedida do tipo.

[ClassName]::[ClassName]()

l) Função destrutora ou destrutor: função que tem o memso nome da classe (precedido
por um ~) chamada automaticamente quando o objeto é destruído (liberado da
memória).

m) A função destrutora não retorna nenhum tipo de valor e não pode receber
argumentos.

[ClassName]::~[ClassName]()
Sumário de termos relacionados

Método – função-membro ou membro de função de uma classe


Mensagem – qualquer chamada a uma função membro de um objeto.

Função inline – função-membro cujo corpo é declarado no interior da classe.

Visibilidade – os membros de uma classe podem ser classificados, quanto à visibilidade,


como private, public ou protected. Os membros public podem ser acessados por qualquer
função; os membros private podem ser acessados apenas pelas funções-membro da
classe; e o membros protected podem ser acessados pelas funções-membro da classe e de
suas classes derivadas.

Operador ponto – liga o objeto ao membro.

Operador de resolução de escopo – utilizado na declaração de funções-membro fora do


corpo da classe, para indicar que as respectivas funções pertencem à classe em questão.

Construtor – função chamada automaticamente quando um objeto é criado; a função


construtora não tem tipo (pois não retorna nenhum tipo de valor) , mas pode receber
qualquer número de argumentos.

Função de acesso – método public utilizado para ler ou alterar membros de dados private.

Operadores de Dados

• x[y] = elemento (y-1) da matriz x

• x.y = membro y do objeto x

• &x = endereço de x na memória

• *x = conteúdo do endereço apontado por x

• xy = membro y do objeto apontado por x


Utilizações do especificador const

a) para declarar funções-membro que não podem modificar o valor dos membros de
dados da classe, apenas acessá-los.

[tipo] [ClassName]::[FunctionName](list parameters) const

b) para impedir que os valor dos membros de dados sejam alterados após a inicialização,
que deve ser feita obrigatóriamente na função construtora da classe. Neste caso, todos
os métodos da classe devem ser declarados como constantes, conforme sintaxe
exibida em (a).

const [ClassName] [ObjectName] (list parameters)

c) para impedir que o valor de uma variável seja modificado após sua inicialização, que
deve ser feita obrigatoriamente na declaração da variável.

const [name] = [value]

d) A formulação acima pode ser utilizada para substituir a instrução

#define [name] [value]

Objeto como membros de dados de uma classe

a) Considere o exemplo a seguir:

class Date
{
private:
int day, month;

public:
int year;
Date(int,int,int);
int PrintDay();
int PrintMonth();
int ChangeBirthday(int,int,int);
~Date();
};
class President
{
private:
FirstName[20], LastName[20];

public:
President(char [ ],char [ ], int, int, int);
~President();
Date Birthday;
}

b) Vemos que Birthday é uma instância da classe Date, e que está definida como um
membro de dados da classe President.

c) Logo, quando um objeto da classe President é inicializado, a função construtora da


classe precisa inicializar também o objeto membro de dados Birthday, o que implica
em executar também a função construtora da classe Date.

d) Portanto, a função construtora da classe President precisa inicializar os membros de


dados da classe Date, o que é feito através do operador de inicialização de membro
(:).

President::President(char n1[ ], char n2[ ] , int d, int m, int y):Birthday(d,m,y)


{
………
}

Estruturas e classes (observações)

a) Conforme já mencionado, os membros de uma estrutura são public por default e os


de uma classe são private por default.

b) Consequentemente, a utilização da palavra-chave public no corpo de da declaração de


uma estrutura é desnecessária, assim como da palavra-chave private no corpo de
declaração de uma classe.
Sobrecarga de funções

a) Em C++ é possível declarar duas ou mais funções com o mesmo nome. Estas funções
(além da primeira) são ditas sobrecarregadas.

b) As funções sobrecarregadas são diferenciadas pelo compilador não pelo tipo de


variável que retornam, mas pela lista de argumentos.

c) A utilização de funções sobrecarregadas pode ser útil em diversas situações, como


por exemplo na inicialização de objetos (construtores sobrecarregados).

Funções membro que retornam um objeto

a) Considere a declaração da classe Venda

class Venda
{
private:
int npecas;
float preco;

public:
Venda();// construtor
Venda AddVenda(Venda);
void PrintVenda();
~Venda() { } ;// função destrutora (inline)
};

b) Considere agora a declaração da função-membro da classe Venda que retorna um


objeto Venda

Venda Venda::AddVenda(Venda A)
{
Venda Temp;

Temp.npecas= npecas + A.npecas;


Temp.preco = preco + A.preco;

return Temp;
}

c) Declaramos abaixo 3 objetos da classe Venda


Venda A,B,Temp;

d) A instrução Temp = A.AddVenda(B); equivale a somar os valores das respectivas


variáveis de instância dos objetos A e B.

d) O objeto B é passado como argumento para a função-membro do objeto A.

e) Um novo objeto Temp é criado na função AddVenda,e suas variáveis d einstância


recebem a soma das variáveis de instância do objeto atual (A) e do objeto passado
como parâmetro (B), ou seja, Temp = A + B ;

f) Este resultado (um objeto da classe Venda) é atribuído ao objeto Temp, declarado no
bloco principal do programa.

Membros de dados private static

a) Quando um membro de dados é declarado como static, ele é compartilhado por todos
os objetos pertencentes à classe.

b) Os membros de dados private auto (classe de armazenamento default) são


individualizados por objeto, ou seja, cada membro é criado para cada objeto.

c) As variáveis de instância static comportam-se de forma semelhante às variáveis static


convencionais.

d) Os membros de dados static devem ser declarados através da instrução

[tipo] [NomeClasse]::[NomeVariável] = [ inicialização]


Objetos criados dinâmicamente

a) Objetos são criados dinâmicamente por meio do operador new (semelhante à malloc()
na linguagem C), que retorna um ponteiro para o endereço do objeto.

b) O espaço em memória ocupado pelo objeto é liberado por meio da instrução delete.

c) Os membros de objetos criados dinamicamente são acessados por meio do operador


de dados ().

d) Quando o ponteiro para o objeto é criado por meio da instrução new, a função
construtora é executada.

e) Quando o ponteiro para o objeto é destruído por meio da instrução delete, a função
destrutora é executada.

f) No caso de objetos criados automaticamente, a função destrutora é executada quando


é atingido o término da execução do bloco no qual o objeto foi declarado.

Herança

a) As classes-base incorporam os membros públicos e protegidos da classe base.

b) Isto permite a reutilização de código, ou seja, se é necessário modificar ou adicionar


funções, não é necessário alterar o código-fonte da classe base, mas apenas criar
classes-derivadas que implementem estas funções.

c) Para isso, basta ter à disposição o código-objeto com as classes-base (não é


necessário dispor do código fonte das mesmas). Ou seja, podem ser definidas classes
derivadas a partir de classes base confinadas em bibliotecas.

d) Definindo classe derivada

class [derivada]:[public/private] [base]

e) Qualquer membro público da classe-base é acessível à classe derivada.

f) Os membros protected são acessíveis às funções-membro da classe base e de todas as


classes derivadas.

g) Se nenhum construtor for especificado na classe derivada, o construtor sem


argumentos da classe base será utilizado.
h) Construtores da classe-base:

[derivada]::[derivada] (lista de parâmetros 2) : [base](lista de parâmetros 1) { corpo }

- o construtor da classe derivada recebe a lista de parâmetros 2 e passa lista de


parâmetros 1 para a função construtora da classe base, que é executada.

- Em seguida, as instruções do corpo da função são executadas.

i) O compilador busca o membro na classe-base primeiramente. Não encontrando,


busca na classe-derivada.

Herança pública e privada

Herança pública (ou derivação pública)  Class Agente: public Policia  todos os
membros public da classe base (Policia) são membros public da classe derivada
(Agente) e todos os membros protected da classe base são protected da classe
derivada. Ou seja, a visibilidade dos membros da classe base é mantida na classe
derivada.

a) Herança privada (ou derivação privada)  Class Agente:private Policia  todos os


membros public e protected da classe base serão membros private da classe derivada.

Reescrevendo funções-membro da classe base

a) Quando é necessário adicionar instruções a uma função de uma classe base pré-
compilada (da qual não dispomos do código-fonte), podemos definir uma função de
mesmo nome na classe derivada. Assim, uma chamada a função será feita de modo
único por um objeto da classe derivada.

b) A função na classe derivada chama a função na classe base utilizando o operador de


resolução de escopo (::).

void print()
{
Base::print();
}
Classes Abstratas

Classes abstratas são utilizadas apenas para derivar outras classes, ou seja, nenhuma
instância destas classe (objeto) é declarada (ver classe Conta no diretório heritage1).

Níveis de Herança

Uma classe derivada pode ser subclasse de outra classe derivada. Podemos ter múltiplos
níveis de hierarquia (ver classe ContaPremio no diretório heritage1).

- Obs: os dois mecanismos de incorporação de membros de classes base são herança


(simples e múltipla) e objetos membros.

Herança múltipla

a) Uma classe derivada tem mais de uma classe base

b) Sintaxe de declaração:

class [derivada] : [public/private] [base1] , ... , [public/private] [base n]

c) Ambiguidade em herança múltipla: ocorre, dentre outras situações, quando há


funções de mesmo nome nas classes base, sem correspondência na classe derivada
(não há função alguma com este nome na classe derivada).

d) A ambiguidade é resolvida pelo operador de resolução de escopo (::).

[nome do objeto].[nome da classe]::[nome do membro](lista de parâmetros) ;

e) Os construtores da classe derivada em herança múltipla têm a mesma sintaxe do ítem


(h), seção Herança. As chamadas às classes-base são separtadas por vírgulas. A
construtora da classe derivada deve receber todos os argumentos necessários para
inicializar todos os membros de dados das classes base.

[derivada]::[derivada] (lista de parâmetros 2) :


[base](lista de parâmetros 1A), ..., [base](lista de parâmetros 1N)
Ponteiros

a) Ponteiro variável - contém um endereço de memória.

b) Ponteiro constante - o nome de uma matriz é um endereço constante.

c) Operador de endereços (&) - operador unário que retorna o endereço do operando.

d) Operador de referências(&) - cria uma cópia da variável operando; esta cópia na


verdade é apenas um alias, pois ocupa a mesma posição de memória da variável
original.

e) Operador indireto(*) - retorna o valor armazenado no endereço apontado pelo


operando, ou seja, retorna o valor da variável apontada.

f) Operações com ponteiros:

- int *px, y;
- px = &x ; (atribuição)
- y = *px; (operação indireta)
- cout << &px ; (retorna endereço do ponteiro)
- n = py - px ; (diferença = (&y - &x)/(nº de bytes do tipo apontado))

g) Alocação dinâmica de memória

- Operador new: retorna um ponteiro para o início do bloco de memória alocado. O


operador new, ao contrário de malloc (que retorna um ponteiro void), retorna um
ponteiro para otipo da variável apontada. Torna-se desnecessária a utilização do
operador de molde.

- Operador delete: libera a memória previamente alocada por new. Delete recebe como
argumento o ponteiro retornado por null.
Alocação Dinâmica em C/C++

a) Considere a instrução em C

struct MY_STRUCT S;

Que declara uma estrutura do tipo MY_STRUCT; o programa aloca memória


automaticamente esta variável.

b) Contudo, se declaramos um ponteiro para MY_STRUCT

struct MY_STRUCT *S;

O ponteiro é incializado com um endereço inválido (NULL). É necessário atribuir um


endereço para este ponteiro, o que é feito (em C) pelo operador malloc:

S = (struct MY_STRUCT *) malloc(sizeof(MY_STRUCT));

c) Esta instrução aloca a memória necessária e retorna um ponteiro genérico void. Este
tipo de ponteiro não pode ser diretamente acessado, sendo necessário utilizar o
operador de molde (struct MY_STRUCT *) para convertê-lo para pobteiro para
MY_STRUCT. (obs: o operador sizeof retorna o tamanho do operando em bytes).

d) Em C++, a alocação dinâmica de memória é feita com o operador new, que considera
o tipo deponteiro a ser retornado, dispensado a utilzação do operador de molde.

S = new MY_STRUCT;

e) O operador new retorna um ponteiro do tipo indicado na instrução para o primeiro


byte do objeto ou variável.

f) O operador new, ao alocar memória para um objeto, faz com que sua função
construtora seja automaticamente executada. Logo, é possível passar parâmetros para
o construtor na própria instrução de alocação dinâmica de memória:

- declara ponteiro para instância da classe MyClass

MyClass *Obj;

- aloca memória para o ponteiro

Obj = new MyClass(12,122,”PFC”);

g) O destrutor de um objeto criado automaticamente é executado quando é atingido o


término da execução do bloco no qual o objeto foi definido.

h) O destrutor de um objeto alocado dinâmicamente (via operador new) é executado


quando a memória ocupada pela instância é liberada (via operador delete), o que pode
ser feito antes do término da execução do bloco.

i) Obviamente, é possível alocar dinamicamente não apenas objetos, mas também tipos
de variáveis pré-definidos na linguagem. Considere as instruções a seguir:

int *ptr;
ptr = new int;

j) Utilizando os operadores new e delete com arrays (alocação dinâmica de vetores)

int *intNotas;
int intSize = 10;
float media=0;

intNotas = new int[intSize];

.....

delete [] intNotas;

k) O código a seguir ilustra a alocação dinâmica em C++, através da utilização dos


operadores new e delete com arrays. Também há um exemplo de atribuição entre
objetos (página 26, Treinamento em linguagem C++, módulo 2).
#include <conio.h>
#include <iostream.h>
#include <string.h>

// declara classe MFC


class MFC
{ private:// membros de daods públicos da classe
char *strMyStringPtr;// ponteiro para char

public:
MFC(char*);// construtor
void vdPutData();// função de acesso
void vdUpDateMyString(char*);
~MFC();// destrutor };

MFC::MFC(char *string)
{ int l=strlen(string);

// aloca memória para o membro de dados private da classe


// o endereço da nova string é armazenado em strMyStringPtr
strMyStringPtr = new char[l+1];

strcpy(strMyStringPtr,string); }

void MFC::vdPutData()
{ cout << strMyStringPtr << endl;}

void MFC::vdUpDateMyString(char *string)


{ int l=strlen(string);

// libera memória previamente alocada na função construtora


// obs: poderia ter sido utilizxado um ponteiro para char temporário
delete [] strMyStringPtr;

// aloca memória para o membro de dados private da classe


// o endereço da nova string é armazenado em strMyStringPtr
strMyStringPtr = new char[l+1];

strcpy(strMyStringPtr,string); }

MFC::~MFC()
{ // libera a memória alocada pelo operador new
delete [] strMyStringPtr; }

void main()
{
MFC Obj1("Saraiva"),Obj2("Kadesh");

Obj1.vdPutData(); getch();
Obj1.vdUpDateMyString("This one is much longer");
Obj1.vdPutData(); getch();
Obj1 = Obj2 ;
Obj1.vdPutData(); getch();
}
Sobrecarga de operadores

a) Os operadores utilizados com os tipos básicos da linguagem C++ não podem ser
utilizados com os tipos definidos pelo usuário, como classes, estruturas e
enumerações.

b) Sobrecarregar um operador significa redefinir seu símbolo, de modo que possa ser
utilizado com tipos definidos pelo usuário.

c) A sobrecarga de operadores é feita através de funções operadoras.

d) As funções operadoras podem ser globais ou membros de classe.

e) A sobrecarga só pode ser feita a partir dos operadores existentes na linguagem.

f) Os seguintes operadores não podem ser sobrecarregados: operador ponto (.), operador
de resolução de escopo (::) e operador condicional ternário (?:).

Unários  não recebem parâmetros  pré ou pós fixados ?


Binários  recebem um único parâmetro

g) A palavra reservada operator deve vir logo após o tipo retornado pela função
operadora, em sua declaração.

[tipo] operator [operador]([parâmetro – se for binário])

h) Toda vez que [operador] for aplicado a um objeto da classe da qual a função
operadora acima é membro, ela será chamada.

i) Considere a sobrecarga do operador unário pré-fixado ++:

Declaração: void operator ++( )


Chamada : ++Obj (equivale a Obj.operator++())
Operadores unários pré e pós fixados

a) As funções operadoras que implementam a sobrecarga de operadores unários não


recem parâmetro algum.

b) Para identificar um operador como pós-fixado, inserir a palavra chave int entre
parênteses; ela apenas servirá, neste contexto, para permtir ao compilador diferenciar
as funções operadoras pós e pré-fixadas.

c) A operação pós-fixada deve ser implementada pelo programador.

Conversões

a) Conversões entre tipos básicos: as conversões entre tipos básicos são feitas de forma
implícita (conversão implícita) ou de forma explícita (conversão explícita) através do
operador de molde.

b) Conversão de um objeto para tipo básico: para realizar a conversão de um objeto para
um tipo básico é necessário sobrecarregar o operador de molde, criando uma função
chamada função conversora. Funções conversoras: retornam um valor para o tipo
desejado; na sua declaração não deve ser inserido o tipo do valor retornado, pois esta
informação está contida no operador de molde sobrecarregado ( conversão de objeto
para tipo básico ).

c) Conversão de um tipo básico para objeto: para realizar a conversão de um tipo básico
para objeto é necessário sobrecarregar o operador de atribuição.

Básico Objeto
Básico Operador de molde ou Sobrecarga do operador de
conversão implícita atribuição
Objeto Função conversora (1) Função conversora
(sobrecarga do operador (2) Construtor para conversão
de molde)
Conversão de objeto  tipo básico
Sobrecarga do operador de molde – função conversora
class string
{
private:
char str[20];

public:
string() { str[0]=0; }
string(char s[]) { strcpy(str,s);}
// função conversora – não especificar tipo
operator int();
// função conversora – não especificar tipo
operator float();
~string() {}
};

string::operator int()
{
return atoi(str);
}

string::operator float()
{
return atof(str);
}

void main()
{

string str1(“12”), str2(“123.33”);


int x ;

float y = str2; // conversão implícita


x = int(str1); // conversão explícita

cout << x << endl;


cout << y << endl;

getch();

}
Listas Encadeadas

a) Inicializa ponteiro marcador do topo da lista

void *head = NULL;

b) Rotina de inserção

- aloca memória para novo elemento

MyStruct *novo = new MyStruct;

- rotina de entrada dos dados da estrutura

- encadeamento da lista

// aponta para NULL ou para o elemento anteriormente inserido na lista


novo  próximo = head;

// reposiciona head no topo da lista


head = novo;

c) Rotina de busca

- aloca memória para elemento atual

MyStruct *atual = new MyStruct;

- aponta para o topo da lista

atual = (MyStruct *)head;

- percorre a lista

while(atual!=NULL)
{
…….
atual = atual  próximo;
}
d) Rotina de exclusão

- aloca memória para elemento atual

MyStruct *atual = new MyStruct;

- aponta para o topo da lista

atual = (MyStruct *)head;

- percorre a lista

while(atualpróximo!=NULL)
{
if(atualpróximocampo = valor) atualpróximo=atualpróximopróximo;
…….
atual = atual  próximo;
}

e) Rotina de exclusão especial para elemento no topo da lista – ver código em anexo

f) Rotina de exclusão especial para elemento no fim da lista – ver códgio em anexo.
Treinamento em linguagem C++
Capítulo 11 - Ponteiros
Listas encadeadas (ou listas ligadas)

#include <iostream.h>
#include <conio.h>
#include <stdlib.h>

struct Livro
{ char nome[40];
int code;
float preco;
Livro *proximo;// ponteiro para Livro };

void *head = NULL;

inline int Empty(Livro* atual){ return (atual==NULL)?1:0; }

void Inserir()
{
// aloca memória para novo elemento
Livro *novo = new Livro;

cout << "Nome : " ; cin >> novo->nome;


cout << "Codigo: "; cin >> novo->code;
cout << "Preco : "; cin >> novo->preco;

// encadeamento da lista
novo->proximo = (Livro *) head;
head = novo;
}

void Listar()
{
Livro *atual= (Livro *)head;

if(!Empty(atual))
while(atual!=NULL)
{
cout << "Nome : " << atual->nome << endl;
cout << "Codigo: " << atual->code << endl;
cout << "Preco : " << atual->preco << endl <<endl;
atual = atual->proximo;
}
}

void Remover(int code)


{
Livro *atual= (Livro *)head;
Livro *aux = (Livro *)NULL;
// rotina especial para remover elemento do topo da lista
if(atual->code==code)
{ head = atual->proximo;
return; }

if(!Empty(atual))
while(atual->proximo!=NULL)
{
if(atual->proximo->code==code)
{ atual->proximo = atual->proximo->proximo;
return; }

aux = atual;
atual = atual->proximo;
}

// rotina especial para remover elemento do fim da lista


if(atual->code==code) aux = NULL;// aux aponta para a posição anterior na lista

void Pesquisar(int code)


{
Livro *atual= (Livro *)head;

if(!Empty(atual))
while(atual!=NULL)
{
if(atual->code==code)
{
cout << "Nome : " << atual->nome << endl;
cout << "Codigo: " << atual->code << endl;
cout << "Preco : " << atual->preco << endl <<endl;
//break; se habilitado, impede listagem de ocorrências múltiplas
//do valor da chave de busca
}

atual = atual->proximo;
}

void main()
{

int op,code;

do
{
cout << "[1] Insere elemento na lista" << endl;
cout << "[2] Remove elemento da lista" << endl;
cout << "[3] Busca elemento na lista" << endl;
cout << "[4] Listar elementos"<< endl;
cout << "[5] Sair do programa" << endl;
cout << "Selecione opcao : ";
cin >> op;

switch(op)
{
case 1: Inserir();break;

case 2: cout << endl;


cout << "Codigo = ";
cin >> code;
Remover(code);
break;

case 3: cout << endl;


cout << "Codigo = ";
cin >> code;
Pesquisar(code);
break;

case 4: Listar();break;

case 5: exit(0);

default: cout << "Opcao invalida !";


}

}
while(1);

}
Ponteiros para funções

a) Declaração de um ponteiro para função do tipo void (atribuir ao ponteiro ptr o


endereço da função)
void *ptr;
ptr = MyFunction;

a) poderíamos condensar as duas linhas acima em uma única instrução:

void *ptr = MyFunction;

b) Note a ausência dos parênteses. Se estivessem presentes, estaríamos atribuindo ao


ponteiro não o endereço da função, mas o valor por ela retornado.

c) Para fazer uma chamada a função utilizado o ponteiro:

(*ptr)();

d) Matriz de ponteiros para funções

int (*ptr[])(int) = { Soma, Multiplica, EhMaior, EhIgual};

e) A instrução (*ptr[i])() corresponde à chamada da (I-1)-ésima função elemento da


matriz.
Gravando uma linha por vez no arquivo de saída

#include <fstream.h>

void main()
{
ofstream fout("teste.txt");

fout << "Line 1 - This is Chapter 13"<< endl;


fout << "Line 2 - -----------------------------"<< endl;
}

a) o arquivo de cabeçalho FSTREAM.H contém as declarações das classes OFSTREAM


e IFSTREAM.
b) declaramos um objeto da classe OFSTREAM, inicializando-o com o nome do
arquivo de saída.
c) o operador sobrecarregado << imprime o argumento (a string) no arquivo de saída.
d) não é necessário fechar o arquivo explicitamente, pois a função destrutora da classe
ofstream irá fazê-lo quando o objeto fout for descartado.

Lendo uma linha por vez do arquivo de entrada

#include <fstream.h>

void main()
{
const int MAX=80;
char buff[MAX], fim_de_linha='.';

ifstream fin("teste.txt");

while(fin)
{
fin.getline(buff,MAX,fim_de_linha);
cout << buff;
}
}

a) declaramos um objeto da classe IFSTREAM, inicializando-o com o nome do arquivo


de entrada.
b) o método getline() armazena no máximo MAX caracters por linha no buffer buff. A
leitura é interrompida antes deste limite se for encontrado o caracter fim_de_linha.
c) o argumento fim_de_linha é opcional; se não for fornecido, o valor padrão assumido
é '\n'.
d) após sua leitura, cada linha é impressa na tela (saída padrão).

Identificando o fim de arquivo (eof)

a) Objetos da classe IFSTREAM têm um valor que pode ser testado para a verificação
de fim de arquivo (EOF).
b) Qualquer mensagem (chamada de um membro de objeto da classe) retornará o valor
zero em caso de fim de arquivo.
c) Portanto, o laço while acima poderia ser reescrito, de forma mais compacta, como:

while(fin.getline(buff,MAX,fim_de_linha)) cout << buff;

A função open()

a) Os objetos da classe IFSTREAM e OFSTREAM podem ser incializados na


declaração (através do construtor da classe) ou após a declaração, através da função
OPEN.
b) Tanto a função OPEN quando o construtor das classes IFSTREAM e OFSTREAM
podem receber dois parâmetros:

- o nome do arquivo de entrada/saída;


- o modo de abertura do arquivo (Guia de Consulta Rápida - Página 25)

ios::in (default para objetos da classe ifstream) - leitura.


ios::out ( default para objetos da classe ofstream) - gravação.
ios::app - grava a partir do final do arquivo.

Lendo um caracter por vez do arquivo de entrada

#include <fstream.h>
void main()
{
ifstream fin;
char ch;

fin.open("teste.txt",ios::in);

while(fin.get(ch)) cout << ch;


}

a) declaramos um objeto da classe IFSTREAM.


b) utilizamos o método OPEN para inicializar o objeto fin com o nome do arquivo de
entrada.
c) fornecemos, a título de ilustração, o segundo argumento da função OPEN, que é o
modo de abertura do arquivo. Este argumento é dispensável neste caso, pois é o modo
padrão para objetos da classe IFSTREAM.
d) o método get() retorna um carater lido do arquivo de entrada.

Gravando um caracter por vez no arquivo de saída

#include <fstream.h>

void main()
{
ofstream fout;
char ch=0;

fout.open("teste.txt",ios::out);

while(ch!='.')
{
cin >> ch;
fout.put(ch);
}
}

O programa lê um caracter por vez do teclado (entrada padrão) e o imprime no arquivo


de saída, através do método put, que recebe este caracter como argumento. O laço
prossegue até que seja digitado o caracter ponto.

Exemplo de operações com arquivos em C++

/*
Treinamento em Linguagem C++
Capitulo 13 - Operacoes com Arquivos
[1] Gravar em um arquivo de saída as linhas de um arquivo de entrada que
satisfaçam o seguinte critério:
a) comecem com vogal
b) tenham uma consoante no quinto caracter

[2] Imprimir o número de cada linha (referente à sua posição no arquivo de entrada).
[3] Exibir o número médio de caracteres/linha do arquivo de entrada.
[4] Exibir a percentagem de linhas do arquivo de entrada que satisfazem a condição [1]
*/

#include <fstream.h>
#include <stdio.h>
#include <iomanip.h>
#include <conio.h>

// (0)consoante (1)vogal (-1)caracteres nao alfabeticos


inline int VogalConsoante(char ch)
{
if(((ch>=97)&&(ch<=122)||(ch>=65)&&(ch<= 90)))
if((ch==97)||(ch==101)||(ch==105)||(ch==111)||(ch==117)||(ch==65)
||(ch== 69)||(ch== 73)||(ch== 79)||(ch== 85))
return 1;
else return 0;

return(-1);
}

void main()
{
ifstream in; // declara objeto da classe ifstream
ofstream out;// declara objeto da classe ofstream

// requisita nomes dos arquivos de entrada e saida


char input[20],output[20];
cout << "Nome do arquivo de entrada = ";gets(input);
cout << "Nome do arquivo de saida = ";gets(output);

in.open(input,ios::in) ;// inicializa objeto da classe ifstream


out.open(output,ios::out);// inicializa objeto da classe ofstream

const int MAX=81;// define tamanho máximo do buffer


char buffer[MAX];// declara buffer utilizado pelo método getline
int lin=0,ch=0 ;// contadores de linhas e caracteres
int lin2=0 ;// contador de linhas que satisfazem a condição 1

while(in.getline(buffer,MAX))// se EOF, a mensagem retorna 0


{
lin++;
ch+=strlen(buffer);

if((VogalConsoante(buffer[0])==0)&&(VogalConsoante(buffer[4])==1))
{
out << setfill('0') << setw(3) << lin << " - " << buffer << endl;
lin2++;
}
}
cout << endl;
cout << "Numero total de linhas no arquivo de entrada = " << lin << endl;

cout << "Numero medio de caracters/linha = " << setiosflags(ios::fixed) <<


setprecision(1) << (float)ch/lin << endl;

cout << "Percentagem de linhas que satisfazem a condicao = " << setiosflags(ios::fixed) <<
setprecision(1) << 100*(float)lin2/lin << "%" << endl;

getch();
}

Gravando objetos

#include <fstream.h>

void main()
{
ofstream out(“teste.txt”);
MyClass obj;

…….

out.write((char *)&obj,sizeof(obj));

…….
}

O método write da classe ofstream recebe dois argumentos: o endereço do objeto


(convertido para ponteiro do tipo char) e o número de bytes ocupados pelo objeto (valor
obtido utilizando o operador sizeof()).

Lendo objetos

#include <fstream.h>

void main()
{
ifstream in(“teste.txt”);
MyClass obj;

…….

while(in.write((char *)&obj,sizeof(obj)))
{
…….
}
}

O método read da classe ifstream recebe dois argumentos: o endereço do objeto


(convertido para ponteiro do tipo char) e o número de bytes ocupados pelo objeto (valor
obtido utilizando o operador sizeof()).

Os métodos seekg( ), seekp( ) , tellg( ) e tellp( )

a) Qualquer arquivo em C++ tem dois valores inteiros a ele associados: o ponteiro de
posição corrente de leitura e o ponteiro de posição corrente de gravação.

b) O método seekg(offset,ref) reposiciona o ponteiro de posição corrente de leitura,


deslocando-o offset bytes em relação ao byte ref.

c) O método seekp(offset,ref) reposiciona o ponteiro de posição corrente de gravação,


deslocando-o offset bytes em relação ao byte ref.

d) O método tellg( ) informa a posição do ponteiro corrente de leitura, em bytes em


relação ao início do arquivo.

e) O método tellp( ) informa a posição do ponteiro corrente de gravação, em bytes em


relação ao início do arquivo.

f) No parâmetro ref, podemo fornecer as flags: ios::beg (início do arquivo),


ios::end(final do arquivo) e ios::curr(posição atual); o valor padrão é ios::beg.

Potrebbero piacerti anche