Treino C++
Por: Ale • 29/9/2016 • Ensaio • 7.099 Palavras (29 Páginas) • 618 Visualizações
Página 1 de 29
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
Em C++, as classes permitem ao programador definir novos tipos de dados.
As classes podem ser declaradas pelas palavras-chave STRUCT, UNION e CLASS
As estruturas em C++ podem ter membros de dados e de função; seus membros são public por default.
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.
As classes (propriamente ditas) tem membros de dados (variáveis de instância) e membros de função cuja visibilidade é private por default.
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
private: os membros private podem ser acessados apenas pelas funções-membro da classe
public: os membros public podem ser acessados por qualquer função
protected: os membros protected podem ser acessados por qualquer função-membro da classe-base e de suas classes derivadas.
Enumerações
As enumerações permitem ao usuário criar variáveis às quais podem ser atribuídos valores constantes.
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
Forma alternativa de passar parâmetros para uma função
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.
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.
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
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.
As funções inline são tratatadas com macros, o que pode aumentar a velocidade de execução.
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 passagem de parâmetros para fun'ções pode ser feita por valor, por referência ou por ponteiro.
Na chamada por valor, a função chamada cria uma cópia local do argumento passado pela função chamadora.
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 }
A passagem de parâmetros por ponteiro ou por referência permite à função retornar mais de um valor para a função chamadora.
As chamadas de funções com passagem de argumentos por referência ou por valor são idênticas.
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);
}
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
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.
Os membros de dados são normalmente declarados na seção private.
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.
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.
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.
Instrução de chamada a uma função-membro:
ClassName.FunctionName();
A instrução de chamada a uma função membro é chamada de MENSAGEM.
Declaração do corpo da função for a da classe:
[tipo] [ClassName] :: [function_name]()
O operador (::) é o operador de resolução de escopo. Este operador informa que [function_name] é membro da classe [ClassName].
Função construtora ou construtor : função que tem o mesmo nome da classe e é chamada automaticamente quando o objeto é declarado.
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]()
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).
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
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
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)
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]
A formulação acima pode ser utilizada para substituir a instrução
#define [name] [value]
Objeto como membros de dados de uma classe
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;
}
Vemos que Birthday é uma instância da classe Date, e que está definida como um membro de dados da classe President.
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.
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)
Conforme já mencionado, os membros de uma estrutura são public por default e os de uma classe são private por default.
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
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.
As funções sobrecarregadas são diferenciadas pelo compilador não pelo tipo de variável que retornam, mas pela lista de argumentos.
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
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)
};
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.
O objeto B é passado como argumento para a função-membro do objeto A.
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 ;
Este resultado (um objeto da classe Venda) é atribuído ao objeto Temp, declarado no bloco principal do programa.
Membros de dados private static
Quando um membro de dados é declarado como static, ele é compartilhado por todos os objetos pertencentes à classe.
Os membros de dados private auto (classe de armazenamento default) são individualizados por objeto, ou seja, cada membro é criado para cada objeto.
As variáveis de instância static comportam-se de forma semelhante às variáveis static convencionais.
Os membros de dados static devem ser declarados através da instrução
[tipo] [NomeClasse]::[NomeVariável] = [ inicialização]
Objetos criados dinâmicamente
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.
O espaço em memória ocupado pelo objeto é liberado por meio da instrução delete.
Os membros de objetos criados dinamicamente são acessados por meio do operador de dados (().
Quando o ponteiro para o objeto é criado por meio da instrução new, a função construtora é executada.
Quando o ponteiro para o objeto é destruído por meio da instrução delete, a função destrutora é executada.
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
As classes-base incorporam os membros públicos e protegidos da classe base.
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.
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.
Definindo classe derivada
class [derivada]:[public/private] [base]
Qualquer membro público da classe-base é acessível à classe derivada.
Os membros protected são acessíveis às funções-membro da classe base e de todas as classes derivadas.
Se nenhum construtor for especificado na classe derivada, o construtor sem argumentos da classe base será utilizado.
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.
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.
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
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.
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
Uma classe derivada tem mais de uma classe base
Sintaxe de declaração:
class [derivada] : [public/private] [base1] , ... , [public/private] [base n]
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).
A ambiguidade é resolvida pelo operador de resolução de escopo (::).
[nome do objeto].[nome da classe]::[nome do membro](lista de parâmetros) ;
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
Ponteiro variável - contém um endereço de memória.
Ponteiro constante - o nome de uma matriz é um endereço constante.
Operador de endereços (&) - operador unário que retorna o endereço do operando.
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.
Operador indireto(*) - retorna o valor armazenado no endereço apontado pelo operando, ou seja, retorna o valor da variável apontada.
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))
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++
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.
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));
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).
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;
O operador new retorna um ponteiro do tipo indicado na instrução para o primeiro byte do objeto ou variável.
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”);
O destrutor de um objeto criado automaticamente é executado quando é atingido o término da execução do bloco no qual o objeto foi definido.
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.
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;
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;
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
#include
#include
// 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
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.
Sobrecarregar um operador significa redefinir seu símbolo, de modo que possa ser utilizado com tipos definidos pelo usuário.
A sobrecarga de operadores é feita através de funções operadoras.
As funções operadoras podem ser globais ou membros de classe.
A sobrecarga só pode ser feita a partir dos operadores existentes na linguagem.
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
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])
Toda vez que [operador] for aplicado a um objeto da classe da qual a função operadora acima é membro, ela será chamada.
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
As funções operadoras que implementam a sobrecarga de operadores unários não recem parâmetro algum.
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.
A operação pós-fixada deve ser implementada pelo programador.
Conversões
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.
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 ).
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ásicoObjetoBásicoOperador de molde ou conversão implícitaSobrecarga do operador de atribuiçãoObjetoFunção conversora (sobrecarga do operador de molde)Função conversora
(2) Construtor para conversão
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
Inicializa ponteiro marcador do topo da lista
void *head = NULL;
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;
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;
}
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;
}
Rotina de exclusão especial para elemento no topo da lista – ver código em anexo
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
#include
#include
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 <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 <//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
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;
poderíamos condensar as duas linhas acima em uma única instrução:
void *ptr = MyFunction;
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.
Para fazer uma chamada a função utilizado o ponteiro:
(*ptr)();
Matriz de ponteiros para funções
int (*ptr[])(int) = { Soma, Multiplica, EhMaior, EhIgual};
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
void main()
{
ofstream fout("teste.txt");
fout << "Line 1 - This is Chapter 13"<< endl;
fout << "Line 2 - -----------------------------"<< endl;
}
o arquivo de cabeçalho FSTREAM.H contém as declarações das classes OFSTREAM e IFSTREAM.
declaramos um objeto da classe OFSTREAM, inicializando-o com o nome do arquivo de saída.
o operador sobrecarregado << imprime o argumento (a string) no arquivo de saída.
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
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;
}
}
declaramos um objeto da classe IFSTREAM, inicializando-o com o nome do arquivo de entrada.
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.
o argumento fim_de_linha é opcional; se não for fornecido, o valor padrão assumido é '\n'.
após sua leitura, cada linha é impressa na tela (saída padrão).
Identificando o fim de arquivo (eof)
Objetos da classe IFSTREAM têm um valor que pode ser testado para a verificação de fim de arquivo (EOF).
Qualquer mensagem (chamada de um membro de objeto da classe) retornará o valor zero em caso de fim de arquivo.
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()
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.
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
void main()
{
ifstream fin;
char ch;
fin.open("teste.txt",ios::in);
while(fin.get(ch)) cout << ch;
}
declaramos um objeto da classe IFSTREAM.
utilizamos o método OPEN para inicializar o objeto fin com o nome do arquivo de entrada.
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.
o método get() retorna um carater lido do arquivo de entrada.
Gravando um caracter por vez no arquivo de saída
#include
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
#include
#include
#include
// (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
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
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( )
- 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.
- 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.
- 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.
- O método tellg( ) informa a posição do ponteiro corrente de leitura, em bytes em relação ao início do arquivo.
- O método tellp( ) informa a posição do ponteiro corrente de gravação, em bytes em relação ao início do arquivo.
- 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.
...
Disponível apenas no TrabalhosGratuitos.com