| FAQ Lite | ||||||||||||||||||||
| Input/output via <iostream.h> e <stdio.h> | ||||||||||||||||||||
|
||||||||||||||||||||
| [ 15.2 ] Porque meu programa entra em loop infinito quando alguém entra um caracter não-válido ? |
| Por exemplo, suponha que você tenha o seguinte código, que lê inteiros a partir de cin: |
#include <iostream.h>
main()
{
cout << "Enter numbers separated by whitespace (use -1 to quit): ";
int i = 0;
while (i != -1) {
cin >> i; // BAD FORM — See comments below
cout << "You entered " << i << '\n';
}
}
| O problema com esse código é que ele carece de verificações
para certificar-se que não está recebendo um caracter não-válido como input. Em
particular, se alguém entra com qualquer valor que não se pareça com um inteiro, como
por exemplo "x", o stream cin cai em um failed state e todos os inputs subseqüentes são
retornados sem qualquer processamento. Em outras palavras, o programa entra em loop
infinito. Se 42 foi o
último número lido com sucesso, o programa vai exibir a mensagem You entered 42 repetidamente. Uma maneira simples de verificar os dados de entrada é retirar a requisição de entrada do corpo do loop while, e colocá-la na expressão de controle do loop while. Por exemplo: |
#include <iostream.h>
main()
{
cout << "Enter a number, or -1 to quit: ";
int i = 0;
while (cin >> i) { // GOOD FORM
if (i == -1) break;
cout << "You entered " << i << '\n';
}
}
| Isso fará com que o loop while se encerre quando você receber um
fim-de-arquivo, receber um valor não-inteiro e ainda quando você receber uma valor -1. Naturalmente você pode eliminar o break alterando a expressão de controle do loop while de while (cin >> i) para while ((cin >> i) && (i != -1)) mas esse não é realmente o ponto de interesse central desse FAQ, já que esse FAQ ocupa-se de iostreams, e não de critérios para programação estruturada. |
| [ 15.3 ] Como funciona essa sintaxe while (cin >> foo) ? |
| Veja o item anterior desse FAQ para ter um
exemplo de funcionamento de uma sintaxe como while (cin >> foo) A expressão (cin >> foo)
chama o operator>> apropriado (por exemplo, ela chama o operator>> que coloca istream no lado
esquerdo da expressão e, se foo for do tipo int, um int& no lado direito). A função istream operator>> retorna seu
argumento a esquerda por convenção, o qual, nesse caso, significa que ela vai retornar cin. Em seguida o
compilador percebe que o istream retornado está em um contexto booleano, então ele chama o operador cast
istream::operator bool(). Ou seja, nesse caso ele chama cin.operator bool (), exatamente como se
você tivesse moldado explicitamente
(bool) cin ou bool(cin). O operador molde operator bool() retorna true se o stream estiver em bom estado, ou false se o stream estiver em um failed state (no caso de void*, os valores retornados serão um pointer não-NULL, ou um pointer NULL respectivamente). Por exemplo, se você faz a operação de leitura além da conta, isto é, faz operação de leitura após ter lido o fim-de-arquivo), ou se a informação atual no stream de entrada não é um valor válido para o tipo foo (por exemplo, se foo é um int e o dado é um caracter "x") o stream vai cair em um failed state e o operador molde vai retornar false A razão pela qual operator>> não retorna simplesmente um valor booleano indicando que a operação foi bem sucedida é para suportar sintaxe cascading cin >> foo >> bar; O operator>> é transitivo a esquerda, o que significa que o comando acima é verificado sintaticamente como: cin >> foo) >> bar; Em outras palavras, se nós substituirmos operator>> pelo nome de uma função normal como readFrom(), isso se torna a expressão: readFrom( readFrom(cin, foo), bar); Como sempre, começamos a resolução pela expressão mais interna. Devido a associatividade a esquerda de operator>>, a expressão cin >> foo se torna a expressão mais a esquerda. Essa expressão retorna cin (mais precisamente, retorna a referência para o seu argumento da esquerda) para a próxima expressão. A próxima expressão também retorna (a referência para) cin, mas essa segunda referência é ignorada, uma vez que é a expressão mais externa nesse conjunto de expressões. |
int i = 0;
while (! cin.eof()) { // WRONG!
cin >> x;
++i;
// Work with x ...
}
| Do que você realmente precisa é: |
int i = 0;
while (cin >> x) { // RIGHT!
++i;
// Work with x ...
}
| [ 15.5 ] Porque meu programa ignora meu pedido de input após a primeira interação ? |
| Porque o extrator numérico deixa não-dígitos
atrás do buffer de entrada. Se o seu código se parece com: |
char name[1000];
int age;
for (;;) {
cout << "Name: ";
cin >> name;
cout << "Age: ";
cin >> age;
}
| O que você realmente quer é: |
for (;;) {
cout << "Name: ";
cin >> name;
cout << "Age: ";
cin >> age;
cin.ignore(INT_MAX, '\n');
}
| [ 15.6 ] Como eu posso prover impressão para minha class Fred ? |
| Use sobrecarga de operator para prover um operador friend de deslocamento para a esquerda, operator << |
#include <iostream.h>
class Fred {
public:
friend ostream& operator<< (ostream& o, const Fred& fred);
// ...
private:
int i_; // Just for illustration
};
ostream& operator<< (ostream& o, const Fred& fred)
{
return o << fred.i_;
}
main()
{
Fred f;
cout << "My Fred object: " << f << "\n";
}
| Nós usamos uma função não-membro (uma friend nesse caso) uma vez que o objeto Fred é um operando à direita do operador
<<. Se o objeto Fred pudesse estar do lado esquerdo de <<, ou seja, myFred << cout ao invés de cout << myFred nós poderíamos ter usado uma função membro nomeada como operator << Note que operator << retorna o stream. Essa é a razão pela qual as operações de input podem ser em cascata. |
| [ 15.7 ] Como eu posso prover input para minha class Fred ? |
| Use sobrecarga de operator para prover um operador friend de deslocamento para a direita, operator >>. Isso é similar ao operador de saida, exceto que o parâmetro não tem um const: "Fred&" ao invés de "const Fred&" |
#include <iostream.h>
class Fred {
public:
friend istream& operator>> (istream& i, Fred& fred);
// ...
private:
int i_; // Just for illustration
};
istream& operator>> (istream& i, Fred& fred)
{
return i >> fred.i_;
}
main()
{
Fred f;
cout << "Enter a Fred object: ";
cin >> f;
// ...
}
| Note que operator >> retorna o stream. É por isso que operações de input podem ser usadas em cascata e/ou usadas em loop while ou comando if. |
| [ 15.8 ] Como eu posso prover impressão para toda uma hierarquia de classes? |
| Providencie um friend operator << que chame uma função protected virtual. |
class Base {
public:
friend ostream& operator<< (ostream& o, const Base& b);
// ...
protected:
virtual void print(ostream& o) const;
};
inline ostream& operator<< (ostream& o, const Base& b)
{
b.print(o);
return o;
}
class Derived : public Base {
protected:
virtual void print(ostream& o) const;
};
| O resultado final é que operator << atua como se fosse resolvido
dinamicamente, mesmo tratando-se como uma função friend. Isso é
chamado Virtual Friend Function Idiom. Note que classes derivadas impõem-se sobre print(ostream&) const. Em particular, elas não provêm seus próprio operator <<. Naturalmente se base é uma ABC, Base::print(ostream&) const pode ser declarada virtual pura usando a sintaxe " usando a sintaxe "= 0" |
#include <iostream.h>
#include <fstream.h>
main()
{
#if 1
ifstsream file("../test.dat"); // RIGHT!
#else
ifstsream file("..\test.dat"); // WRONG!
#endif
// ...
}
| Lembre-se: a barra invertida ("\") é usada em
literais para criar caracteres especiais: "\n" é um newline, "\b" é um backspace,
e "\t" é um tab, "\a" é um alert, "\v" é um tab
vertical, etc. Assim o nome de arquivo "\version\next\alpha\beta\test.dat" é interpretado como um grupo de caracteres especiais; use "/version/next/alpha/beta/test.dat" mesmo em sistemas que usam "\" como separador de diretórios, como o DOS, Windows, OS/2, etc. |
|
| | Home | Bookmarks | Universidades | Para Saber mais | Universidades | WEB Directory | Mapa do site | | |