Escrevendo costume i / o

Alguns programadores não são grandes fãs de sobrecarregar os operadores padrão para classes definidas pelo usuário C ++. Isto inclui escrever inserters personalizados e extratores. No entanto, muitos programadores preferem criar seus operadores de entrada / saída próprio costume. Esta introdução leva você através das etapas de criação de uma primeira inserção personalizado (saída) e, em seguida, um extrator de costume (entrada).

Criar a classe

Crie a sua classe sem que diz respeito à entrada ou saída. Incluir obter e conjunto funções para recuperar e definindo valores individuais dentro de um objecto. O exemplo seguinte é um Aluna classe para uso nesta seção. Eis o conteúdo da Student.h arquivo de inclusão:

classe Student {public: Estudante explícita (char const * pszName = ", Longa id = 0, duplo GPA = 0.0) - // get e funções definidas para esta classstring getName () const-vazio setName (string& s) -long getID () const-vazio setId (longa nID) -duplo getGPA () const-vazio setGPA (DGPA duplo) -} -

Este código não inclui a implementação do obter e conjunto métodos. Seus detalhes não deve influenciar a criação da inserção e exaustor.

A hipótese acima é que a conjunto funções executar algum tipo de verificações para detectar a entrada inválido - por exemplo, setGPA () não deve permitir que você defina o ponto de classe média para um valor fora da faixa de 0,0 a 4,0.

Criar uma inserção simples

A inserção deve saída um Aluna objeto, quer para exibição ou para um arquivo. O seguinte protótipo seria adicionado à Student.h arquivo de inclusão:

ostream& operatorlt; lt; (ostream& para fora, Student const& s) -

A inserção é declarado com um tipo de retorno de ostream& e devolve o objecto transmitido ao mesmo. Caso contrário, um comando como o seguinte não iria funcionar:

cout lt; lt; "Meu aluno é " lt; lt; meu aluno lt; lt; endl-

O objecto devolvido a partir de lt; lt; meu aluno é utilizado no lt; lt; endl que se segue.

A implementação desta inserção é simples (normalmente isso iria aparecer no Student.cpp Arquivo):

ostream& operatorlt; lt; (ostream& para fora, Student const& s) {int prev = out.precision (2) -out lt; lt; s.getName () lt; lt; " (" lt; lt; s.getID () lt; lt; ")"lt; lt; "/" lt; lt; s.getGPA () - retornar out-}

Experimentá-lo e fazer ajustes

Então, vamos ver como isso funciona inserção:

// CustomIO - desenvolver um inserter personalizado e extrator # incluem #incluir #incluir #incluir "student.h"usando espaço de nomes std-int principal (int argc, char * pArgs []) {S1 Student ("Davis", 123.456, 3,5) -cout lt; lt; s1 lt; lt; endl-Student s2 ("Eddins", 1, 3) -cout lt; lt; s2 lt; lt; endl-cout lt; lt; "Pressione Enter para continuar ..." lt; lt; endl-cin.ignore (10, `n`) - cin.get () - 0-} retornar

Isto gera o seguinte resultado:

Davis (123456) /3.5Eddins (1) / 3

Se isso é bom, então você está feito. No entanto, para aplicações profissionais, você provavelmente vai querer implementar algumas regras de saída como o seguinte (estes são apenas exemplos):

  • * Uma escola em que IDs de estudante são seis dígitos. Se o número for inferior a um total de seis dígitos, em seguida, o número deve ser preenchido à esquerda com zeros.

    Video: Os Contemporâneos - O Costume pt2

  • * médias de notas são normalmente apresentadas com dois dígitos depois do ponto decimal.

Felizmente, existem controles que implementam esses recursos. No entanto, ser um pouco cuidadoso antes de ajustar a formatação de saída. Por exemplo, suponha que a inserção você queria saída de um parâmetro inteiro é em formato hexadecimal. Os usuários da inserção seria muito surpreso se todas as saídas subsequentes apareceu em hexadecimal em vez de decimal. Portanto, é importante registrar que as configurações anteriores são e restaurá-los antes de retornar de nossa inserção.

Uma versão da inserção gussied aparece da seguinte forma:

ostream& operatorlt; lt; (ostream& para fora, Student const& s) {fora lt; lt; s.getName () lt; lt; " ("- // forçar o id para ser um de seis dígitos fieldchar prevFill = out.fill ( `0`) - out.width (6) Check-out lt; lt; s.getID () - out.fill (prevFill) - // agora a saída do resto do Studentint prevPrec = out.precision (3) -ios_base :: fmtflags prev = out.setf (ios_base :: showpoint) Check-out lt; lt; ")" lt; lt; "/" lt; lt; s.getGPA () - out.precision (prevPrec) -out.setf (ant) -Retornar out-}

Você pode ver que a inserção gera o nome do aluno, assim como antes. No entanto, antes de emitir ID do aluno, ele define a largura do campo para seis caracteres e define o caractere de preenchimento para a esquerda para 0.

A largura do campo aplica-se apenas a muito próxima saída por isso é importante para definir este valor imediatamente antes do campo que deseja impactar. Porque ele tem a duração de apenas um campo, não é necessário para gravar e restaurar a largura do campo.

Uma vez que o campo tem sido de saída, o caractere de preenchimento é restaurado para o que era antes. Da mesma forma a precisão é definido para três dígitos e o ponto decimal é forçado em antes de exibir o ponto de classe média. Isso força a 3 para exibir como 3.00.



A saída resultante aparece como se segue:

Davis (123456) /3.50Eddins (000001) /3.00

o extractor

O trabalho de criar o extrator na verdade começa com a inserção. Observe que ao criar o formato de saída para o meu SLUNO objeto, o programador adicionou alguns marcações especiais que permitiriam que um extrator para se certificar de que o que ele está lendo é realmente um Aluna. Por exemplo, ela incluiu parênteses em torno da carteira de estudante e uma barra entre ele eo GPA.

Meu extractor pode ler estes campos para se certificar de que ele vai ficar em sincronia com o fluxo de dados. Na visão geral, o extrator será necessário realizar as seguintes tarefas:

  • * Leia o nome (uma cadeia de caracteres).

  • * Leia um parêntese de abertura.

  • * Leia uma ID (um inteiro).

  • * Leia um parêntese fechado.

  • * Leia uma barra.

  • * Ler o GPA (um número de ponto flutuante).

Ele terá de fazer isso, embora conscientes de se um problema de formatação ocorre o tempo todo. O que se segue é a minha versão do exaustor Student:

istream& operatorgt; gt; (istream& em, Estudante& s) {// lê valores (ignorar espaço em branco extra) cadeia de nome longo nID-double DGPA-char openParen = 0, closedParen = 0, slash = 0-ios_base :: fmtflags prev = in.setf (ios_base :: skipws) -dentro gt; gt; namegt; gt; openParen gt; gt; nID gt; gt; closedParengt; gt; golpear gt; gt; DGPA-in.setf (ant) - // se os marcadores não combinam ... se (openParen = `(` || closedParen = `)` || cortar = `/`!) {//. ..then este não é um Studentin.setstate legal (ios_base :: failbit) -Retornar in -} // tentar definir o valuestry aluno {s.setName (nome) -s.setID (nID) -s.setGPA ( DGPA) -} catch (...) {// algo não está certo - bandeira do failurein.setstate (ios_base :: failbit) -throw-} retornar in-}

Este dispositivo de inserção é iniciado pela leitura de cada um dos campos esperados como anteriormente descrito no diagrama de fluxo. Se qualquer um dos caracteres do marcador está faltando (o parêntese aberto, fechado parêntese, e barra), então este não é um legal Aluna objeto. A maneira aprovado para indicar tal falha é definir o failbit no objecto de entrada. Isto irá parar todas as outras entrada até que a falha seja apagada.

O próximo passo é realmente tentar armazenar esses valores na Aluna. Por exemplo, todos os marcadores pode ter estado presente, mas o valor lido para o ponto de classe média pode ter sido 8,0, um valor que está claramente fora da nossa gama de predefinido de 0 a 4.0. Assumindo que o Aluna objecto inclui controlos para valores fora-de-gama nos seus métodos de jogo, a chamada para setGPA () irá lançar uma exceção que é pego no extractor. Mais uma vez, o extrator define o failbit. Se o extractor relança a exceção é até o programador.

É muito melhor que contar com a setGPA () método para detectar o problema gama de implementar essa verificação no próprio extractor. Melhor deixar o Aluna objeto proteger seu próprio estado de contar com funções externas.

Use esses novos métodos

O seguinte (muito) simples CustomIO programa mostra como esses métodos inserter e extrator são usados. Este exemplo juntamente com o costume Aluna inserção e exaustor estão disponíveis em faqcartx.info:

int principal (int argc, char * pArgs []) {S1 Student ("Davis", 123.456, 3,5) -cout lt; lt; s1 lt; lt; endl-Student s2 ("Eddins", 1, 3) -cout lt; lt; s2 lt; lt; endl-cout lt; lt; "Entrada de um objeto de estudante:"CIN II-III gt; gt; S1-se (cin.fail ()) {cout lt; lt; "estudante de leitura de erro " lt; lt; endl-cin.clear () -} else {cout lt; lt; "Ler: " lt; lt; s1 lt; lt; endl-} cout lt; lt; "Pressione Enter para continuar ..." lt; lt; endl-cin.ignore (10, `n`) - cin.get () - 0-} retornar

A saída deste programa (quando fornecido um estudante legal como entrada aparece da seguinte forma:

Video: Emoji Costume Ideas w/ Sonya Esman

Davis (123456) /3.50Eddins (000001) /3.00Input um objeto estudante: Laskowski (234567) /3.75Read: Laskowski (234567) /3.75Press Enter para continuar ...

Observe que o estudante Davis mostra apenas o queria: a carteira de estudante é rodeado por parênteses e o ponto de classe média aparece com dois dígitos depois do ponto decimal. Este último é verdadeiro mesmo para o aluno Eddins um pouco problemático.

O estudante Laskowski é aceito como entrada porque tem todas as marcas próprias de um estudante válido: parênteses e barras em todos os lugares certos. Confira o que acontece se deixamos algo fora, no entanto:

Entrada de um objeto de estudante: Laskowski 234567 / 3.75Error estudante leitura

Este pequeno programa mostra dois hábitos muito importantes que você deve desenvolver:

Video: Suit Full Video Song | Guru Randhawa Feat. Arjun | T-Series

  • Verifique a bandeira falhar chamando falhou() após cada entrada.

    Video: Os Contemporâneos - O Costume pt1

  • Limpar o sinalizador falhar assim que você reconheceu o fracasso chamando Claro().

    Todos os pedidos subsequentes de entrada será ignorada até que você limpou a bandeira falhar.


Publicações relacionadas