You are on page 1of 7

Streams em linguagem C

++
O uso das classes de strea ms para simplificar operações de I/O em C++
Tarcísio Lopes

“Um elefante é um cavalo projetado por um comitê”. Quer dizer, funciona e tem algumas
características próprias, mas é enorme, pesado, lerdo e difícil de manter. Se for branco, então... é um
elefante branco.
Esta pérola de engenharia filosófica se aplica bem à linguagem C++. A linguagem C
original foi desenvolvida por uma dupla, Brian W. Kernighan e Dennis M. Ritchie. Posteriormente,
Bjarne Stroustrup encarregou-se dos acréscimos que deram origem à linguagem C++. Sem
menosprezar o valor do trabalho das grandes equipes, o fato de a linguagem ser o resultado de tão
poucas cabeças funcionando em estreita sintonia responde por suas características únicas de
compacidade, concisão e eficiência (tanto Kernighan e Ritchie, quanto Stroustrup desenvolveram
seus trabalhos nos Laboratórios Bell).
Mesmo quando comitês ANSI se propuseram a padronizar C e C++, eles partiram das
publicações originais dos autores como rascunho-base e usaram o critério de adotar aquilo que era
de uso corrente para solucionar eventuais ambigüidades – para alivio geral.
No entanto, a genial simplicidade pode às vezes ser enganosa. Tomemos por exemplo o
sistema de I/O por classes de streams em C++.
Geralmente uma das primeiras coisas que se aprende em C++ é usar o operador de inserção
<< para apresentar alguma saída em tela. Por exemplo:

int i = 10;
double d = 12.34;
cout << “i = “
<< i
<< “, d = “
<< d
<< “\n”;
O operador << tem associatividade da esquerda para a direita; ele retorna uma referência
para o objeto ostrea m para o qual é invocado. Isso possibilita o uso “em cascata” mostrado.
Essas linhas exibem na saída padrão (a tela) o seguinte:

i = 10, d = 12.34
Um programa C++ já abre automaticamente a saída padrão cout, correspondente a stdout
em C.

Outras funções que dizem respeito à formatação são fill(). muitas vezes o novato não se sente encorajado a mergulhar na complexidade e no poder do sistema de I/O por streams de C++. Os strea ms suportam diretamente os tipos fundamentais de dados: char. long.h> // Necessário para manupuladores com parâmetros . width() e precision() .O fato é que. A formatação dos tipos inteiros segue as mesmas regras da função printf() . long double e void*. float. Como os manipuladores recebem uma referência a um strea m como argumento. embora o programador possa fazer alterações ajustando flags. e como faze-lo. C++ proporciona classes para suportar fluxos de dados para o console (monitor). Eis um exemplo de uso: #include <iostream. quanto como consumidores. cout << &intVar. retornando uma referência a esse mesmo strea m. como a execução de I/O básico é tão simples e concisa. O que são streams? Um strea m é uma abstração para um fluxo de dados. Para exibir endereços de variáveis. cerr // Corresponde a stderr. eles podem ser embutidos em uma cadeia de inserção para alterar o estado do strea m. pode-se usar o ponteiro void*: int intVar. Tal fluxo ocorre entre uma fonte (source) e um consumidor (sink). buffers de memória. funcionando tanto como fontes. arquivos e strings. Além de cout. Manipuladores Manipuladores são operadores similares a funções que permitem alterar algumas das variáveis de formatação. setf() e unsetf() . outras três classes de objetos são automaticamente abertas pelos programas C++: cin // Corresponde a stdin. int. Para esta finalidade. // Exibe o endereço de intVar. a classe ios tem as funções membros flags() . Procuraremos mostrar neste artigo por que vale a pena ir fundo no estudo dos strea ms . char* (string).h> #include <iomanip. short. clog // cerr com buffer. double. que vai muito além desses recursos básicos.

25 Hierarquia A hierarquia das classes de strea ms é bastante complexa devido ao uso freqüente da herança múltipla. } Este programa produz a seguinte saída na tela: 1995 2001 39 Podemos também definir nossos próprios manipuladores: #include <iostream. } A saída será a seguinte: R$1. k = 39. return 0. cout << real << debito << real << credito. Trataremos aqui de alguns aspectos fundamentais. convém estudar o diagrama geral de hierarquia de classes C++ . j = 2001. Para se ter uma idéia precisa. As classes baseadas em ios acessam aquelas baseadas em strea mbuf através de ponteiros ios e suas .25.65.h> // Precede o valor com um tab e o sinal do Real.65 R$3. Ambas são classes de baixo nível. Há duas famílias paralelas de classes iostrea m : uma derivada de strea mbuf e outra derivada de ios. credito = 3.int main() { int i = 1995. return 0. cout << setw(6) << i << setw(6) << j << setw(6) << k. cada uma com um conjunto diferente de funções-membro. ostream& real(ostream& output) { return output << “\tR$”. Todas as classes de strea ms têm pelo menos uma destas como base. } int main() { float debito = 1.

cout << “\nDados digitados: “ << nTipo. double valor. return 0. As classes baseadas em ios utilizam as funções membros da família streambuf. char *unidades. } .nome << “ “ << m.valor >> m.unidades = new char[16].nome = new char[16]. nTipo. istream& operator >> (istream& s. Streams e tipos de dados do programador Tratando-se de tipos de dados definidos pelo programador. O programador pode também derivar suas próprias funções e bibliotecas diretamente de streambuf.derivadas contem um ponteiro para strea mbuf .nome >> m. cout << “\nDigite nome.unidades. return s. cabe a este sobrecarregar os operadores << e >>. novoTipo& m) { s >> m. valor e unidades: “.h> struct novoTipo { char *nome. strea mbuf representa uma interface para a memória e dispositivos físicos. filebuf e strstrea mbuf . return s. } int main() { novoTipo nTipo. tais classes utilizam strea mbuf para executar I/O formatado e com checagem de erros. } // Sobrecarregando >>. novoTipo& m) { s << m. } // Sobrecarregando <<. sendo usada quando há pouca ou nenhuma necessidade de formatação. ostream& operator << (ostream& s. #include <iostream. tal como C++ faz com as classes conbuf. cin >> nTipo.unidades.valor << “ “ << m. nTipo.

essas classes convenientemente proporcionam construtores e funçõesmembros para criação de arquivos. if (!f1) cerr << “Erro abrindo arq1. } ifstream inpfile(argv[1]). A classe istrstrea m proporciona essas mesmas capacidades com flexibilidade melhorada. Para usa-las. O exemplo a seguir utiliza. char **argv) { int ref. } Processamento de strings Em C. vários dos conceitos vistos acima. ostrstrea m herda as funções de ostream. deve-se incluir o arquivo strstrea. if (inpfile) { .putc(ch).TXT para ARQ2. while (f2 && f1.”. if (argc == 1) { cout << “\nIndicar nome de arquivo.txt”. similarmente. if (!f2) cerr << “Erro abrindo arq2. usamos as funções sscanf e sprintf para formatação de strings na memória.h . ifstream f1(“ARQ1. além das classes de processamento de strings. #include <fstream.get(ch)) f2.I/O de arquivos Para usar as classes de entrada/saída de arquivos ofstrea m e ifstrea m é necessário incluir (#include) o arquivo fstrea m.TXT”). istrstrea m herda as funções de istrea m. ofstream f2(“ARQ2.h> int main(int argc. float preco. ofstrea m herda as operações de extração de istrea m. Além de lidar com I/O de arquivos. return(-1).txt”.h> int main() { char ch.h> #include <iomanip.h> #include <string.h> #include <strstrea. char descricao[41].h.TXT”). O seguinte exemplo copia o arquivo ARQ1. como manipuladores e I/O de arquivos: #include <fstream. return 0.TXT.

Todos os bons livros sobre C++ dedicam amplo espaço a essa matéria. istrstream instr(inpbuffer. nossa idéia é ter uma função catalisadora. Voltando ao exemplo do elefante e do cavalo. 41). Mergulhando mais fundo O assunto streams em C++ é abrangente e complexo. dentro do espaço de que dispomos aqui. instigando os programadores para que busquem ir fundo no assunto. // Formata floats. É essa complexidade que faz com que poderosas operações de I/O sejam executadas de forma eficiente com poucas linhas de código. cout. // Linefeed não é copiado. Uma fonte importante de informações é também a documentação específica de cada compilador. strlen(inpbuffer)). .setf(ios::showpoint).char inpbuffer[81]. while (inpfile. ios::floatfield). além de uma visão geral. int linenum = 0. Como sempre.getline(descricao. cout << ++linenum << “: “ << ref << “\t” << setprecision(2) << preco << “\t” << descricao << “\n”. // Sempre mostrar ponto decimal.setf(ios::fixed. cout. confirmando as características de C++ que comentamos no começo do artigo. que geralmente tem. } } return 0. Este trabalho não pretende de forma alguma esgotar o assunto.getline(inpbuffer. instr >> ref >> preco >> ws. instr. trata-se da complexidade com uma função: gerar a simplicidade. detalhes que propiciam uma visão da filosofia de implementação de cada fabricante. dada a sua importância. O manipulador ws permite que o espaço em branco existe antes da string descricao seja saltado. } Observe o uso das flags de formatação e dos manipuladores setf e setprecision fazem com que os preços sejam mostrados no formato normalmente utilizado para dinheiro.81)) { // instr = string stream.

.O tempo aplicado na investigação desta área será sempre amplamente compensado pelo ganho em tempo de codificação e o poder obtido nas operações de I/O.