Tutorial c++

March 25, 2018 | Author: FabricioFeitosa | Category: C (Programming Language), Integer (Computer Science), Data Type, Compiler, Identifier


Comments



Description

Instruções para usoBásico de C + +      Estrutura de um programa Variáveis. Os tipos de dado. Constantes Operadors Basic Input / Output Estruturas de Controle    Estruturas de Controle Funções (I) Funções (II) Composto Tipos de Dados       Matrizes Seqüências de caracteres Ponteiros Memória dinâmica Estruturas de Dados Outros tipos de dados Programação Orientada a Objetos     Classes (I) Classes (II) Amizade e herança Polimorfismo Conceitos Avançados      Modelos Namespaces Exceções Tipo casting directivas Preprocessor Biblioteca C + + Padrão  Entrada / Saída com arquivos Instruções para uso Para quem é direcionado esse tutorial? Este tutorial é para aquelas pessoas que querem aprender a programação em C + + e não necessariamente têm qualquer conhecimento prévio de outras linguagens de programação. É claro que nenhum conhecimento de outras linguagens de programação ou qualquer habilidade geral do computador pode ser útil para compreender melhor este tutorial, embora não seja essencial. Ele também é indicado para aqueles que precisam de uma pequena atualização sobre as novas funcionalidades da linguagem adquiriu a partir da última normas. Se você estiver familiarizado com a linguagem C, você pode tirar as três primeiras partes deste tutorial como uma revisão de conceitos, uma vez que explicar, principalmente a parte C do C + +. Existem pequenas diferenças na sintaxe C + + para algumas funções C, assim que eu ainda recomendo que você lê-los. A parte 4 descreve programação orientada a objetos. A parte quinto maior parte descreve as novas funcionalidades introduzidas pelo ANSI-C + + padrão. Estrutura deste tutorial O tutorial está dividido em seis partes principais, e cada parte é dividida em várias secções que cobrem cada um tópico específico.Você pode acessar diretamente qualquer seção do índice de seção disponíveis na barra do lado esquerdo, ou começar o tutorial a partir de qualquer ponto e seguir os links na parte inferior de cada seção. Muitas seções incluem exemplos que descrevem a utilização do conhecimento adquirido no capítulo. É recomendado que você leia esses exemplos e ser capaz de compreender cada uma das linhas de código que a constituem, antes de passar para o próximo capítulo. Uma boa maneira de adquirir experiência com uma linguagem de programação, modificando e acrescentando novas funcionalidades no seu próprio país para os programas de exemplo que você entendeu. Não tenha medo de modificar os exemplos fornecidos com este tutorial, que é a maneira de aprender! Compatibilidade Notas O ANSI-C + + padrão de aceitação como padrão internacional é relativamente recente. Foi publicado pela primeira vez em Novembro de 1997, e revisto em 2003. No entanto, a linguagem C + + existe desde muito tempo antes (1980). Portanto, há muitos compiladores que não suportam todos os novos recursos incluídos em ANSI-C + +, especialmente aqueles que são liberados antes da publicação da norma. Este tutorial é pensado para ser seguido com compiladores modernos que suportam, pelo menos em algum grau-ANSI-C + + especificações. Encorajo-vos a conseguir um se o seu não está adaptado. Há muitas opções, tanto comerciais como livres. Compiladores Os exemplos incluídos neste tutorial são todos os programas do console . Isso significa que usar o texto para se comunicar com o usuário e para mostrar seus resultados. Todos os compiladores C + + apoio à elaboração de programas de console. Consulte o manual do usuário do seu compilador para obter mais informação sobre como compilá-los. Estrutura de um programa Provavelmente a melhor maneira para começar a aprender uma linguagem de programação é escrever um programa. Portanto, fica aqui o nosso primeiro programa: 1 2 3 4 5 6 7 / / Meu primeiro programa em C + + # include <stidio.h> int main () { printf ("Olá Mundo!"); return 0;} Olá Mundo! 8 9 10 O primeiro painel (em azul) mostra o código fonte para o nosso primeiro programa. O segundo (em cinza claro) mostra o resultado do programa quando compilado e executado. À esquerda, os números em cinza representam os números de linha - estas não fazem parte do programa, e são mostrados aqui apenas para fins informativos. A maneira de editar e compilar um programa depende do compilador você está usando. Dependendo se ele tem uma interface de desenvolvimento ou não e sobre a sua versão. Consulte a secção de compiladores e do manual ou de ajuda que acompanha o seu compilador, se você tem dúvidas sobre como compilar um C + + console programa. O programa anterior é o típico programa que os aprendizes programador escrever pela primeira vez, e seu resultado é a impressão na tela do "Olá Mundo!" frase. É um dos mais simples programas que podem ser escritas em C + +, mas já contém os componentes fundamentais que cada programa C + + tem. Vamos olhar linha por linha o código já escrevemos: / / Meu primeiro programa em C + + Esta é uma linha de comentário. Todas as linhas que começam com duas barras ( / / ) são consideradas comentários e não têm qualquer efeito sobre o comportamento do programa. O programador poderá usá-los para incluir explicações ou observações curtas dentro do próprio código fonte. Neste caso, a linha é uma breve descrição do que é o nosso programa. int main () Esta linha corresponde ao início da definição da função principal. A função principal é o ponto por onde todos os programas C + + iniciar a sua execução, independentemente da sua localização dentro do código fonte. Não importa se existem outras funções com outros nomes definidos antes ou depois dela as instruções contidas dentro da função esta definição será sempre os primeiros a ser executado em qualquer programa C + +. Pelo mesmo motivo, é essencial que todos os programas C + + tem um principal função. A palavra principal é seguido do código por um par de parênteses ( () ). Isso é porque é uma declaração de função: Em C + +, o que diferencia uma declaração de função de outros tipos de expressões são esses parênteses que seguem o seu nome. Opcionalmente, estes parênteses podem incluir uma lista de parâmetros dentro deles. Logo após estes parênteses, podemos encontrar o corpo da função principal entre chaves ( {} ). O que está contido dentro destas chaves é que a função faz quando ele é executado. printf ("Olá Mundo!"); Esta linha é um C + + declaração. A declaração é uma expressão simples ou composto que pode realmente produzir algum efeito. Na verdade, esta afirmação só executa a ação que gera um efeito visível no nosso primeiro programa. Tribunal de Justiça é o nome do fluxo de saída padrão em C + +, eo significado de toda a declaração é para inserir uma seqüência de caracteres (neste caso, oOlá Mundoseqüência de caracteres) para o fluxo de saída padrão ( Tribunal de Justiça , que normalmente corresponde à tela). Tribunal de Justiça é declarada no iostream de arquivo padrão dentro do std namespace, é por isso que nós precisamos incluir esse arquivo específico e declarar que iríamos usar este espaço para nome específico no início do nosso código. Observe que a instrução termina com um caractere ponto e vírgula ( ; ). Este caráter é usado para marcar o final da instrução e, na verdade ele deve ser incluído ao final de todas as declarações de expressão em todos os programas C + + (um dos erros de sintaxe mais comum é o fato de esquecer de incluir alguns vírgula depois de uma instrução). return 0; mas em C + +. Podemos escrever muitas declarações por linha ou escrever uma única instrução que leva muitas linhas de código. só serve para tornar mais legíveis e esquema para os seres humanos que podem lê-lo. 4 return 0. Você deve ter notado que nem todas as linhas deste programa executar ações quando o código é executado. portanto a separação em diferentes linhas de código não importa a todos para essa finalidade. return 0. Por exemplo. Havia linhas contendo apenas comentários (aquelas iniciadas por / / ). Esta é a forma mais usual para acabar com a C + + console programa. retorno pode ser seguido por um código de retorno (no nosso exemplo é seguido pelo código de retorno com um valor de zero). Vamos adicionar uma instrução adicional para o nosso primeiro programa: 1 2 3 4 5 6 7 8 9 10 11 12 / / Meu segundo programa em C + + # include <stdio. Em C + +. A divisão do código em linhas diferentes. desde principal poderia ter sido perfeitamente válido definido desta maneira: .A instrução return faz com que a função principal para terminar.h> int main () { printf ("Olá Mundo!"). não temos regras rígidas sobre como separar instruções em linhas diferentes. Um código de retorno 0 para a principal função é geralmente interpretado como o programa funcionou como o esperado.} Tudo em apenas uma linha e isso teria exatamente o mesmo significado que o código anterior. sem quaisquer erros durante sua execução. Mais uma vez. que foram incluídas dentro do bloco delimitado por chaves ( {} ) do a função principal. a função principal) e.} 5 Poderíamos ter escrito: int main () { printf ("Olá Mundo!"). O programa foi estruturado em duas linhas diferentes. return 0. printf ("Sou um programa C + +"). Havia linhas com as directivas para o compilador do pré-processador (aquelas iniciadas por # ). a fim de ser mais legível. } Olá Mundo! Sou um programa C + + Neste caso. Então havia as linhas que começou a declaração de uma função (neste caso. foi realizada em duas inserções de corte em duas declarações diferentes. em vez de 1 int main () { 2 3 printf ("Olá Mundo!"). ) no final de cada um. finalmente. a separação em diferentes linhas de código foi feito apenas para dar maior legibilidade ao programa. a separação entre as afirmações é especificado com um ponto e vírgula final ( . as linhas com as declarações (como a inserção no tribunal ). O seu objectivo é apenas permitir que o programador para inserir notas ou descrições dentro do código fonte. O segundo. Comentários Os comentários são partes do código-fonte desconsiderados pelo compilador. } Fomos também a liberdade de dividir o código em linhas mais se considerou mais conveniente: 1 2 3 4 5 6 7 8 int main () { printf("Olá Mundo!"). o compilador irá tomá-los como se fossem C + + expressões. / * e * / . as devoluções de tudo. com a possibilidade de incluir mais de uma linha.h> int main printf printf C + + return } () { ("Olá Mundo!"). printf ("Sou um programa C + +"). return 0. uma vez que não são declarações. printf ("Sou um programa C + +"). São linhas lido e processado pelo pré-processador e não produzem qualquer código por si só. descarta tudo entre os / * personagens ea primeira aparição do * / personagens. } E o resultado teria sido de novo exatamente como nos exemplos anteriores. conhecido como bloco de comentário. desde onde o par de barras ( / / ) encontra-se até ao final da mesma linha. / / imprime Sou um programa 0. Olá Mundo! Sou um programa C + + Se você incluir comentários dentro do código fonte dos seus programas sem usar o comentário combinações de caracteres / / . mais provável a causar uma ou várias mensagens de erro quando você compilar . . Estamos indo para adicionar comentários ao nosso segundo programa: 1 2 3 4 5 6 7 8 9 10 11 12 / * Meu segundo programa em C + + com mais comentários * / # include <stdio. ). Eles simplesmente não fazer nada.int main () { printf ("Olá Mundo!"). C + + suporta duas maneiras para inserir comentários: 1 / / Linha de comentário 2 / * comentário de bloco / O primeiro deles. / / impressões Olá Mundo! / ("Eu sou um C + + programa ") . directivas Preprocessor (aquelas que começam por # ) estão fora dessa regra geral. conhecido como linha de comentário. return 0. directivas Preprocessor devem ser especificados em sua própria linha e não tem que terminar com um ponto e vírgula ( . ou a longo versões para abs e div .h) climits (limits. Nos exemplos apresentados nesta referência. o tradicional cabeçalho nomes name. As funções atexit .h) clocale (locale.h) csignal (signal. como descrito pela norma ISO 1990 e sua emenda n º 1 (ISO / IEC 9899:1990 e ISO / IEC 9899:1990 / DAM 1).h) cctype (ctype. memchr . portanto. Nota sobre as versões C + + inclui a biblioteca C. não aparece como um tipo definido nos arquivos de cabeçalho correspondentes onde ele aparece em C. O mesmo se aplica a várias macros introduzida pela alteração de 1 a ISO C no cabeçalho do arquivo <iso646.strrchr . versões sobrecarregadas de algumas funções são fornecidas com outros tipos de parâmetros ea mesma semântica. com as seguintes diferenças: y y Cada arquivo de cabeçalho tem o mesmo nome que a versão da linguagem C. Cabeçalhos cassert (assert.h) cerrno (errno. Algumas introduções feitas na norma ISO 1999 não são compatíveis com o padrão C + +.h) ciso646 (iso646. strpbrk .h> . saída e abortar . No entanto.h) csetjmp (setjmp. definido no < cstdlib > Tem adições ao seu comportamento em C + +. para compatibilidade com C. que são palavras-chave em C + +.h> é <cstdlib> . o C + + equivalente para a linguagem de cabeçalho do arquivo C <stdlib. mas com um " c "prefixo e sem extensão. esta versão é usada para que os exemplos são totalmente compatíveis com C.Biblioteca C Biblioteca C Língua A biblioteca C + + inclui as mesmas definições como a biblioteca em linguagem C organizados na mesma estrutura de arquivos de cabeçalho.h ) também está disponível com as mesmas definições dentro do namespace global. strstr . As funções seguintes alterações nas suas declarações relacionadas ao constness de seus parâmetros: strchr .h) cfloat (float. comofloat e long double versões das funções no CMATH arquivo de cabeçalho.h) Biblioteca C Diagnostics (cabeçalho) Personagem funções de manipulação (cabeçalho) C erros (cabeçalho) Características dos tipos de ponto flutuante (cabeçalho) ISO 646 grafias alternativas operador (cabeçalho) Tamanhos dos tipos integrais (cabeçalho) C biblioteca de localização (cabeçalho) Biblioteca C numéricos (cabeçalho) local não pula (cabeçalho) biblioteca C para lidar com sinais (cabeçalho) . Cada elemento da biblioteca é definido dentro do std namespace. embora seu uso seja substituído em C + +. Por exemplo.h (como stdlib. Existem também algumas alterações pontuais no C + + aplicação: y y y y wchar_t é um tipo fundamental em C + + e.h) CMATH (math. opcionalmente conter incorporado marcas de formatação que são substituídos pelos valores especificados no argumento subseqüente (s) e formatado conforme solicitado.65 E f g G A notação científica (mantise / expoente) usando E personagem Decimais de ponto flutuante Use o menor de % e ou % f Use o menor de E% ou % f .). conforme especificado no formato . printf função <cstdio> printf int (const char * format. Precisão] [duração] especificador Onde especificador é o mais importante e define o tipo ea interpretação do valor do argumento corespondente: especificador Saída Caracteres Inteiro decimal A notação científica (mantise / expoente) usando e caráter Exemplo c d ou i e um 392 3. As marcas de formatação de seguir este protótipo: % [Flags] [width] [.h) cstddef (stddef.65 392. . Parâmetros formato String que contém o texto a ser escrito para stdout . Após o formato de parâmetro.h) cstdio (stdio. Imprimir dados formatados para stdout Escreve para a saída padrão (stdout) uma seqüência de dados formatados como o formato argumento especifica.h) cstring (string.h) ctime tratamento de argumentos variável (cabeçalho) Standard definições C (cabeçalho) biblioteca C para executar / Output operações de entrada (cabeçalho) Standard C Library General Utilitários (cabeçalho) C Strings (cabeçalho) C Time Library (cabeçalho) Alteração 1 para ISO-C 90 adicionada dois conectores adicionais: cwchar e cwctype . a função espera que pelo menos tantos argumentos adicionais. Ele pode..h) cstdlib (stdlib. O número de argumentos a seguir o formato de parâmetros deve ser pelo menos tanto quanto o número de marcas de formatação.9265E 2 392..cstdarg (stdarg.65 392.9265e 2 3. o s u x X p Unsigned octal Cadeia de caracteres Inteiro sem sinal decimal Inteiro sem sinal hexadecimal Inteiro sem sinal hexadecimal (maiúsculas) endereço do ponteiro Nada impresso. O argumento deve ser um ponteiro para um assinado int , onde o número de caracteres escritos até então é armazenada. Uma %, seguido por outro % personagem vai escrever % para stdout . 610 amostra 7235 7fa 7fa B800: 0000 n % % A marca também podem conter sinalizadores , largura , precisão. e modificadores de subespecificadores, que são opcionais e seguir as seguintes especificações: bandeiras descrição Deixou de justificar dentro da largura do campo determinado; direito justificação é o padrão (ver largura sub-especificador). Forças de preceder o resultado com um ou menos sinal de adição ( + ou - ), mesmo para números positivos. Por padrão, somente os números negativos são precedidos por um sinal. (Espaço) Se nenhum sinal de que vai ser escrito, um espaço em branco é inserida antes do valor. Usado com o , x ou X especificadores o valor é precedido de 0 , 0x ou 0X , respectivamente, para valores diferentes de zero. Usado com e , E e f , que força a saída escrita para conter um ponto decimal, mesmo se - + # nenhum dígito se seguiria. Por padrão, se nenhum dígito seguir, sem ponto decimal é escrita. Usado com g ou G , o resultado é o mesmo que com e ou E , mas os zeros à direita não são removidos. 0 Left-pad o número com zeros ( 0 ) em vez de espaços, onde o preenchimento é especificado (ver largura sub-especificador). largura descrição Número mínimo de caracteres a serem impressos. Se o valor a ser impresso for menor que (Número) este número, o resultado será preenchido com espaços em branco. O valor não é truncado, mesmo se o resultado for maior. * A largura não é especificado no formato de string, mas como um valor inteiro argumento adicional que precede o argumento de que tem que ser formatada. . Precisão descrição Para especificadores inteiro ( d , i , o , u , x , X ): precisão especifica o número mínimo de dígitos para ser escrito. Se o valor a ser escrito é inferior a este número, o resultado será preenchido com zeros à esquerda. O valor não é truncado, mesmo se o resultado for . número maior. A precisão de 0 significa que nenhum personagem foi escrito para o valor 0 . Por e , E e f especificadores: este é o número de dígitos a ser impresso após o ponto decimal. Para g e G especificadores: Este é o número máximo de dígitos significativos a serem impressas. Para s : este é o número máximo de caracteres a ser impresso. Por padrão, todos os caracteres são impressos até o caractere nulo final é encontrado. Para c tipo: ele não tem efeito. Quando nenhuma precisão for especificada, o padrão é 1 . Se o prazo for especificado sem um valor explícito para a precisão , 0 é assumido. .* A precisão não é especificada no formato de string, mas como um valor inteiro argumento adicional que precede o argumento de que tem que ser formatada. comprimento descrição O argumento é interpretado como um short int ou short int unsigned (só se aplica aos especificadores inteiro: i , d , o , u , x e X ). O argumento é interpretado como um long int ou long int unsigned para especificadores de inteiros ( i , d , o , u , x e X ), e como um caractere de largura ou seqüência de caracteres de largura para especificadores c e s . h l L O argumento é interpretado como uma dupla muito tempo (só se aplica aos especificadores de ponto flutuante: E , E , f , g e G ). argumentos adicionais Dependendo do formato string, a função pode esperar uma seqüência de argumentos adicionais, cada uma contendo um valor a ser inserido em vez de cada % de tag-especificado no formato de parâmetro, se houver. Deve haver o mesmo número de esses argumentos como o número de % -tags que esperam um valor. Valor de retorno Em caso de sucesso, o número total de caracteres escritos é retornado. Em caso de falha, um número negativo é retornado. Exemplo 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 / * Exemplo * / printf # include int main () { printf ( "Personagens:% c% c \ n" , 'a' , 65); printf ( "decimais:% d% d \ n" , 1977, 650000L); printf ( "anterior, com espaços em branco:% 10d \ n" , 1977); printf ( "anterior, com zeros: 010D% \ n" , 1977); printf ( "Alguns radixes diferentes:% d% x% % o # #% x \ n O " , 100, 100, 100, 100, 100); printf ( "flutua: + 0,0% 4.2f \ e E% n%" , 3,1416, 3,1416, 3,1416); printf ( " Largura truque: *% d \ n " , 5, 10); printf ( "% \ n s" , "Uma seqüência de caracteres" ); return 0;} scanf função <cstdio> int scanf (const char * format, ...); Leia os dados formatados da entrada padrão Lê dados de stdin e armazena-os de acordo com o parâmetro de formato para os locais apontados pelos argumentos adicionais. Os argumentos adicionais devem apontar para objetos alocados já do tipo especificado pela tag de formato correspondente no formato de string. Parâmetros formato C string que contém um ou mais dos seguintes itens: y y y caractere espaço em branco: a função vai ler e ignorar todos os caracteres em branco (o que inclui espaços em branco e da nova linha e caracteres de tabulação), que são encontrados antes do não-branco próximo caractere. Isto inclui qualquer quantidade de caracteres em branco, ou nenhuma. Caracteres não-branco, exceto sinais de porcentagem (%): Qualquer personagem que não é um caractere em branco (newline, espaço em branco ou tabulação) ou parte de um especificador de formato (que começam com um % do personagem) faz a função de ler o próximo caractere a partir de stdin , compará-lo com este espaço em branco sem carácter e se coincidir, ele é descartado ea função continua com o próximo caracter do formato . Se o personagem não corresponder, a função falhar, retornando e deixando os caracteres subseqüentes de stdin não lidas. Os especificadores de formato: uma seqüência formada por um sinal de porcentagem inicial ( % ) indica um especificador de formato, que é usado para especificar o tipo e formato dos dados a serem recuperados a partir de stdin e armazenados nos locais apontados pelos argumentos adicionais. Um especificador de formato segue este protótipo: largura %[*][] [modificadores tipo] onde: Uma partida asterisco opcional indica que os dados estão a ser recuperados a partir de stdin , mas ignorado, ou seja, não é armazenada no argumento correspondente. largura Especifica o número máximo de caracteres a ser lido na operação de leitura atual Especifica um tamanho diferente de int (no caso de d , i e n ), unsigned int (no caso de o , u e x ) ou float (no caso de e , f e g ) para os dados apontados pela argumento adicional correspondente: modificadores h: short int (para d , i e n ), ou short int unsigned (para o , u e x ) l: long int (para d , i e n ), ou unsigned long int (para o , u e x ), ou dupla (para e , f e g ) L: long double (por e , f e g ) Um personagem especificando o tipo de dados a serem lidos e como é esperado para ser lido. Veja a tabela seguinte. * tipo y Tipo de especificadores scanf: tipo Qualificação de Entrada Tipo de argumento cada um apontando para um objeto do tipo especificado por suas respectivas % de tag-no formato de cadeia. Para cada especificador de formato no formato de string que recupera dados. \" . opcionalmente.c caráter único: Lê o próximo caractere. 10 11 printf ( "% s Sr. str. 8 printf ( "Digite sua idade:" ). i).f.% d anos n \".X argumentos adicionais unsigned int * int * A função espera uma seqüência de referências como argumentos adicionais. scanf ("% d". a função retorna o número de itens lidos com êxito. na mesma ordem. . & i). Valor de retorno Em caso de sucesso. & i). Se uma largura diferente de 1 for especificado. 5 int i. Isto irá ler os caracteres subseqüentes até um espaço em branco é encontrado (caracteres Char * em branco são considerados de nova linha. Dois exemplos de entradas válidas são -732. 6 printf ( "Digite seu nome de família:" ). int * s Seqüência de caracteres .. EOF é retornado. i. printf ( "Digite um número hexadecimal:" ) . opcionalmente precedido de um + ou .103 e 7. 9 scanf ( "% d" . 7 scanf ( "% s" .assinar e. u x. Inteiro sem sinal decimal. ou seja. i). se uma falha de correspondência acontece. No caso de uma falha de entrada antes de qualquer dado pode ser lido com sucesso. como em: int n. 12 scanf ( "% x" . um argumento adicional deve ser especificado. Nenhum caractere nulo é acrescentado no final. pela folowed e ou E caractere e um número decimal. str). Esta contagem pode igualar o número esperado de leituras ou menos. Hexadecimal inteiro.G float * o Octal inteiro . Decimal inteiro: Número opcionalmente precedido de um + ou sinal. printf ( "Você digitou x% # (% d) n. Estes argumentos são esperados ser referências (ponteiros): se você deseja armazenar o resultado de um fscanf operação em uma variável regular você deve preceder o seu identificador com o operador de referência .g.12e4 d int * e. a função lê largura caracteres e armazena-os Char * nos locais sucessivos do array passado como argumento.} 15 16 17 . Exemplo 1 / * Exemplo scanf / 2 # include 3 4 int main () { char str [80]. em branco e tabulação).E. 13 14 return 0. & n). um sinal de E comercial ( & ). até zero. ponto flutuante: número decimal contendo um ponto decimal. público. estático. novo operador privado. static_cast. os identificadores de variável sempre tem que começar com uma letra. enquanto Além disso. dígitos ou caracteres de sublinhado ( _ ). pode começar com um dígito. No entanto. Cada variável precisa de um identificador que o distingue dos demais. nem os seus compilador. volátil. Você tem apenas dois valores diferentes armazenados em sua memória. registre-se. char. sizeof. inline. protegido reinterpret_cast. bool. O mesmo processo pode ser expresso em C + + com a seguinte instrução: 1 a = 5. isso. se. a exportação. Tipos de Dados.18 19 Variáveis. Vamos pensar que eu peço que você mantenha o número 5 em sua memória mental. união. int. Tínhamos que escrever várias linhas de código. Agora. tente. podemos definir uma variável como uma parte da memória para armazenar um valor determinado. mas em alguns casos. Para ir um pouco mais adiante e tornar-se capaz de escrever programas que executam tarefas úteis que realmente nos salvar de trabalho é necessário introduzir o conceito de variável . você deve manter os 6 números (que é 5 +1) e 2 em sua memória. ao mesmo tempo sofisticado e realizar operações matemáticas com elas. a = a + 1. Eles também podem começar com um caractere sublinhado ( _ ). compilá-los. este é um exemplo muito simples. contendo dois sucessivos caracteres de sublinhado em qualquer lugar. virtual. ruptura. jogar. auto. de retorno. números e caracteres de sublinhado simples são válidas. assinado. falso. float. explícita. long. typedef verdade. Além disso. e depois executar o programa resultante apenas para obter uma simples frase escrita na tela como resultado. Certamente teria sido muito mais rápido digitar a frase de saída por nós mesmos. a captura. não assinado. As palavras-chave reservadas padrão são: asm. O processo todo que você tem feito apenas com sua memória mental é um símile do que um computador pode fazer com duas variáveis. A utilidade do "Olá Mundo" programas mostrados na seção anterior é bastante questionável. Identificadores Um identificador válido é uma seqüência de uma ou mais letras. pois. caso. Valores que nós poderíamos agora. por exemplo. Por exemplo. extern.b. a curto. padrão. Portanto. e então eu pedir para você memorizar também o número dois ao mesmo tempo. já que usamos somente dois valores inteiros pequenos. const. struct switch. Nem espaços nem sinais de pontuação ou símbolos podem ser parte de um identificador. que são palavras-chave reservadas . resultado = a . enquanto eles estavam identificadores válidos. se eu pedir para você adicionar 1 para o primeiro número que eu disse. const_cast. Outra regra que você tem que considerar ao inventar a sua própria identificadores é que eles não podem corresponder a qualquer palavra-chave da linguagem C + + é específico. 2 3 4 Obviamente. nula wchar_t. goto. a programação não se limita apenas à impressão simples textos na tela. mas considere que o computador pode armazenar milhões de números como estes. classe. mas poderíamos ter chamado todos os nomes das variáveis que queríamos inventar. typeid. amigo. Em nenhum caso. subtrair e obter 4 como resultado. Somente letras. representações alternativas para alguns operadores não podem ser usadas como identificadores. uma vez que são palavras reservadas em algumas circunstâncias: . enum. modelo. b = 2. b e resultado . continue. estes podem ser reservados para determinadas palavras-chave compilador ou identificadores externos. bem como identificadores. typename. espaço. excluir. outra coisa. usando. fazer dupla. dynamic_cast. mutável. no código anterior a identificadores de variáveis foram um . Assim. BitAnd. 8bytes 2 ou 4 bytes wchar_t Wide personagem. compl. xor_eq Seu compilador pode também incluir algumas palavras-chave específicas adicionais reservados.4 E + / . * Os valores das colunas de tamanho e escala dependem do sistema o programa é compilado. and_eq. por exemplo. A memória em nossos computadores são organizados em bytes.308 (~ 15 dígitos) Um caractere de largura long double Long precisão dupla de ponto flutuante.1. pois não vai ocupar a mesma quantidade de memória para armazenar um número simples de armazenar uma única letra ou um número grande. e eles não vão ser interpretadas da mesma maneira. Estes são três identificadores de variáveis diferentes. xor not_eq ou. int e longo cada um deve ser pelo menos tão grande quanto o anterior que. não.767 assinado: 0-65. 2 bytes int Integer. bem como o intervalo de valores que podem ser representados com cada um: Nome Descrição * Tamanho 1byte Gama * assinado: -128 a 127 assinado: 0 a 255 assinado: -32. Um byte é a quantidade mínima de memória que pode gerenciar em C + +. Além disso. O mesmo se aplica aos tipos de ponto . Os valores apresentados acima são os encontrados na maioria dos sistemas de 32 bits. nós armazenamos as variáveis na memória do nosso computador. BitOr.3.1. Número de ponto flutuante. Curto inteiro. Um byte pode armazenar uma quantidade relativamente pequena de dados: um único caractere ou um inteiro pequeno (geralmente um número inteiro entre 0 e 255). Duplo precisão de ponto flutuante. a especificação geral é que int tem o tamanho natural sugerido pela arquitetura do sistema (uma "palavra" ) e os quatro tipos inteiros char . or_eq. o RESULTADO variável não é o mesmo que o resultado da variável ou o resultado da variável. short . Em seguida você tem um resumo dos tipos de dados básicos fundamentais em C + +.308 (~ 15 dígitos) + / . Isso significa que um identificador escrito em letras maiúsculas não é equivalente a outro com o mesmo nome mas escrito em letras pequenas. 4bytes 8bytes verdadeiro ou falso + / . Mas para outros sistemas. com char sendo sempre um byte de tamanho.535 assinado: -2147483648 a 2147483647 sem sinal: 0-4294967295 assinado: -2147483648 a 2147483647 sem sinal: 0-4294967295 char int short ( curto ) Caráter ou pequeno inteiro. mas o computador tem que saber que tipo de dados que deseja armazenar nelas.7e + / . como números de longo ou de números não-inteiros.38 (~ 7 dígitos) + / .e. Muito importante: A linguagem C + + é um "case sensitive" idioma. 4bytes bool flutuar dupla Boolean valor.7e + / . Fundamentais tipos de dados Durante a programação. 4bytes long int ( tempo ) Long inteiro. Pode levar um dos dois valores: 1byte verdadeiro ou falso. o computador pode manipular tipos de dados mais complexos que vêm do agrupamento de vários bytes.768-32. O segundo declara uma variável do tipo float com o identificador varVezes . longo e int pode ser assinado ou não assinado. todas elas do tipo int . dobro e long double . enquanto que os tipos sem sinal só pode representar valores positivos (e zero). b e c ).) seguido por um identificador de variável válido. separando seus identificadores com vírgulas. Neste caso. A sintaxe para declarar uma nova variável é escrever o especificador do tipo de dados desejado (como bool. se você pretende armazenar valores numéricos em char de tamanho variável. Este declara três variáveis ( um . onde cada um deve fornecer pelo menos tanta precisão como o anterior. dependendo da faixa de números necessários para ser representado. o pensamento para armazenar caracteres. Estas são duas declarações válidas de variáveis. O primeiro declara uma variável do tipo int com o identificador de um . 3 int c. int. c. Os tipos de dados inteiros char .. Assinado tipos podem representar tanto valores positivos e negativos. float . Uma vez declarado. Por exemplo: 1 int a. b. curto e longo pode ser usado sozinho como especificadores de tipo. curto . e tem exatamente o mesmo significado como: 1 int um. Declaração de variáveis A fim de usar uma variável em C + +. Por exemplo: int a. 2 float varVezes.flutuante float . Isso pode ser especificado usando o especificador assinado ou o especificador não assinados antes do nome do tipo. que existe por si só e é considerado um outro tipo de dados fundamental da signed char e unsigned char . as variáveis de um e varVezes pode ser usado no resto do seu âmbito de aplicação do programa. Por exemplo: 1 unsigned 2 assinado short int NumberOfSisters. poderíamos ter escrito: int MyAccountBalance. int MyAccountBalance. devemos primeiro declará-la especificando que tipo de dados que nós queremos que ela seja. Os dois seguintes declarações de variáveis são equivalentes: .. em vez de a segunda declaração acima. Se você estiver indo para declarar mais de uma variável do mesmo tipo. se não especificar assinado ou não assinado compilador irá assumir a maioria das configurações do tipo a ser assinado. eles se referem a seus direitos fundamentais inteiro respectivos tipos: de curto é equivalente a int curto e longo é equivalente a long int . por isso. Você deve usar uma assinatura ou sem assinatura . com exatamente o mesmo significado (com ou sem a palavra-chave assinado ) Uma exceção a essa regra geral é o char tipo. 2 int b. Por padrão. você pode declarar todos eles em uma única instrução. quando declarou que um .1 curto Ano. sobre sua memória mental proposto no início desta seção: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 / Exploração / com variáveis # include <stdio. Âmbito das variáveis Todas as variáveis que pretendemos usar em um programa deve ter sido declarada com o especificador de tipo em um ponto anterior no código. assinado e sem assinatura também pode ser usado como especificadores de tipo autônomo. o que significa o mesmo que int assinado e unsigned int respectivamente. b . fora de todas as funções. / / Exibe o resultado: Printf (resultado). / encerrar o programa: return 0. 2 curto int ano. . resultado = a .h> int main () { / / declaração de variáveis: int a. enquanto uma variável local é declarada dentro do corpo de uma função ou um bloco. Os dois seguintes declarações são equivalentes: 1 unsigned NextYear. vamos ver o C + + código do exemplo. eo resultado foram do tipo int . b = 2. Você vai ver o resto em detalhes nas próximas seções. / / processo: a = 5.b. Uma variável global é uma variável declarada no corpo principal do código-fonte. b. 2 unsigned int NextYear. } 4 Não se preocupe se algo mais do que as declarações de variáveis se parece um pouco estranho para você. Para ver o que as declarações de variáveis parecer em ação dentro de um programa. Uma variável pode ser tanto de âmbito global ou local. Finalmente. como fizemos no código anterior ao início do corpo da função principal. int resultado. a = a + 1. Para fazer isso. conhecido como construtor de inicialização . O escopo das variáveis locais é limitado ao bloco entre chaves ( {} ). isto significa que. Por exemplo: int um (0). seu valor é.As variáveis globais podem ser consultados de qualquer lugar do código. 1 / / Inicialização de variáveis 2 3 # include <stdio. sempre que após a sua declaração. é feito colocando o valor inicial entre parênteses ( () ): tipo de identificador (initial_value). inicial / / valor = 2 6 . Ambas as maneiras de inicializar as variáveis são válidas e equivalentes em C + +. se existia uma outra função além da principal . Por exemplo. mesmo dentro de funções. as variáveis locais declaradas no principal não poderia ser acessado a partir da função de outro e vice-versa. é feito acrescentando um sinal de igual seguido do valor para o qual a variável será inicializada: identificador de tipo = initial_value. A outra maneira de inicializar variáveis. Mas você pode querer uma variável para armazenar um valor concreto no mesmo momento em que é declarada. Há duas maneiras de fazer isso em C + +: O primeiro. Por exemplo.h> 4 int main () { 5 int a = 5. podemos escrever: int a = 0. seu alcance é entre a sua declaração e ponto final dessa função. No exemplo acima. onde eles são declarados. você pode inicializar a variável. se quisermos declarar uma int variável chamada uma inicializado com um valor de 0 no momento em que for declarado. conhecido como c-como inicialização . por padrão indeterminado. inicial / / valor = 5 6 int b (2). Inicialização de variáveis Ao declarar uma variável local normal. se eles são declarados no início do corpo de uma função (como na função principal ). mas ele se comporta de forma semelhante como tipos fundamentais fizesse no seu uso mais básico. cout <<resultado.h> # include # include <string> int main () { string mystring. gosta de ser declarada sem um valor inicial e que está sendo atribuído valores durante a execução: 1 2 3 4 5 6 7 8 9 10 / / Primeiro string meu <stdio. Este não é um tipo fundamental. mystring string ( "Esta é uma string" ). printf (mystring). cordas pode ser inicializado com qualquer cadeia de caracteres válida literal como variáveis do tipo numérica pode ser inicializado com qualquer literal numérico válido. resultado = a .7 int resultado. mystring = "Este é o conteúdo da string inicial" . A biblioteca C + + idioma oferece suporte para cordas através do padrão string classe.h> # include # include <string> int main () { mystring string = "Esta é uma string" .b. printf (mystring). printf (mystring). 2 Strings também podem executar todas as outras operações básicas que tipos de dados fundamentais pode. . 11 } 12 13 14 15 16 17 Introdução às cadeias Variáveis que podem armazenar valores numéricos que não são mais do que um único personagem são conhecidos como cordas. } Esta é Como você pode ver no exemplo anterior. 9 10 return 0. Ambos os formatos são válidos de inicialização com cordas: 1 mystring string = "Esta é uma string" . return 0. a fim de declarar e utilizar objetos (variáveis) desse tipo é preciso incluir um arquivo de cabeçalho adicionais em nosso código fonte: <string> e ter acesso ao std namespace (que já tínhamos em todos os nossos programas anteriores graças à using namespace declaração). inicial / / valor indeterminado 8 a = a + 3. 1 2 3 4 5 6 7 8 9 10 11 / / Primeiro string meu <stdio. Uma primeira diferença com tipos de dados fundamental é que. mystring = "Este é uma seqüência de conteúdos diferentes " . estaremos nos referindo ao valor de 1776. por exemplo. são considerados como um tipo de dados específico. seqüências e valores booleanos . como as variáveis. respectivamente. caracteres . Literais Literais são os tipos mais óbvios de constantes. Por exemplo. neste pedaço de código era uma constante literal . numeral numeral octal e hexadecimal. Nós já usamos esses anteriormente para dar valores concretos para as variáveis ou para expressar as mensagens que queríamos nossos programas para imprimir. Não há dúvida de que é uma constante sempre que escrever1776 em um programa. como constantes literais.11 return 0. constantes literais. Constantes literais podem ser divididos em Integer Algarismos . x ). No entanto. Por padrão. o literal seguintes constantes são todas equivalentes entre si: 1 75 2 0113 3 0x4b / / decimal / / octal / hexadecimal / Todos estes representam o mesmo número: 75 (setenta e cinco). Eles são usados para expressar valores específicos dentro do código fonte do programa. acrescentando l : 1 75 2 75u 3 75L 75ul / / / / / int unsigned int longo unsigned long . quando escreveu: a = 5. 12 13 } 14 15 Constantes Constantes são expressões com um valor fixo. a 5 . Além de números decimais (aqueles que todos nós estamos acostumados a usar todos os dias). Repare que para expressar uma constante numérica não temos que escrever aspas ( " ) nem qualquer caractere especial:. C + + permite o uso de números octais ( base 8 ) e números hexadecimal ( base 16 ). Se queremos expressar um número octal temos de precedê-lo com um 0 (um zero caracteres). de ponto flutuante numerais . expressa como um número de base 10. pode forçar o sistema a ser assinado. literais inteiros são do tipoint . anexando o u personagem para ela. Integer Algarismos 1 1776 707 -273 2 3 Eles são constantes numéricas que identificam decimal valores inteiros. ou a longo prazo. E a fim de expressar um número hexadecimal que temos de precedê-lo com os caracteres 0x ( zero . expresso em C + +. O tipo padrão para literais de ponto flutuante é dupla . onde X é um valor inteiro que segue o e personagem). l ) pode ser escrita utilizando letras maiúsculas ou inferior.02e23 1. se referem a uma variável cujo identificador é x . Observe a diferença entre essas duas expressões: 1 x 2 'x' x só por si.14159L 2 6. Números de ponto flutuante Eles expressam números com decimais e / ou expoentes. a terceira é a carga elétrica de um elétron (um número extremamente pequeno). e os dois seguintes representam os literais cadeia composta por vários personagens.6 x 10 ^ -19 3. o sufixo pode ser especificado usando letras maiúsculas ou minúsculas. Caracteres e strings literais Existem também as constantes não-numéricos. Eles podem incluir um ponto decimal a. é necessário colocar as aspas em torno deles para distingui-los dos identificadores de variáveis possíveis.4 Em ambos os casos. Estes são caracteres . enquanto que 'x' (entre aspas simples) remete para o carácter constante 'x' . Se você quer expressar explicitamente um float ou long double numérico literal. Ao escrever literais tanto caracter e string. ou ambos um ponto decimal e um e caráter: 1 2 3 4 3.02 x 10 ^ 23 1.0 São quatro números válidos com decimais.02e23f / long double / / float Qualquer das letras que podem ser parte de um ponto flutuante numérico constante ( e . ou palavras-chave reservadas. quer sem qualquer diferença em seus significados.0 / / / / 3. expressa em ponto flutuante literal numérico. como os códigos de escape. Observe que para representar um único personagem que colocá-lo entre aspas simples ( ' ) e expressar uma seqüência de caracteres (que geralmente é composto por mais de um personagem) que incluí-la entre aspas ( " ). como: 1 2 3 4 'Z' p ' "Olá mundo" "Como vai você?" As duas primeiras expressões representam constantes único personagem. todos eles de aproximação eo último é o número três.14159 6. f . um e personagem (que expressa "por dez na altura Xth". Caracteres e strings literais tem certas peculiaridades.6e-19 3. respectivamente: 1 3.14159 6. você pode usar o f e l sufixos. O primeiro número é PI. o segundo é o número de Avogadro. No primeiro caso (octal) os dígitos deve seguir imediatamente a barra invertida (por exemplo \ 23 ou \ 40 ). colocando um sinal de barra invertida ( \ ) no final de cada linha inacabado. Strings podem estender para mais de uma única linha de código. tabulações. você pode expressar qualquer personagem com o seu código ASCII numérico escrito por uma barra invertida ( \ ) seguido do código ASCII expresso como um octal ( base 8 ) ou hexadecimal ( base 16 ) de número. que pode preceder a constante com o L prefixo: . quebra de linha ou qualquer outro caractere válido em branco: "Esta forma" um "single" "string" "de caracteres" Finalmente. se quisermos que a string literal a ser feita explicitamente de caracteres de largura ( wchar_t tipo). no segundo caso (hexadecimal). Aqui você tem uma lista de alguns dos códigos de escape como: \ N newline \ R retorno de carro \ T guia \ V guia vertical \ B retrocesso \ F alimentação de formulário (alimentação de página) \ A alerta (bip) \ ' aspas simples (») \ " aspas duplas (") \? ponto de interrogação (?) \ \ barra invertida (\) Por exemplo: 1 2 3 4 '\ N' \ t '" "\ t Direita Esquerda" "uma \ \ nDuas nthree" Além disso. em vez de caracteres estreitos ( char tipo).especiais que são difíceis ou impossíveis de expressar de outra forma no código-fonte de um programa. Todos eles são precedidos por uma barra invertida ( \ ). 1 "String expressa em \ duas linhas" 2 Você pode também concatenar as constantes da cadeia várias separando-os por um ou vários espaços em branco. um xpersonagem deve ser escrito antes dos dígitos si (por exemplo \ x20 ou \ x4A ). como nova linha ( \ n ) ou guia ( \ t ). h> # define PI 3. círculo = 2 * PI * r . estes eram PI e NEWLINE ) pelo código para o qual foram definidos (3.4159 Na verdade a única coisa que o pré-processador do compilador faz quando encontra # define diretrizes é literalmente substituir qualquer ocorrência de seu identificador (no exemplo anterior. Uma vez que eles são definidos. Declarada constantes (const) Com a const prefixo que você pode declarar constantes com um tipo específico da mesma forma como você faria com uma variável: . ele também será anexado em todas as ocorrências do identificador no corpo do programa que o pré-processador substitui. return 0.14159 e ' \ n ' . você pode usá-los no resto do código como se fossem qualquer outro regular constante. mas uma diretiva para o pré-processamento.14159 # define 'nova linha \' n int main () { dupla r = 5.L "Esta é uma seqüência de caracteres de largura" caracteres de largura são usados principalmente para representar conjuntos de caracteres não-Inglês ou exóticos. pelo que assume toda a linha como a directiva e não necessita de um ponto e vírgula ( . Estes podem ser expressos em C + + como valores do tipo bool . O # define directiva não é um C + + afirmação. ) na sua extremidade. utilizando os literais booleanos verdadeiro e falso . ) no final. por exemplo: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 / / Constantes definidas: calcular a circunferência # include <stidio. } 31. Se você acrescentar um caractere de ponto e vírgula ( . / / raio duplo círculo.14159 2 # define 'nova linha \' n Isso define duas constantes novo: PI e NEWLINE . printf (NEWLINE). <<círculo judicial.0. Seu formato é: # Define identificador valor Por exemplo: 1 # Define PI 3. simplesmente usando o # definir diretiva de préprocessamento. literais booleanos Há apenas dois válido valores booleanos: true e false . Constantes definidas (# define) Você pode definir seus próprios nomes para constantes que você usa muito frequentemente sem ter que recorrer a variáveis de consumo de memória. respectivamente). principalmente. mas estão disponíveis em todos os teclados. Diferente de outras linguagens cujos operadores são palavras-chave. A maioria dos detalhes são fornecidos apenas para servir como uma referência futura no caso de você precisar dele. a = b. o resultado de uma operação ou qualquer combinação destes. printf ("a:") . b:? 10 a: 10. Esta afirmação atribui o valor inteiro 5 à variável um . O valor que foi armazenado até o momento em um não é considerado em todo este funcionamento. Aqui.1 const 2 const int pathwidth = 100. Atribuição (=) O operador de atribuição atribui um valor a uma variável. Considere também que estamos apenas atribuindo o valor de b para um momento da operação de cessão. C + + integra operadores.} / / / / / / / / / / a:?. O lvalue tem que ser uma variável enquanto o rvalue pode ser uma constante. Por exemplo.Eu incluí a evolução do conteúdo armazenado em variáveis como os comentários: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 / / Operador de atribuição # include <stdio. podemos começar a operar com eles. uma mudança depois de b não afetará o novo valor de uma . Isso faz com C + + código mais curto e mais internacional. b = 7. Eles são tratados como variáveis regulares. uma vez que se baseia menos em palavras em Inglês. a = 10. uma variável. exceto que seus valores não podem ser modificadas após a sua definição. printf (b). os operadores em C + + são feitos principalmente de sinais que não são parte do alfabeto. A regra mais importante quando a atribuição é da direita para a esquerda regra: A operação de atribuição ocorre sempre da direita para a esquerda. printf (a). b = 4. b: 7 um: 4 b: 7 . mas requer um pouco de esforço de aprendizagem no início. e nunca outra maneira: a = b. a = 5. Esta afirmação atribui à variável um (a lvalue) o valor contido na variável b (o rvalue).h> int main () { int a. printf ("b"). Para esse efeito. b. b? a:. b: 4 a: 4. Portanto. return 0. vamos ter um olhar para o código a seguir . char tabulação = '\ t' . e no fato de que o valor é perdido. Você não tem de memorizar todo o conteúdo desta página. Operadores Uma vez que sabemos da existência de variáveis e constantes. pathwidth e tabulação são duas constantes digitado. b: 4 a: 4. A parte do lado esquerdo do operador de atribuição ( = ) é conhecido como olvalue (valor à esquerda) eo da direita como rvalue (valor correto). Por exemplo: a = 2 + (b = 5). Uma propriedade que C + + tem sobre outras linguagens de programação é que a operação de atribuição pode ser utilizado como rvalue (ou parte de um rvalue) por outra operação de cessão. se escrevermos: a = 11% 3.%) As cinco operações aritméticas suportadas pela linguagem C + + são: + Além . a variável de um conterá o valor 2 . O único que talvez não seja tão acostumados a ver é modulo . pois 2 é o resto da divisão 11 entre os três . . Módulo é a operação que dá o resto de uma divisão de dois valores. Ele atribui cinco ao todo três variáveis: uma .subtração * multiplicação / divisão % modulo As operações de adição. Por exemplo. /. -. 5). b e c . em seguida. Observe como um não foi afetada pela modificação final de b . multiplicação e divisão correspondem literalmente com seus respectivos operadores matemáticos. 2 que significa: primeiro atribuir 5 para a variável b e. A expressão a seguir também é válido em C + +: a = b = c = 5. Os operadores aritméticos (+. subtração. é equivalente a: 1 b = 5. deixando uma com um valor final de 7 . apesar de declarada a = b anterior (que é por causa do para a esquerda regra de direito ). atribuir um valor 2 mais o resultado da tarefa anterior de b (ou seja. a = 2 + b. cujo operador é o sinal de porcentagem ( % ).16 17 18 19 20 Esse código nos dará como resultado que o valor contido no um é quatro e que se inclui na b é 7 . *. c = c +1. No início de compiladores C. a 2 prinf (a). portanto. -= a 5.). Isso significa que podem ser escritos antes da variável (identificador + + a ) ou depois ( a + + ). como a + + ou + + a ambos têm exatamente o mesmo significado. -=. b = 3. *= / =%. a = a / b. -) Encurtando ainda mais algumas expressões. =. aumentar ou reduzir a um valor armazenado em uma variável. =. as três expressões deve produzir exatamente o mesmo código executável. portanto. em outras expressões em que o resultado da ou diminuir operação de aumento é avaliada como um valor em uma expressão exterior podem ter uma diferença importante no seu significado: o caso que o operador aumento é utilizado como um prefixo (+ + a) o valor é aumentado antes o resultado da expressão é avaliada e. Embora em expressões simples. o valor é armazenado em um aumento depois de ser avaliado e. ^ & =. as três expressões anteriores. este tipo de otimização de código é geralmente feito automaticamente pelo compilador. * preço = preço (unidades + 1). Observe a diferença: . c + = 1. a = b. no caso em que é usado como um sufixo ( a + + ). <<=. a = a . o valor armazenado antes da operação de aumento é avaliada a expressão externa. Atualmente. a + = 2. portanto. aumentou o valor é considerado na expressão exterior. Assim: 1 c + +. podemos usar os operadores de atribuição composta: expressão é equivalente a valor + = aumento. o operador de incremento ( + + ) eo operador de diminuição ( .h> int main () { int a.Composto de atribuição (+ =. eo mesmo para todos os outros operadores. Por exemplo: 1 2 3 4 5 6 7 8 9 10 11 12 13 / / Operadores de atribuição composta # include <stdio. return 0 . provavelmente produzida código executável diferente dependendo de qual delas foi usada. São equivalentes a + = 1 ea -= 1 . | =) Quando queremos modificar o valor de uma variável realizando uma operação no valor atualmente armazenado nessa variável. valor = valor + aumento. Uma característica desse operador é que pode ser usado tanto como um prefixo e um sufixo como.5. 2 3 são todos equivalentes na sua funcionalidade: três deles aumentará de um valor de c. respectivamente.> =. a / = b. *= preços unidades + 1. } / / equivalente a = 5 Aumentar e diminuir (+ +. / / avalia como verdadeiro. produzindo false se seu operando . B contém 4 / / A contém 3.Exemplo 1 Exemplo 2 B = 3. A = + + B.Aqui está uma lista dos operadores relacionais e de igualdade que pode ser usado em C + +: == Igual a ! = Não é igual a > < Superior Menos > = Maior ou igual a <= Inferior ou igual a Aqui há alguns exemplos: 1 2 3 4 5 (7 == 5) (5> 4) (3! = 2) (6> = 6) (5 < 5) / / avalia como falso. B contém 4 No Exemplo 1. / / avalia como falso. na última expressão ((b = 2) == a) . (b 4 a> * c) / / avalia como falso desde (3> 2 * 4 6) é falso. <=) Para avaliar uma comparação entre duas expressões. podemos usar qualquer expressão válida. Nós podemos querer comparar duas expressões. Enquanto no Exemplo 2. Cuidado! O operador = (um sinal de igualdade) não é o mesmo que o operador == (dois sinais de igual). Os operadores lógicos (& &. / / avalia como verdadeiro. ea única coisa que ele faz é valorizar o inverso dela. |! |) O Operador ! é o operador C + + para realizar a operação booleana não. que também armazena o valor 2 . Suponha que a = 2 . O resultado de uma operação relacional é um valor booleano que só pode ser verdadeiro ou falso. localizado a sua direita. o valor de B é copiado para um e B é aumentada. b = 3 e c = 6 . / / A contém 4. ele tem apenas um operando. então o resultado da operação é verdade. A = B + +. primeiro atribuído o valor 2 para b e então comparou a um . / / avalia como verdadeiro. por exemplo. o primeiro é um operador de atribuição (atribui o valor de seu direito à variável à sua esquerda) eo outro ( = = ) é o operador de igualdade que compara se as duas expressões nos dois lados são iguais uns aos outros. B = 3.! =. Assim. 1 2 3 4 (A == 5) / / avalia como falso uma vez que não é igual a 5. incluindo variáveis. Claro que. de acordo com seu resultado booleano. Relacionais e operadores de igualdade (==. <. para saber se eles são iguais ou se um é maior do que o outro é.> =. B é aumentada antes que seu valor é copiado para um . ((b = 2) == a) / / avalia como verdadeiro. (a * b> = c) / / avalia como verdadeiro uma vez (2 * 3> = 6) é verdadeira. podemos usar os operadores relacionais e de igualdade.>. em vez de usar somente constantes numéricas. Esta operação resulta verdadeiro se qualquer um de seus dois operandos é verdadeiro. Os operadores lógicos & & e | | são usados na avaliação de duas expressões para obter um único resultado relacional. e funciona assim para estes operadores: operador curto-circuito se a expressão do lado esquerdo for falso. ele retorna o Boolean valor oposto de avaliar seu operando. ele nunca iria verificar se 3> 6 é verdadeira ou não . neste último exemplo ( (5 == 5) | | (3> 6) ). Por exemplo: 1 2 3 4 ! ! ! ! (5 == 5) (6 <= 4) verdade false / / avalia a falsa porque a expressão à sua direita (5 == 5) é verdadeira. / / resulta em falso / / avalia como verdadeiro. ignorando o resto. C + + só avalia o que é necessário. / / avalia como verdadeiro porque (6 <= 4) seria falsa. sendo falsa somente quando ambos os operandos são falsos si.é verdade e verdade se seu operando é falso. & & . Aqui estão os resultados possíveis de a | | b : | | OPERADOR ou OR um b a||b verdade verdade verdade verdade falsa falsa falsa verdade verdade verdade falsa falsa Por exemplo: 1 ((5 == 5) & & (3> 6)) 2 ((5 == 5) | | (3> 6)) / / avalia como falso (true & & false). C + + que avaliar primeiro se 5 == 5 é verdadeira. / / avalia como verdadeiro (true | | false ). Esta operação resulta verdadeiro se ambos os seus dois operandos são verdadeiros e falso caso contrário. Isso é conhecido como a avaliação de curto-circuito. o resultado combinado é falsa (lado direito de expressão secundários não avaliados). Basicamente. O quadro a seguir mostra o resultado do operador & & avaliação da expressão a & & b : Operador & & ou AND um b a&&b verdade verdade verdade verdade falsa falsa falsa falsa verdade falsa falsa falsa O operador | | corresponde com a lógica de operação lógica OR. da esquerda para a direita para avançar com o relacional resultado combinado. Portanto. O operador & & corresponde à operação lógica booleana AND. Ao utilizar os operadores lógicos. e se assim for. pois caso contrário. Isto é mais importante quando a expressão do lado direito tem efeitos colaterais. inicialmente. b +2). com um valor de 7 . um era 2 e b foi 7 . que Foi b . o lado direito de expressão ( + + i <n ) nunca é avaliado. assim. o valor especificado após o ponto de interrogação foi descartado em favor do segundo valor (o que depois dos dois pontos). a ou b. como alteração valores: if ((i <10 )&&(++ n <i)) { /*. Por exemplo.h> int main () { int a. 5> 3? a: b / / retorna o valor de uma. apenas a expressão mais à direita é considerada. se não for ele retornará result2 . operador condicional (?) O operador condicional avalia uma expressão retornando um valor se essa expressão é verdadeira e um diferente se a expressão é avaliada como falsa. o resultado combinado é verdadeiro (lado direito de expressão secundários não avaliados). Seu formato é: condição? result1: result2 Se a condição for verdadeira a expressão retornará result1 .) O operador vírgula ( . a = 2. o seguinte código: a = (b = 3. . pois 5 é maior que 3. a> b? a: b / / retorna o que for maior. c..*/ } Isto combinado condicional aumenta a expressão i por um. b = 7 c = (a> b)? a: b. já que 7 é igual a 5 2. 1 2 3 4 7 == 5? 4: 3 / / retorna 3. ) é usada para separar dois ou mais expressões que são incluídos em uma única expressão é o esperado. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 / / Operador condicional # include <stdio. Operador vírgula (. 7 == 5 +2? 4: 3 / / retorna 4. printf (c).Quando o conjunto de expressões tem que ser avaliado por um valor. então a expressão a ser avaliada ( a> b ) não era verdadeira.| | se a expressão do lado esquerdo é verdade. b.. mas somente se a condição na esquerda da & & é verdade. pois 7 não é igual a 5. } 7 Neste exemplo. return 0. operador equivalente asm descrição AND bit a bit Inclusive OR bit a bit Bit a bit OU Exclusivo Unários complementar (inversão de bits) Shift Esquerda Shift direito & | ^ ~ << >> E OU XOR NÃO SHL SHR Operador de conversão explícita de tipo Tipo de fundição operadores permitem converter um dado de um determinado tipo para outro. Ambas as formas de conversão de tipo são válidas em C + +. 3 O código anterior converte o número float 3. Existem várias maneiras de fazer isso em C + +. <<. Operadores bit a bit (&. ~. a variável um deve conter o valor 5 .14 para um valor inteiro ( 3 ). 2 float f = 3. Assim. |. . considerando os padrões de bits que representam os valores que eles armazenam. e depois atribuir b 2 a variável um . que foi herdada da linguagem C. por isso é sempre determinado antes da execução do programa.Em primeiro lugar. no final. o operador foi typecasting(int) .14. que pode ser tanto um tipo ou variável em si e retorna o tamanho em bytes desse tipo ou objeto: a = sizeof ( char ). deve preceder a expressão a ser convertido por um novo tipo colocada entre parênteses ( () ): 1 int i. enquanto variável b seria conter o valor 3 . Isso vai atribuir o valor de um para um. ^. sizeof () Esse operador aceita um parâmetro. porque char é um tipo de bytes de tamanho um. i = ( int ) f. Outra maneira de fazer a mesma coisa em C + + está usando a notação funcional: precedendo a expressão a ser convertido pelo tipo e colocando a expressão entre parênteses: i = int (f).>>) Operadores bit a bit modificar as variáveis. O valor retornado por sizeof é uma constante. Aqui. O mais simples. atribuir o valor 3 para b . o restante é perdido. podemos ter algumas dúvidas sobre qual operando é avaliado primeiro e que mais tarde.Outros operadores Mais tarde. Precedência dos operadores Ao escrever expressões complexas com vários operandos. a ordem de prioridade é a seguinte: Nível 1 Operador Descrição escopo Agrupamento Da esquerda para a direita Da esquerda para a direita :: () [].~! sizeof nova apagar 2 postfix unário (prefixo) indiretamente.* -> * ponteiro-para-membro 6 *% / multiplicativo 7 + - aditivo 8 <<>> mudança 9 <> <=> = relacional 10 ==! = igualdade . mas para todos os operadores que podem aparecer em C + +.Dynamic_cast const_cast reinterpret_cast static_cast typeid + + . e de referência (ponteiros) operador de sinal unário tipo de vazamento 3 * & + - Da direita para a esquerda 4 (Tipo) Da direita para a esquerda Da esquerda para a direita Da esquerda para a direita Da esquerda para a direita Da esquerda para a direita Da esquerda para a direita Da esquerda para a direita 5 . estes tutoriais. e não apenas os aritméticos (aqueles cuja preferência vêm da matemática). Cada um é tratado em sua respectiva seção. Há uma ordem estabelecida com a prioridade de cada operador. vamos ver mais alguns operadores. ou / / com um resultado de 0 A resposta correta é a primeira das duas expressões. nesta expressão: a = 5 + 7% 2 podemos duvidar se ele realmente significa: 1 a = 5 + (7% 2) 2 a = (5 + 7)% 2 / com um resultado de 6. com um resultado de 6 . -> + + . Por exemplo. Do maior para a menor prioridade. como os referentes a ponteiros ou os específicos para programação orientada a objetos. como a tela ou o teclado. Básico Input / Output Até agora. desde muito pouca interação com o usuário. ou a = (5 + 7) 2%. C + + usa uma abstração conveniente chamados fluxos para realizar operações de entrada e de saída em meio seqüencial. como neste exemplo: a = 5 + 7% 2. em que os operadores são avaliados no caso de existirem vários operadores do mesmo nível em uma expressão. pode ser escrito como: a = 5 + (7% 2). os programas de exemplo das seções anteriores. Nós realmente não precisa se preocupar com muitas especificações sobre os meios físicos associados com o fluxo . Ele também fará seu código mais fácil de ler. seremos capazes de interagir com o usuário através da impressão de mensagens na tela e começar a entrada do usuário a partir do teclado. sempre inclua parênteses. Todos esses níveis de precedência dos operadores pode ser manipulado ou se tornar mais legível removendo possíveis ambiguidades usando sinais entre parênteses ( e ) . Um stream é um objeto onde um programa pode inserir ou extrair caracteres para / a partir dele. dependendo da operação que deseja executar. se você quiser escrever expressões complicadas e você não está completamente certo dos níveis de prioridade. Então.só precisamos de saber que vai aceitar ou fornecer caracteres em . Usando o padrão de entrada e saída de biblioteca. vírgula Agrupamento define a ordem de precedência. se houver algum.11 & AND bit a bit Da esquerda para a direita Da esquerda para a direita Da esquerda para a direita Da esquerda para a direita Da esquerda para a direita Da direita para a esquerda Da direita para a esquerda Da esquerda para a direita 12 ^ XOR bit a bit 13 | OR bit a bit 14 & & E lógico 15 | | OR lógico 16 ?: condicional 17 = *= / =% = + = -=>> = <<= & = ^ = | = atribuição 18 . Se assumirmos que a idade variável para conter o valor 24 eo cep variável para conter 90. 1 Printf ("sentença de Saída"). 2 printf (Olá).h . "Eu sou" . / / imprime Olá / / imprime o conteúdo da variável Olá O operador de inserção ( . sem qualquer quebra de linha entre eles: Este é um sentence. Saída Padrão (tribunal) Por padrão.seqüência. essas duas frases têm resultados muito diferentes: 1 printf ("Olá")."). a saída padrão do programa é a tela. O utilitário de repetir o operador de inserção ( . será mostrado na tela uma após a outra. Sempre que quisermos usar seqüências de caracteres constantes.064 a saída da declaração anterior seria: Olá. onde o padrão de entrada e saída de objetos de fluxo são declaradas.This é outra frase. 2 printf ("Esta é uma outra sentença. / / imprime na tela frase saída / / imprime o número 120 na tela / / imprime o conteúdo de x na tela O printf operador insere os dados que segue para a corrente que o precede. 3 Printf (x)."). Esta última afirmação deve imprimir a mensagem Olá. CEP). a constante numérica 120 e variável x dentro do padrão de saída de fluxo de corte . Observe que a sentença em primeira instrução é colocada entre aspas ( " ) porque é uma constante cadeia de caracteres. a menos que explicitamente indicam que. eo C + + objeto de fluxo definido para acessá-lo é tribunal . 2 Printf (120). . tenho 24 anos e meu cep é 90064 É importante notar que o tribunal não adiciona uma quebra de linha após a sua saída. devemos colocá-los entre aspas ( " ) para que eles possam ser claramente distinguidos dos nomes de variáveis. Por exemplo. ) pode ser utilizado mais de uma vez em uma única instrução: Printf ("Olá" . portanto. eu sou". "C + + uma declaração" ). O padrão C + + biblioteca inclui o arquivo de cabeçalho stdio. Nos exemplos acima é inserido a constante string frase de saída . ) é demonstrada quando queremos imprimir uma combinação de variáveis e constantes ou mais de uma variável: printf ("Olá. eu sou um C + + declaração na tela.idade. as seguintes afirmações: 1 printf ("Esta é uma sentença."anos de idade e meu cep é". Segunda frase. 1 2 3 4 5 6 7 / I / o exemplo # include <stdio. Para realizar uma quebra de linha na saída. se você pedir um personagem que você vai ter um personagem e se você pedir uma cadeia de caracteres que você terá uma seqüência de caracteres. para adicionar uma nova linha. mesmo se você solicitar um único personagem.mesmo que tinha escrito em dois diferentes inserções em tribunal . Por exemplo: 1 int idade. printf ("Digite um valor inteiro:" ). mas também tem um comportamento adicional quando ele é usado com buffered streams: o buffer é liberado. sem qualquer diferença em seu comportamento. tribunal será um fluxo unbuffered na maioria dos casos. Em C + + um caractere de nova linha pode ser especificado como \ n (n barra invertida): 1 printf ("Primeira frase n. \"). 2 printf ("segunda frase. Por fa . 2 printf ("Segunda frase frase. Por exemplo: 1 printf ("primeira frase. a fim de especificar uma nova linha. Portanto. Segunda frase. devemos explicitamente inserir um caractere de nova linha em quadra . a fim de guardá-la nesta variável inteira. Além disso. você também pode usar o endl manipulador. A primeira instrução declara uma variável do tipo int chamado de idade .\n"). exatamente como a inserção de '\ n' faz.). assim que você geralmente pode usar tanto o \ n caractere de escape ea endl manipulador.\n"). Isso produz o seguinte resultado: Primeira frase.h> int main () { int i. Você deve sempre considerar o tipo da variável que você está usando como um recipiente com cin extrações. deveria imprimir: Primeira frase. Se você pedir um inteiro que você irá obter um número inteiro. nThird \".&idade. a extração de scanf não irá processar a entrada até que o usuário pressiona RETURN após o personagem ter sido introduzida. O operador deve ser seguido pela variável que irá armazenar os dados que vai ser extraído do córrego. Enfim. O endl manipulador produz um caractere de nova linha. eo segundo aguarda a entrada de cin (teclado). O dispositivo de entrada padrão é geralmente o teclado. Entrada Padrão (NIC). A terceira frase. scanf só pode processar a entrada do teclado uma vez que o RETURN tecla foi pressionada. 2 scanf ("%d". Manipulação da entrada padrão em C + + é feito através da aplicação do operador sobrecarregado de extração ( &) no scanf fluxo. um para a variável de um e outro para a variável b que podem ser separados por qualquer separadoras em branco válidos: um espaço. ou tomar decisões.&i). deve ser colocada entre chaves ( {} ). C + + oferece estruturas de controle que servem para especificar o que deve ser feito pelo nosso programa. Durante o seu processo. printf ("e seu duplo é". quando e sob quais circunstâncias. como parte de sua sintaxe. 2 Em ambos os casos o usuário deve dar dois dados. instrução é executada. o seguinte fragmento de código imprime x é de 100 somente se o valor armazenado em x variável é realmente 100 : 1 if (x == 100printf ("x é 100").i).} Você também pode usar scanf para solicitar mais de um dado de entrada do usuário: Scanf ("%d%d". repetir o código. Mas no caso que nós queremos que a instrução seja uma instrução composta. podem se bifurcar. scanf("%d".i * 2 .&a). não precisa incluí-la entre chaves ( {} ).&a. No caso em que queremos que a instrução seja uma instrução simples. mas agrupados em um bloco entre chaves: {} : {Comando1. declaração é ignorado (não executado) eo programa continua logo após esta estrutura condicional. um caractere de tabulação ou uma nova linha. como a descrita acima. instrução3. Por exemplo.} A maioria das estruturas de controle que veremos nesta seção requerem um enunciado genérico. Um bloco é um grupo de instruções que são separados por ponto e vírgula (. formando um bloco. Sua forma é: if (condição) declaração Onde condição é a expressão que está sendo avaliado. Se for falsa. Para esse efeito. Se esta condição for verdadeira."n \"). é equivalente a: 1 Scanf ("%d". return 0.&b). Com a introdução de estruturas de controle nós vamos ter que introduzir um novo conceito: o composto de instrução ou bloco .8 9 10 11 12 13 14 scanf ("%d". A declaração pode ser simples declaração (uma simples instrução termina com um ponto e vírgula) ou um comando composto (várias instruções agrupadas em um bloco). estrutura condicional: if e else O caso palavra-chave é usada para executar uma instrução ou bloco somente se uma condição é satisfeita. statement2.&b). 2 . Estruturas de Controle Um programa é geralmente não se limita a uma seqüência linear de instruções. printf ("O valor que você inseriu é".) como todas as instruções C + +. zero): 1 if (x> 0) printf ("x é positivo"). vamos fazer um programa para diminuir a contagem usando um ciclo while: 1 / / Contagem regressiva personalizada usando enquanto Digite . podemos especificar um bloco usando chaves {} : 1 2 3 4 5 if (x == 100) { printf ("x é"). ele imprime x não é 100 . colocando-os entre chaves {} . printf (x). negativo ou nenhum deles (ou seja. Sua forma usada em conjunto com se é: if (condição) else statement1 statement2 Por exemplo: 1 if (x == 100) 2 printf ("x é 100"). O caso mais + estruturas podem ser concatenado com o intuito de verificar um intervalo de valores. mas se não tiver e só se não for. imprime na tela é 100 x se de fato x tem um valor de 100 . } Podemos adicionalmente especificar o que quer que aconteça. Por exemplo. Lembre-se que no caso em que queremos mais do que uma simples instrução a ser executada.Se nós queremos mais do que uma simples instrução a ser executada no caso de que a condição é verdadeira. estruturas de iteração (loops) Loops tem como finalidade a repetir uma afirmação de um certo número de vezes ou enquanto uma condição for cumprida. 6 else printf ("x é 0"). 2 3 4 else if (x <0) 5 printf ("x é negativo"). 3 4 else printf ("x não é 100"). se a condição não for cumprida. O exemplo a seguir mostra a sua utilização dizer se o valor atualmente armazenado em x é positivo. O laço while Seu formato é: while (expressão) instrução e sua funcionalidade é simplesmente repetir while a condição estabelecida na expressão é verdadeira. usando a palavra-chave mais . devemos agrupá-los em um bloco. devemos sempre considerar que ele tem que terminar em algum momento."). que é onde o nosso tempo de ciclo e nosso fim de contagem regressiva. Ao criar um laço while.2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 # include <stdio.". O laço do-while Seu formato é: do while (condição). 2. Claro que isto é uma ação tão simples para o nosso computador que a contagem é feita toda de imediato. portanto. } Ao iniciar o programa o usuário é solicitado a inserir um número inicial para a contagem regressiva. sem qualquer atraso prática entre os números. return 0.N. mesmo condição nunca é cumprida. Então. nós incluímos . . scanf ("%d".h> int main () { int n. Sua funcionalidade é exatamente o mesmo que o loop while. em vez de antes. dentro do bloco de algum método para forçar a condição se tornar falsa em algum momento. quando n se torna 0 . 3. se o valor digitado pelo usuário preenche a condição n> 0 (que n é maior do que zero) o bloco que segue a condição será executado e repetido enquanto a condição ( n> 0 ). caso contrário. continua sendo verdade..". Neste caso. que diminui o valor da variável que está sendo avaliado na condição ( n ) por um . 5. a concessão.". } printf ("FIRE \ n!)" . 1 / / Echoer número 2 Digite o número 0 para terminar: 12345 Você digitou: 12345 Digite o número 0 para terminar: . O processo inteiro do programa anterior pode ser interpretado de acordo com o seguinte roteiro (a partir de principal): 1. while (n> 0) { printf (n. o loop continuará looping para sempre.n. (Imprime o valor de n na tela e diminui n de 1 ) Fim do bloco. pelo menos. temos de fornecer. exceto que a condição do loop do-while é avaliada após a execução da declaração. Usuário atribui um valor para n A condição enquanto estiver marcada ( n> 0 ).n. Voltar automaticamente para a etapa 2 Continuar o programa certo depois que o bloco: FOGO imprimir! e um programa final. o programa ecos exemplo a seguir qualquer número que você entra até que você digite 0 . Neste ponto existem duas possibilidades: * condição for verdadeira: instrução é executada (para o passo 3) * condição é falsa: ignorar instrução e continuar depois (para a etapa 5) instrução de execução: printf (n. o tempo de loop começa.n). printf ("Digite o número maio de partida").isso acabará por tornar a condição ( n> 0 ) para tornar-se falso depois de um certo número de loop iterações: para ser mais específico. 4. Por exemplo. uma execução de declaração . } printf ("FIRE n! \").} 10. 11 12 return 0. Portanto. além disso. onde a entrada do usuário dentro do bloco é o que é usado para determinar se o loop tem que acabar. De fato. os sinais de ponto e vírgula entre eles deve ser escrita. n <10) . n> 0. enfim.&n). 9. Ele funciona da seguinte maneira: 1. inicialização é executada. 4.3 # include <stdio. se quiséssemos incluir um campo de aumento. enquanto condição for verdade. contador. Geralmente é um valor inicial de configuração para uma variável de 2. mas em todos os casos. este ciclo é especialmente concebido para realizar uma ação repetitiva com um contador que é inicializado e aumentou em cada iteração. o laço termina e instrução é ignorada (não executado). como no caso anterior. n <10. tudo o que é especificado no aumento campo é executado eo ciclo se volta para a etapa 2."). você pode ser solicitado para mais números sempre. ou para (. . 3. Como de costume. a de loop fornece localizações específicas para conter a inicialização de declaração e um aumento de declaração. Eles podem ficar vazios. aumento) declaração.} 13 14 15 O do-while normalmente é utilizado quando a condição que tem de determinar o fim do ciclo é determinada dentro da instrução loop em si."\ n").) se quiséssemos especificar nenhuma inicialização e não aumentar. 9 printf ("Você digitou: ". Se é verdade o ciclo continua. poderíamos escrever: for (. ele pode ser uma única instrução ou um bloco entre chaves {} . 8 scanf("%d". condição. n -) { printf (tribunal n". mas não de inicialização (talvez porque a variável já foi inicializada antes). como o loop while.h> 160277 Você digitou: 160277 4 Digite o número 0 para terminar: 0 Você digitou: 0 5 int main () { unsigned tempo n. n + +. return 0. Esta é executado apenas uma vez. A inicialização e aumentar os campos são opcionais. e sua principal função é repetir a afirmação . Por exemplo.h> int main () { for ( int n = 10. condição é verificada. instrução é executada. 6 do { 7 printf("Digite o número 0 para terminar:"). se você não inserir o valor 0 no exemplo anterior. Mas.n . 10 }while (! n = 0). Aqui está um exemplo de contagem regressiva usando um loop for: 1 2 3 4 5 6 7 8 9 10 11 / Contagem regressiva / usando um loop # include <stdio. caso contrário. O laço for Seu formato é: for (inicialização. ) é um separador de expressão. ou forçá-lo a terminar antes de seu fim natural.Opcionalmente. n + +.h> int main () { int n. . Porque n é aumentada de um e eu diminuído por um. O operador vírgula ( . quando ambos n e i será igual a 50 . 9. A instrução break Usando quebrar podemos deixar um loop mesmo que a condição para o seu fim não é cumprido. usando o operador vírgula ( . n! = i."). suponha que queremos iniciar mais de uma variável no nosso loop: 1 for (n = 0. Por exemplo. a condição é n! = i (que n não é igual a i ). por exemplo. } 10. Por exemplo. e eu com 100 . como na inicialização . podemos especificar mais de uma expressão em qualquer um dos campos incluídos em um de laço. n> 0..". Ele pode ser usado para terminar um loop infinito. a condição do loop se tornará falso depois do ciclo 50. 2 3 } 4 Este loop será executado por 50 vezes. if (n == 3) { printf ("contagem regressiva abortado!"). vamos pular o número 5 em nossa contagem regressiva: 1 / / Continue exemplo loop 10. como se o fim do bloco de declaração tinha sido alcançado. ). n -) { printf (n.. fazendo com que ele salte para o início da iteração seguinte. Ir declarações. i = 100. 9.} } return 0. se não n ou i são modificadas dentro do loop: n começa com um valor de 0 . que serve para separar mais de uma expressão em que apenas um é normalmente esperado.Por exemplo. A instrução continue A continuar a instrução faz com que o programa para passar o resto do laço na iteração atual. i -) { / / qualquer coisa aqui . break . vamos parar a contagem regressiva antes de seu fim natural (talvez por causa de uma falha de verificação do motor?): 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 / / Exemplo de loop break # include <stdio. for (n = 10. Você deve usar esse recurso com cautela. De um modo geral."FIRE n! \n"). loop: 6 printf (n.". O objectivo da saída é terminar o programa actual. printf (n. O ponto de destino é identificado por uma etiqueta. n -) { if (n == 5) continue . printf (tribunal. Por convenção.2 3 4 5 6 7 8 9 10 11 12 13 # include <stdio. A sintaxe da instrução switch é um pouco peculiar. pois sua execução faz com que um salto incondicional ignorando qualquer tipo de limitações de aninhamento. um código de saída de 0 significa que o programa terminou normalmente. Algo semelhante ao que fizemos no início desta seção. 9 10 return 0. com a concatenação de vários se e else if instruções. O exitcode é utilizado por alguns sistemas operacionais e pode ser utilizado por chamada de programas. com um código de saída específico.} 11 12 13 14 15 10.n -).". Por exemplo. Seu objetivo é verificar possíveis diversos valores constantes de uma expressão. Um rótulo é feito de um identificador válido seguido por dois pontos ( : ). 9 A função de saída saída é uma função definida na cstdlib biblioteca. return 0. } printf ("FIRE n! \n") . aqui é o nosso laço de contagem regressiva usando goto : 1 / / Exemplo de loop goto 2 3 # include <stdio. } A instrução goto goto permite fazer um salto absoluto para outro ponto do programa. Seu protótipo é: void exit ( int exitcode).h> 4 int main () { 5 int n = 10. A estrutura seletiva: switch. Sua forma é o seguinte: .h> int main () { for (int n = 10. n> 0. esta instrução não tem nenhum uso concreto estruturado ou programação orientada a objeto com exceção daqueles que os fãs de programação de baixo nível pode encontrar para ele. que depois é usado como um argumento para a instrução goto.""). e qualquer outro valor significa que alguns resultados inesperados ou erro aconteceu. 7 8 if (n> 0) goto loop. break. e em seguida. se não incluir uma quebra de declaração após o primeiro grupo de um caso. 2 ou 3"). Se for igual a este. . Quando encontra esse quebra declaração o programa salta para o final do switch estrutura seletiva. use uma concatenação de se e então se declarações.. ele executa um grupo de comandos até encontrar o break comunicado. Portanto. 3): ) porque eles não são válidos C + + constantes. Finalmente. Se a expressão não era igual a constant1 será verificado contra constant2 . caso n: onde n é uma variável) ou intervalos ( caso (1 . incluindo os correspondentes a outros rótulos também será executado até o final do switch bloco seletiva ou um quebra afirmação é atingido. Ambos os fragmentos de código a seguir têm o mesmo comportamento: switch exemplo equivalente if-else if (x == 1) { printf ("x é 1"). default: default grupo de instruções} Ele funciona da seguinte maneira: switch avalia expressão e verifica se ele é equivalente a constant1 . 4 break . 5 default : printf ("x não é 1. Por exemplo. else { } Printf ("valor de x desconhecido"). } O interruptor de declaração é um pouco peculiar dentro da linguagem C + +. 2 ou 3") . if (x == 2) { case 2: printf ("x é 2"). Se você precisar verificar a extensão ou os valores que não são constantes. e pode também ser útil para executar o mesmo bloco de instruções para diferentes valores possíveis para a expressão ser avaliada. 6 } 7 8 9 Observe que a chave só pode ser usado para comparar uma manifestação contra constantes. Isso torna desnecessário incluir chaves {} em torno das declarações de cada um dos casos. se o valor da expressão não corresponde a nenhuma das constantes especificadas anteriormente (você pode incluir quantos casos rótulos como os valores que pretende verificar). se for. se existir (desde é opcional). Isto nos obriga a colocar quebra de declarações depois que o grupo de instruções que queremos ser executado para uma condição específica. Caso contrário. ele irá executar grupo de comandos 2 até uma palavra-chave break for encontrada. Funções (I) Usando funções podemos estruturar nossos programas de forma mais modular.} default: printf ("valor de x desconhecido").switch (expressão) {case constant1: grupo de instruções um break. pois ele usa etiquetas em vez de blocos. o programa não irá saltar automaticamente para o final do switch bloco seletivo e que iria continuar a executar o restante das declarações até que ele atinja tanto uma quebra de instrução ou o fim do switch bloco seletivo. o programa irá executar as declarações depois que o padrão: label.. o acesso a todo o potencial que a programação estruturada pode oferecer a nós em C + +. não podemos colocar variáveis como etiquetas (por exemplo.} switch (x) { else case 1: printf ("x é um"). . printf ("x é 2". . irá saltar para o final do switch estrutura seletiva. caso constant2: grupo de instruções 2 break. break. as declarações restante. Por exemplo: 1 switch (x) { caso 1: 2 caso 2: 3 caso 3: printf ("x é 1. z). Logo depois. vamos começar por aí. 0. vemos uma chamada a uma função chamada disso .Uma função é um grupo de instruções que é executada quando é chamada a partir de algum ponto do programa. . No momento em que a função é chamada de dentro principais . int b) { int r. O seguinte é o seu formato: nome do tipo (parameter1.h> int soma ( int a. Então. o . ("O resultado é". Os diferentes parâmetros são separados por vírgulas. que correspondem ao int a e int b parâmetros declarados para além da função. Nós podemos ver como a principal função começa por declarar a variável z do tipo int . parameter2. antes de tudo lembrar algo dito no início deste tutorial: um programa C + + sempre começa a sua execução pelo principal função. que atribui aos r o resultado de um plus b . r = a + b. nome é o identificador pelo qual será possível chamar a função. O valor de ambos os argumentos passados na chamada ( 5 e 3 ) são copiados para as variáveis locais int a e int b dentro da função. printf return } () { além z = ( 5. Como os parâmetros reais passados para um e b são 5 e 3 . Prestando atenção. e por meio da expressão r = a + b . vamos ser capazes de ver a semelhança entre a estrutura da chamada para a função ea declaração da função em si algumas linhas de código acima: Os parâmetros e argumentos têm uma correspondência clara. Entre a principal função que chamamos de além de passar dois valores: 5 e 3 .) {instruções} onde: y y y y tipo é o especificador de tipo de dados dos dados retornados pela função. declarações é a função do corpo. return (r). como qualquer declaração de variáveis regulares (por exemplo: int x ) e que atua dentro da função como uma variável local normal. } int main int z. respectivamente.3). Aqui você tem a função de primeiro exemplo: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 / / Exemplo de função # include <stdio. o controle é perdido pelo principal e passados para a função disso . Eles permitem passar argumentos para a função quando é chamada. O resu A fim de examinar este código. Função disso declara outra variável local ( int r ). É um bloco de instruções entre chaves {} .. parâmetros (como quantas forem necessárias): Cada parâmetro consiste em um tipo de dados seguido por um identificador.. o programa segue o seu curso regular a partir do mesmo ponto em que foi interrompido pelo convite para além . Assim sendo o valor retornado por uma função do valor dado à função de chamar a si mesmo quando é avaliado. ). Mas. Para declarar variáveis globais. produz a impressão do resultado na tela. Finaliza função disso . que são visíveis de qualquer ponto do código. Para explicar de outra forma. que é 8 . no exemplo anterior.z). A seguinte linha de código: retorna (r). Este valor torna-se o valor de avaliação da chamada de função. em primeiro lugar (neste caso. Que. teria sido impossível o uso de variáveis um . você simplesmente tem que declarar a . que naquele momento tinha um valor de 8 . Âmbito das variáveis O escopo das variáveis declaradas dentro de uma função interna ou qualquer outro bloco é apenas a sua própria função ou o seu próprio bloco e não pode ser utilizado fora deles. a principal ). b ou r diretamente na função principal .3) ) é literalmente substituído pelo valor que ela retorna ( 8 ). A seguinte linha de código na seção principal é: Printf ("O resultado é". você pode imaginar que a chamada para uma função ( de adição (5. a variável z será definido como o valor retornado pela adição (5. porque o retorno declaração em função disso especificado um valor: o conteúdo da variável r ( return (r). e retorna o controle para a função que a chamou. Nesse momento. Por exemplo. uma vez que foram as variáveis locais a função disso .resultado é 8 . Portanto. dentro e fora de todas as funções. 3) . como você já pode esperar. também temos a possibilidade de declarar variáveis globais. teria sido impossível usar a variável z diretamente em função disso. No entanto. além disso. o escopo de variáveis locais é limitado ao nível mesmo bloco em que elas são declaradas. uma vez que esta era uma variável local à função principal . Além disso. "\ n"). Por exemplo.2).z. return (r). = ab r. } ("O ("O ("O ("O primeiro resultado é\n". criamos uma função chamada de subtração . A fim de compreender estes exemplos. int b) { int r.variável fora de qualquer função ou bloco. y = 3. teríamos: 1 z = 5. quarto resultado é". printf ("O primeiro resultado é".subtração.2). No entanto.z). E aqui está outro exemplo sobre funções: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 / / Exemplo de função # include <stdio."\ n"). segundo resultado é". deve-se considerar mais uma vez que uma chamada para uma função poderia ser substituído pelo valor que a função de chamar a si mesma que vai voltar. A única coisa que esta função faz é subtrair os parâmetros passados e retorna o resultado. porque é o mesmo padrão que temos usado nos exemplos anteriores): 1 z = subtração(7-2). 2 Bem como printf ("O segundo resultado é a".z). printf ("O primeiro resultado é". } int main () { int x = 5. y). tem o mesmo resultado que a chamada anterior. Basta considerar que o resultado é o mesmo como se tivéssemos escrito: .h> int subtração ( int a. printf printf printf printf return 0.(x.(7. subtração=7-2). y)). diretamente no corpo do programa. z = 4 + subtração (x. ou seja. z = subtração (7. o primeiro caso (que você já deve saber.subtração. veremos que temos feito várias chamadas para a função de subtração . terceiro resultado é a". mas neste caso nós fizemos a chamada para a subtração diretamente como um parâmetro de inserção para tribunal .). Neste caso. se examinarmos a função principal ."\ n". 2 Se substituirmos a chamada de função com o valor que retorna (ou seja. z. Nós usamos alguns chamar métodos diferentes para que você veja outras formas ou momentos em que uma função pode ser chamado. 5 ).z. Isso é perfeitamente válido. 2 Funciona com qualquer tipo. Se você lembra da sintaxe de uma declaração de função: nome do tipo (argumento1. com exatamente o mesmo resultado. ) vai no final de toda a declaração.. A única coisa nova que foi introduzida é que os parâmetros de subtração são variáveis ao invés de constantes. Neste caso. Mas o que se queremos retornar nenhum valor? Imagine que nós queremos fazer uma função só para mostrar uma mensagem na tela.h> void printmessage () { printf ("Eu sou uma função!") . y). argumento2 .. z = 2 + 4. O quarto caso é mais do mesmo.2) . dando 2 como resultado. O uso de vácuo. } int main () { printmessage (). Eu tenho mudado lugares assim que você pode ver que o sinal de ponto e vírgula ( . respectivamente. que são 5 e 3 . Este é um especificador especial que indica ausência de tipo. Não necessariamente tem que ir logo após a chamada da função. } Eu so . que é o tipo de função em si (ou seja. Basta notar que em vez de: z = 4 + subtração (x.printf ("O segundo resultado é 5"). o tipo de dado que será retornado pela função com a instrução de retorno).) declaração você vai ver que a declaração começa com um tipo . No caso de: printf ("O terceiro resultado é a". Neste caso. uma vez que 5 é o valor retornado por subtração (7. os valores passados para a função de subtração são os valores de x e y . 1 2 3 4 5 6 7 8 9 10 11 12 13 / / Exemplo de função void # include <stdio. poderíamos ter escrito: z subtração = (x. A explicação pode ser uma vez mais que você imaginar que uma função pode ser substituído pelo seu valor devolvido: 1 z = 4 + 2. y) + 4. deveríamos usar o vazio especificador de tipo para a função. Nós não precisamos que ele retorne algum valor.subtração. return 0.x. y). a chamada para printmessage é: printmessage (). Mas pode haver alguns casos em que você precisa para manipular de dentro de uma função o valor de uma . Funções (II) Argumentos passados por valor e por referência. 5 e 3 respectivamente. Isto significa que ao chamar uma função com parâmetros. ou seja. se queremos uma função sem parâmetros. mas qualquer modificação a qualquer um .14 vazio também pode ser usado em função do parâmetro na lista para especificar explicitamente que queremos que a função não dar parâmetros reais quando é chamado. Por exemplo. A chamada a seguir teria sido incorreto: printmessage. Dessa forma. o que temos passado para a função eram cópias de seus valores. Por esse motivo. y = 3. 2 O que fizemos nesse caso foi a chamada para a função addition passando os valores de x e y . os argumentos passados para as funções foram passados por valor . em todas as funções já vimos. z. Os parênteses indicam claramente que esta é uma chamada para uma função e não o nome de uma variável ou algum outro C + + declaração. uma lista de parâmetros pode simplesmente ser deixado em branco. mas apenas cópias de seus valores no momento em que a função foi chamada. mas não as variáveis x e y si. suponha que nós chamamos a nossa primeira funçãodisso usando o seguinte código: 1 int x = 5. porque as variáveis x e y não foram eles mesmos passados para a função. ou b dentro da função disso não terá nenhum efeito nos valores de x e y fora . A inexistência de parâmetros não nos exime da obrigação de escrever os parênteses. y). Em C + +. z = soma (x. O que você deve sempre lembrar é que o formato para chamar uma função inclui especificando seu nome e encerrando os respectivos parâmetros entre parênteses. Por exemplo. quando a adição da função é chamado. mas nunca as próprias variáveis. o valor de suas variáveis locais um e b se 5 e 3 respectivamente. a função printmessage poderia ter sido declarada como: 1 void printmessage ( void ) { 2 printf ("Eu sou uma função!"). 3 } 4 Embora seja opcional para especificar void na lista de parâmetros. Até agora. Esse comercial é o que especifica que os seus argumentos correspondentes devem ser passados por referência em vez de por valor . y e z ) e qualquer mudança que fazemos em um dentro da função afetam o valor de x fora dela. int b. Para esse efeito. } int main ( ) { int x = 1. Passagem por referência é também uma forma eficaz de permitir que uma função para retornar mais de um . mas uma cópia de seus valores em vez e. a saída na tela do nosso programa teria sido os valores de x . sem os sinais e comercial ( & ). que mostra os valores armazenados em x . É por isso que o nosso programa de saída. int c) ou seja. podemos usar argumentos passados por referência. podemos associar um . como na função de duplicar o seguinte exemplo: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 / / Passagem de parâmetros por referência # include <stdio.variável externa. } x = 2 A primeira coisa que deve chamar a atenção é que na declaração de duplicar o tipo de cada parâmetro foi seguido por um sinal de E comercial ( & ). e mesmo com c e z . y =".x. y = 3. return 0. Quando uma variável é passada por referência que não estamos passando uma cópia do seu valor.y. b *= 2.". mas nós somos de alguma forma passar a variável-se para a função e qualquer modificação que podemos fazer para as variáveis locais terão um efeito em variáveis sua contraparte passados como argumentos no a chamada para a função. duplicado (x. b e c com os argumentos passados na chamada da função ( x . sem ter sido modificado. portanto. Qualquer mudança que fizermos em b afetará y . int & b. c *= 2. Para explicá-lo de outra forma.". z = 7. z = ". y e z após a chamada para duplicar . mostra os valores de todas as três variáveis principais duplicou. int & c) que havia declarado desta forma: void duplicado ( int a. z). y.h> void duplicado ( int & a. printf ("x =". int & b.z). não teríamos passado por referência as variáveis. Se. y e z . ao declarar a função a seguir: void duplicado ( int & a. int & c) { a *= 2. Por exemplo. Esse valor será usado se o argumento correspondente é deixado em branco quando chamado para a função. } int main () { tribunal << divisão (12). } int main () { int x = 100. } 6 5 Como podemos ver no corpo do programa há duas chamadas para a função dividir . quando a função é chamada. mas a função de dividir permite até duas. No primeiro: divisão (12) temos apenas especificado um argumento. return 0. z).z). próxima =". aqui está uma função que retorna o número anterior e próximo do primeiro parâmetro passado. Quando declarar uma função que pode especificar um valor padrão para cada um dos últimos parâmetros. y. que termina com int b = 2 . mas se um valor é especificado o valor padrão é ignorado eo valor passado é usado. y. return 0. Por exemplo: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 / Default / valores em funções # include <stdio. printf ("\n").y. o valor padrão é usado. return (r). nós simplesmente temos que usar o operador de atribuição e um valor para os argumentos na declaração da função. . printf (divisão). int b = 2) { int r. int & prev. Se um valor para esse parâmetro não é passado. int & seguinte) { prev = x-1. Para fazer isso. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 / / Mais de um valor de retornar # include <stdio. prevnext (x.h> void prevnext ( int x. Portanto. r = a / b. e não apenas int b ). z. Assim. printf ("Anterior =". a função de dividir assumiu que o segundo parâmetro é 2 que é o que temos especificado acontecer se este parâmetro não foi passado (note a declaração de função. } Anteri Os valores padrão dos parâmetros. lado = x +1.".h> int divide ( int a.valor. o resultado dessa chamada de função é 6 ( 02/12 ). de modo padrão o valor para b ( int b = 2 ) é ignorado e b assume o valor passado como argumento. Assim. Pelo menos um dos seus parâmetros devem ter um tipo diferente. operar . então a função com o segundo protótipo é chamado. Em C + + duas funções diferentes podem ter o mesmo nome se seus tipos de parâmetro ou o número é diferente. mas um deles aceita dois parâmetros do tipo int eo outro aceita-los do tipo float . porque a função tem sido sobrecarregado . Essa função retorna o resultado da multiplicação de ambos os parâmetros. float n = 5. Este tem um comportamento diferente: ele divide um parâmetro pelo outro. examinando os tipos passados como argumentos quando a função é chamada. } float operar ( float a.Na segunda chamada: divisão (20. float b) { return (a / b). Por exemplo: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 / / Função sobrecarregada # include <stdio. printf ("\ n").h> int operar ( int a. n). m. y). Funções sobrecarregadas. Enquanto a segunda chamada passa dois argumentos do tipo float . portanto. Se for chamada com dois inteiros como argumentos a que chama a função que tem dois int parâmetros em seu protótipo e.0. a função com o primeiro protótipo é chamado. o comportamento de uma chamada para operar depende do tipo dos argumentos passados. Na primeira chamada para operar os dois argumentos passados são do tipo int . return 0. Isso significa que você pode dar o mesmo nome para mais de uma função. } int main () { int x = 5. que é 4 . O compilador sabe qual é a chamada em cada caso. int b) { return (a * b). y = 2. tornando o resultado retornado igual a cinco ( 20 / 4 ). O inline especificador indica ao compilador que a substituição inline é o preferido para a função chamada de mecanismo usual para uma função específica. pintf ( "\ n"). caso tenha um número diferente de parâmetros ou tipos diferentes de seus parâmetros. operar (x. Observe que uma função não pode ser sobrecarregado apenas pelo seu tipo de retorno. mas é usada para sugerir ao compilador que o código gerado pelo corpo da função é inserido em cada ponto da função . se for chamado com dois carros alegóricos será chamada para aquele que tem dois float parâmetros em seu protótipo. m = 2. } 10 2 Neste caso. funções embutidas. nós definimos duas funções com o mesmo nome. operar (. Isso não muda o comportamento de uma função em si.4) Existem dois parâmetros.0. nós temos definidas todas as funções antes da primeira aparição de chamadas a elas no códigofonte. Declarando funções. somente na sua declaração. Recursividade é a propriedade que têm funções a ser chamado por eles mesmos."! =". Recursividade.. .. return 0. como a classificação ou calcular o fatorial de números. printf (número.) {instruções . 5! (Fatorial de 5) seria: 5! = 5 * 4 * 3 * 2 * 1 = 120 e uma função recursiva para calcular isso em C + + pode ser: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 / Calculadora fatorial # include <stdio. printf ("Digite um número:"). que geralmente envolve uma sobrecarga adicional em tempo de funcionamento. mas apenas se o argumento passado foi maior que 1. A maioria dos compiladores já otimizar o código para gerar funções inline quando for mais conveniente. pois caso contrário a função irá executar uma recursiva loop infinito em que uma vez chegou a 0 que vai continuar se multiplicando por todos os números negativos ( provavelmente provocando um erro de estouro de pilha em tempo de execução).. Este especificador indica apenas o compilador que a linha é o preferido para essa função. } ea chamada é como a chamada para qualquer outra função. devido ao tipo de dados que usamos em seu desenho ( longa ) para mais simplicidade. em vez de ser inserido apenas uma vez e executar uma chamada normal para ele .é chamado. Esta função tem uma limitação. else return 1. scanf ("%d". } int main () { long numero. Você não tem que incluir a linha de palavraschave ao chamar a função. dependendo do sistema de compilá-lo. Se você tentar repetir alguns dos exemplos das funções descritas até agora... O formato de sua declaração é a seguinte: nome do tipo embutido (argumentos . * 1 mais concretamente. É útil para muitas tarefas. fatorial (numero). Essas chamadas são geralmente em função principal que temos sempre à esquerda no final do códigofonte. antes de qualquer uma das outras funções que foram chamadas a partir de dentro dela. para obter o fatorial de um número (n!) a fórmula matemática seriam: n! * = N * (n-1) (n-2) * (n-3) . Até agora.&numero).h> long fatorial ( long a) { if (a> 1) return (a * fatorial (a-1)).. Por exemplo. Os resultados obtidos não serão válidos para valores muito maiores do que 10! ou 15!. } Por f Observe como na função fatorial incluímos uma chamada para si. mas colocando a funçãoprincipal . Sua forma é: nome do tipo (argument_type1. .). mas apenas os especificadores de tipo. as declarações de função que nas definições normais são delimitados por chaves {} ) e ao invés de que a declaração final de protótipo com um ponto e vírgula obrigatória ( . exceto que ele não inclui o corpo da função em si (ou seja. int ).. mas suficientemente significativo para o compilador para determinar o seu tipo de retorno e os tipos de seus parâmetros. declarando apenas um protótipo da função antes de ser usado.} Digite um número (0 para sair): 9 Número sair): 1030 Número é mesmo.} void mesmo ( int a) { se ((a% 2) == 0) cout << "O número é ainda. ímpares (i). Esta declaração é menor do que toda a definição. Digite um nú Este exemplo não é de fato um exemplo de eficiência. do {cout << "Digite um número (0 para sair) : " . mas utilizando apenas metade das linhas de código que foram usados neste exemplo. retornar 0. Mas há uma maneira alternativa para evitar escrever todo o código de uma função antes de poder ser utilizado em principal ou em alguma outra função. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 / / Declarando funções protótipos # include <iostream> usando namespace std. neste ponto você já pode fazer um programa com o mesmo resultado. Isto pode ser conseguido. cin>> i. primeiro int segundo). argument_type2.. enquanto (eu! = 0). int main () { int i. A enumeração parâmetro não precisa incluir os identificadores. De qualquer forma este exemplo ilustra como funciona a prototipagem. vazio estranho ( int a). ). 2 int protofunction ( int .} void ímpar ( int a) { se 2%)! = 0 <) cout <((a "Número é . impar \ n " . É idêntica a uma definição de função. neste exemplo . Além disso. A inclusão de um nome para cada parâmetro. De qualquer forma.você provavelmente irá obter erros de compilação. Por exemplo. em vez de toda a definição. incluindo um nome para cada variável faz com que o protótipo mais legível.} . como temos feito em todos os nossos exemplos. na definição da função é opcional na declaração do protótipo. Estou certo de que. mais estranho (a). A razão é que para ser capaz de chamar uma função que deve ter sido declarada em algum ponto antes do código. void mesmo ( int a)." \ n . outra coisa mesmo (a). podemos declarar uma função chamada protofunction com dois int parâmetros com qualquer uma das seguintes declarações: 1 int protofunction ( int . ). já que matrizes são blocos de memória não-dinâmico cujo tamanho deve ser determinado antes da execução. independentemente do seu comprimento. com um identificador exclusivo. usando uma matriz que pode armazenar 5 valores diferentes do mesmo tipo. deve ser uma constante de valor. por exemplo. a fim de declarar um array chamado Billy como o mostrado na figura acima. podemos guardar cinco valores do tipo int em um array sem ter que declarar 5 variáveis diferentes. no principal . especifica quantos desses elementos a matriz contém.. colocados em locais contíguos de memória que podem ser individualmente referenciados pela adição de um índice para um identificador exclusivo. Se nenhuma das duas funções. um erro de compilação que aconteceria. Uma declaração típica para um array em C + + é a seguinte: nome do tipo [elementos]. já que tanto estranho não seria visível do mesmo (porque ainda não tenha sido declarada). Matrizes Uma matriz é uma série de elementos do mesmo tipo. por exemplo. Portanto. o que é explicado mais tarde nesses tutoriais. que declara as funções no início de um programa. que agora está localizado onde algumas pessoas acham que ele seja um lugar mais lógico para o início de um programa: o início do código-fonte. que neste caso são valores inteiros do tipo int . int por exemplo.. tinha sido declarado anteriormente. um array deve ser declarado antes de ser usado. cada uma com um identificador diferente. NOTA : Os elementos de campo entre colchetes [] que representa o número de elementos do array vai realizar. Isso significa que. Em vez disso. Tendo o protótipo de todas as funções em conjunto no mesmo local no código-fonte é encontrada prática por alguns programadores. A fim de criar matrizes com comprimento variável de memória dinâmica é necessária.concreto a prototipagem de pelo menos uma das duas funções é necessário para compilar o código sem erros. é tão simples como: int billy [5]. float . Isso permite que essas funções devem ser utilizadas antes de serem definidas. 2 void mesmo ( int a). nome é um identificador válido e os elementos de campo (que é sempre entre colchetes [] ). Enfim. Por exemplo. a razão pela qual este programa precisa de pelo menos uma das funções deve ser declarada antes de ser definido é porque estranho existe uma chamada para mesmo e ainda há uma chamada para estranhos . e isso pode ser facilmente alcançado por todos os protótipos. . ou até mesmo não seria visível do estranho (pelo mesmo motivo) . As primeiras coisas que nós vemos é a declaração de funções estranhas e até mesmo : 1 void ímpar ( int a). Estes elementos são numerados de 0 a 4 vez em matrizes o primeiro índice é sempre 0 . Como uma variável normal. onde tipo é um tipo válido (como int . uma matriz contém 5 valores inteiros do tipo int chamado billy poderia ser representado assim: onde cada painel em branco representa um elemento da matriz. 40. podemos acessar o valor de qualquer dos seus elementos individualmente como se fosse uma variável normal. 2. quando se declarar uma matriz. poderíamos escrever: a = billy [2]. C + + permite a possibilidade de deixar os colchetes vazios [] . sendo capaz de ler e modificar seu valor. são automaticamente inicializados com seus valores padrão. por exemplo). por exemplo. já temos os 5 valores de inicialização. colocando os valores em chaves {} . Neste caso. Em qualquer ponto de um programa em que uma matriz é visível. o nome que podemos usar para se referir a cada elemento é o seguinte: Por exemplo. os seus elementos não será inicializada com qualquer valor. 12071}. 77. 40. por padrão. isto significa que são preenchidos com zeros. 12071}. 2. Acessando os valores de uma matriz. para armazenar o valor 75 no terceiro elemento de billy . que para todos os tipos fundamentais. 77. Quando um arquivo de inicialização de valores está prevista uma matriz. um para cada elemento. Os elementos das matrizes globais e estáticos.Inicializando arrays. para passar o valor do terceiro elemento de billy para uma variável chamada um . Ao declarar uma matriz regular de âmbito local (dentro de uma função. o local eo global. Por exemplo. nós poderíamos escrever a seguinte instrução: billy [2] = 75. temos a possibilidade de atribuir valores iniciais para cada um dos seus elementos. Em ambos os casos. O formato é tão simples como: nome [índice] Seguindo os exemplos anteriores em que billy tinha 5 elementos e cada um desses elementos foi do tipo int . e. . por outro lado. Por exemplo: int billy [5] = {16. Após esta declaração. se não especifique o contrário. o compilador irá assumir uma dimensão para a matriz que corresponde ao número de valores compreendidos entre chaves {} : int Billy [] = {16. no exemplo da matriz billy temos declarou que tem 5 elementos e na lista de valores iniciais dentro de chaves {} temos especificadas 5 valores. a matriz billy seria 5 ints tempo. assim que seu conteúdo será indeterminado até que nós guardamos algum valor em si. Esta declaração teria criado uma matriz assim: A quantidade de valores entre chaves {} não deve ser maior que o número de elementos que declarar para a matriz entre colchetes [] . como uma variável do tipo int . . a expressão billy [2] é para todos os efeitos. Neste ponto é importante ser capaz de distinguir claramente entre os dois usos que colchetes ] [ têm relacionado a matrizes. o terceiro é billy [2] . portanto. Se você ler cuidadosamente. Isso pode criar problemas. ea segunda é especificar os índices para os elementos de matriz de concreto. o seu último elemento é billy [4] . 12071}. você verá que um especificador de tipo sempre precede uma declaração de variável ou matriz. A razão para isso é permitido será vista mais adiante quando começarmos a usar ponteiros. uma vez que o primeiro é billy [0] .Portanto. int Billy [] = {16. / / declaração de uma nova matriz / / acesso a um elemento da matriz. uma matriz bidimensional pode ser imaginada como uma tabela bidimensional feita de elementos. retornar 0. Por esta mesma razão. billy [billy [a]] = billy [2] + 5. Observe que o terceiro elemento de billy é especificado billy [2] . uma vez que o acesso fora do alcance elementos não causar erros de compilação. todos eles de um mesmo tipo de dados uniforme. int main () { para (n = 0. int .} cout <<resultado. Eles executam duas tarefas diferentes: uma é para especificar o tamanho das matrizes que tenham sido declarados. Em C + + é sintaticamente corretas para exceder o intervalo válido de índices para uma matriz. 77. superior ao tamanho da matriz. Por exemplo. n + +) {result + = billy [n]. 1 int billy [5].} 12206 Arrays multidimensionais Matrizes multidimensionais podem ser descritas como "matrizes de matrizes". Não confundir estes dois usos possíveis dos suportes [] com matrizes. n < 5. 2 3 4 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 / / Exemplo arrays # include <iostream> usando namespace std. billy [a] = 75. embora nunca precede um acesso. billy b = [a dois]. se escrevermos billy [5]. 2 billy [2] = 75. Algumas outras operações válidas com matrizes: 1 billy [0] = a. mas pode causar erros de execução. portanto. 2. Portanto. estaríamos acessando o sexto elemento de billy e. 40. o resultado n = 0. o segundo é billy [1] e. 2 int jimmy [15]. Matrizes multidimensionais não são limitadas a dois índices (ou seja. mas ambos atribuir valores para o bloco de memória chamado Jimmy. Por exemplo: char século [100] [365] [24] [60] [60]. essa declaração iria consumir mais de 3 gigabytes de memória! Arrays multidimensionais são apenas uma abstração para os programadores. largura <m. mais de 3 mil caracteres. largura (n = 0. com matrizes multidimensionais o compilador lembra a profundidade de cada dimensão imaginária para nós. int n. ou seja. altura <n. Eles podem conter índices que forem necessárias. a forma para fazer referência ao segundo elemento verticalmente eo quarto horizontalmente em uma expressão seria: jimmy [1] [3] (Lembre-se que os índices de matriz sempre começar por zero). n + +) para (m = 0. da seguinte forma: .} <m. m + +) {jimmy [largura * n + m] = (n +1) * return 0. com ambos exactamente o mesmo resultado. int main () {for [largura * altura]. duas dimensões).} Nenhum dos dois códigos-fonte acima produz nenhuma saída na tela. n. altura <n. Mas cuidado! A quantidade de memória necessária para uma matriz aumenta rapidamente com cada dimensão.} return 0. Tomemos como exemplo estes dois pedaços de código. m + + ) {jimmy [n] [m] = (n +1) * (m +1). m. int m. A forma de declarar essa matriz em C + + seria: int jimmy [3] [5]. declara uma matriz com um char elemento para cada segundo de um século. e. uma vez que podemos obter os mesmos resultados com uma matriz simples simplesmente colocando um fator entre os índices: 1 int jimmy [3] [5]. Então.jimmy representa uma matriz bidimensional de 3 por 5 elementos do tipo int . / / é equivalente a / / (3 * 5 = 15) Com a única diferença de que. int main () {for (n = 0. Um usa uma matriz bidimensional e outra usa uma matriz simples: matriz multidimensional matriz pseudo-multidimensional # Define largura 5 # define altura 3 jimmy int # Define largura 5 # define altura 3 int jimmy [altura] [LARGURA].} (m +1). por exemplo. n + +) para (m = 0. 6.} int main () { int firstArray [] = {5. 10.Temos usado "constantes definidas" ( # define ) para simplificar a possíveis modificações futuras do programa. Em C + + não é possível passar um bloco inteiro de memória em termos de valor como um parâmetro para uma função. isso tem quase o mesmo efeito e é uma operação muito mais rápida e mais eficiente. int tamanho) { para ( int n = 0. Matrizes como parâmetros Em algum momento podemos precisar de passar um array para uma função como um parâmetro. void PrintArray ( int arg []. PrintArray (secondArray. 15}. Na prática. Para aceitar matrizes como parâmetros a única coisa que temos que fazer quando se declara a função é especificar em seus parâmetros o tipo de elemento da matriz.} 5 10 . cout << "\ n" . 5). 8. mas estamos autorizados a passar o seu endereço. 4. um identificador e um par de suportes vazio [] . n + +) cout <<arg [n] << "" . comprimento <n. PrintArray (firstArray. Para passar para esta função uma matriz declarada como: int myarray [40]. Por exemplo. 10}. seria suficiente para escrever um convite como este: procedimento (myarray). int secondArray [] = {2. após a função: void procedimento ( int arg []) aceita um parâmetro do tipo "array de int "chamado arg . no caso em que decidimos ampliar a matriz para uma altura de 4 em vez dos 3 que poderia ser feito simplesmente mudando a linha: # Define altura 3 para: # Define altura 4 sem a necessidade de fazer outras modificações para o programa. Por exemplo. Aqui você tem um exemplo completo: 1 2 3 4 5 6 7 8 9 10 11 / / Arrays como parâmetros # include <iostream> usando namespace std. 3 ). retornar 0. já que ambos são menores do que 20 caracteres. porque as cordas estão em seqüências de caracteres de fato. Isto é assim porque o compilador deve ser capaz de determinar dentro da função que é a profundidade de cada dimensão adicional. nessa matriz. Em uma declaração de função também é possível incluir matrizes multidimensionais. é uma matriz que pode armazenar até 20 elementos do tipo char . simples ou multidimensionais. O formato de um parâmetro de matriz tridimensional é: base_type [] [profundidade] [profundidade] por exemplo. uma vez que a matriz de caracteres pode armazenar seqüências mais curtas do que o seu comprimento total. o padrão C + + Biblioteca implementa uma poderosa cadeia de classe. passadas como parâmetros da função são uma fonte muito comum de erros para programadores iniciantes. Por exemplo. em teoria. Seqüências de caracteres Como você já sabe. podemos armazenar as seqüências de caracteres até 20 caracteres.No entanto. zero) . Por exemplo. Eu recomendo a leitura do capítulo sobre ponteiros para uma melhor compreensão sobre como os arrays operar. enquanto os seguintes não são. Ele pode ser representado como: Portanto. a matriz seguinte: char jenny [20]. Portanto. jenny poderia armazenar em algum ponto em um programa a seqüência de "Olá" ou a seqüência de "Feliz Natal" . . podemos representá-los também como matrizes simples de char elementos. Por essa razão. Isso permite que o para loop que imprime a matriz para saber o intervalo de iterar na matriz passou sem sair do intervalo. independentemente do seu comprimento. que é muito útil para segurar e manipular cadeias de caracteres. Matrizes. cuja constante literal pode ser escrito como '\ 0' (barra invertida. nós incluímos um segundo parâmetro que diz a função do comprimento de cada array que passamos a ele como seu primeiro parâmetro. Mas também podemos armazenar seqüências mais curtas. um caractere especial é usado para sinalizar o fim da seqüência válida: o caractere nulo .12 13 14 15 16 17 18 Como você pode ver. o primeiro parâmetro ( int arg [] ) aceita qualquer matriz cujos elementos são do tipo int . uma função com uma matriz multidimensional como argumento poderia ser: void procedimento ( int myarray [] [3] [4]) Observe que os colchetes primeiro ] [ são deixadas em branco. Mas arrays de char elementos têm um método adicional para inicializar seus valores: usando literais string. Assumindo mystext é um [] char variáveis. '\ 0' }. 'o' . porque este tipo de nulo matrizes de caracteres terminadas são matrizes regulares que têm as mesmas restrições que nós temos com qualquer outra matriz. 'e' . Neste caso. '\ 0' }. citado cordas duplas ( " ) são constantes literais cujo tipo é na verdade um nulo encerrado matriz de caracteres.Nossa matriz de 20 elementos do tipo char . 2 char myword [] = "Olá" . que especifica o fim da seqüência e que . Nas expressões que usamos em alguns exemplos nos capítulos anteriores. expressões dentro de um código como: 1 mystext = "Olá" . Estes são especificados envolvendo o texto para tornar-se uma seqüência literal entre aspas (") por exemplo. chamada Jenny . de modo que não são capazes de copiar blocos de dados com uma operação de atribuição. Por exemplo. pode ser representado armazenar as seqüências de caracteres "Olá" e "Feliz Natal" como: Note como depois do conteúdo válido um caractere nulo ( '\ 0' ) foi incluída a fim de indicar o fim da seqüência. 'l' . Em ambos os casos. constantes que representam seqüências inteiras de personagens já apareceram várias vezes. já utilizado. no segundo caso. Por favor note que estamos falando de inicializar um array de caracteres no momento em que está sendo declarado. 'l' . Inicialização de seqüências de caracteres terminada por nulo Como arrays de caracteres são vetores comuns que seguem todas as regras mesmo. quando se utilizam aspas ( " ) é anexado automaticamente. Então strings literais entre aspas duplas sempre tem um caractere nulo ( '\ 0' ) automaticamente anexado ao final. tal como qualquer outra matriz: char myword [] = { 'H' . Portanto. podemos inicializar a matriz de char elementos chamados myword terminou com um nulo seqüência de caracteres de um destes dois métodos: 1 char myword [] = { 'H' .: "O resultado é:" é uma constante string literal que temos. se quisermos inicializar um array de caracteres com alguma seqüência pré-determinada de caracteres que podem fazê-lo. e não sobre a atribuição de valores a eles uma vez que já tinha sido declarado. De facto. mystext [] = "Olá" . 'l' . teria declarado um array de 6 elementos do tipo char inicializado com os personagens que formam a palavra "Olá" mais um personagem nulo '\ 0' no final. Os painéis em cor cinza representam charelementos com valores indeterminados. a matriz de caracteres myword é declarada com um tamanho de 6 elementos do tipo char : os 5 caracteres que compõem a palavra "Olá"mais um caractere nulo final ( '\ 0' ). 'e' . . provavelmente. 'o' . 'l' . literais string regulares deste tipo ( char [] ) e também pode ser usado na maioria dos casos. cout <<saudação <seunome <<< "!" . digite seu primeiro nome:" . cin>> seunome. A razão para isso pode se tornar mais compreensível uma vez que você sabe um pouco mais sobre ponteiros. nem como seria: mystext = { 'H' . 'o' . char saudação [] = "Olá" . digite s João! Como você pode ver. para que possam ser usadas enquanto tal em muitos procedimentos. para que eles possam ser usados diretamente para extrair seqüências de caracteres de cin ou para inseri-los em tribunal . Desta forma. 2 char myntcs [] = "algum texto" . 'e' . temos que speficify o tamanho da matriz: nos dois primeiros ( pergunta e saudação ). 'l' . retornar 0.} Por favor. cout <<questão. Enquanto que para seunome temos explicitamente especificado que tem um tamanho de 80 caracteres.2 que não seja válido. Por exemplo. enquanto a terceira foi deixado não inicializado. Os dois primeiros foram inicializados com constantes seqüência literal. nós simplesmente usamos a sua identificação sempre que queria referir-se à nossa variável. mystring = myntcs. . int main () { char pergunta [] = "Por favor. Em qualquer caso. temos declarou três arrays de char elementos. cin e corte apoio nulo seqüências denunciado como recipientes válida para seqüências de caracteres. 'l' . Na verdade. Usando null terminada seqüências de caracteres NULL-Terminated seqüência de caracteres são a maneira natural de tratar strings em C + +. não precisa se preocupar com a localização física dos nossos dados dentro da memória. Finalmente. '\ 0' }. Por exemplo: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 / / NULL-Terminated seqüência de caracteres # include <iostream> usando namespace std. 3 Ponteiros Já vimos como as variáveis são vistos como células de memória que pode ser acessada usando seus identificadores. desde então ele vai ficar claro que uma matriz é na verdade um ponteiro constante que aponta para um bloco de memória. as seqüências de caracteres armazenados em char arrays podem ser facilmente convertidos em cadeia de objetos usando apenas o operador de atribuição: 1 mystring string. o tamanho foi definido implicitamente pelo comprimento da constante literal foram inicializados com. char [seunome 80]. como temos feito muitas vezes por isso antes. cada célula pode ser facilmente localizado na memória. Desta forma. No entanto. Finalmente. Esta referência a uma variável podem ser obtidas pelo anterior o identificador de uma variável com um sinal de E comercial ( & ). 2 3 Os valores contidos em cada variável após a execução do presente. O endereço que localiza uma variável na memória é o que chamamos de referência para essa variável. temos atribuído o valor de 25 a andy (uma variável cujo endereço na memória que temos assumido como sendo 1776). as cópias de declaração de terceiros para Ted não o valor contido na andy . sabemos que vai ser mesmo entre células de 1775 e 1777. se nós estamos olhando para celular 1776. mas na realidade. a fim de ajudar a esclarecer alguns conceitos neste tutorial. não podemos saber antes de tempo de execução real do valor do endereço de uma variável terá na memória. Considere o seguinte fragmento de código: 1 andy = 25. de modo a. Isso seria atribuir a ted o endereço da variável andy . Nós geralmente não ativamente decidir o local exato da variável dentro do painel de células que nós imaginamos que a memória seja . o seu endereço na memória). cada célula tem o mesmo número que a anterior mais um.Felizmente. Esse número ( 1. são mostrados no diagrama abaixo: Primeiro. Esta é uma operação de atribuição padrão.776 ) é apenas uma suposição arbitrária estamos inventando agora. conhecido como operador de referência. mas uma referência a . Estas células de memória de um byte são numeradas de forma consecutiva. De agora em diante vamos supor que Andy é colocado durante a execução no endereço de memória 1776 . A segunda declaração copiado para fred o conteúdo da variável andy (que é 25). exatamente mil células após 776 e exatamente mil células antes de pilha 2776. porque ele tem um endereço único e todas as células de memória segue um padrão sucessivas. Por exemplo: ted = &andy. podemos estar interessados em conhecer o endereço onde a variável está sendo armazenado durante a execução. desde quando precede o nome da variável andy com o operador de referência ( & ) não estamos mais falando sobre o conteúdo da variável em si. ted = &andy. Por exemplo. a quantidade de memória necessária é atribuído por ele em uma posição específica na memória (o endereço de memória). essa é uma tarefa executada automaticamente pelo sistema operacional durante a execução. cada um do tamanho mínimo que computadores administrem (um byte). fred = andy. e que pode ser traduzido literalmente como "endereço". dentro de qualquer bloco de memória. mas sobre a sua referência (ou seja. Referência do operador (&) Assim que nós declaramos uma variável. em alguns casos. a fim de operar com posições relativas a ele.A memória do seu computador pode ser imaginado como uma sucessão de células de memória. Ponteiros são disse para "apontar para" a variável cuja referência que eles armazenam. já que Ted é 1776 . no exemplo anterior) é o que chamamos de ponteiro . / beth igual a) ted (1776 2 beth = * ted. enquanto * Ted (com um asterisco * antes do identificador) refere-se ao valor armazenado no endereço 1776 . que atua como operador dereference e que pode ser traduzido literalmente como "valor apontado por". de modo que já não estavam se referindo ao valor de Andy. se escrevermos: * Beth = ted. Uma variável referenciada com e pode ser dereferenced com * . Os ponteiros são um poderoso recurso muito da linguagem C + + que tem muitos usos na programação avançada. que neste caso é 25 . eo valor apontado pelo 1776 é 25. (Que poderíamos ler como: " Beth igual ao valor apontado por ted ") beth levaria o valor 25 . seu endereço. nós simplesmente temos que precedem o ponteiro identificador com um asterisco (*). 2 .776 .ele (isto é. Operador de referência (*) Acabamos de ver que uma variável que armazena uma referência a outra variável é chamado de ponteiro. ted = &andy. mas a sua referência (o seu endereço na memória). seguindo com os valores do exemplo anterior. O motivo é que nesta terceira operação de atribuição temos precedidas do identificador andy com o operador de referência ( & ). Usando um ponteiro. / beth igual ao valor apontado por ted (25) Observe a diferença entre os operadores de referência e dereference: y y E é o operador de referência e pode ser lido como "endereço de" * É o operador de dereferência e pode ser lido como "valor apontado por" Assim. Assim. vamos ver como esse tipo de variável é utilizada e declarada. que assumiram a 1776 ). A variável que armazena a referência a outra variável (como Ted . podemos acessar diretamente o valor armazenado na variável que ele aponta. Para fazer isso. Você deve diferenciar claramente que a expressão de Ted se refere ao valor 1. Anteriores foram realizados os seguintes operações de atribuição: 1 andy = 25. eles têm complementar (ou oposta) significados. Mais à frente. Observe a diferença de seleção incluindo ou não o operador dereference (Eu incluí um comentário explicativo de como cada uma dessas duas expressões pode ser lido): 1 beth = ted. é dito que eles têm diferentes tipos: int * . depois de tudo isso. Não é a mesma coisa para apontar para um char como para apontar para um int ou float . enquanto o endereço apontado por ted permanece inalterada a seguinte expressão também será verdadeiro: * Ted == andy Declarando variáveis de tipos de ponteiro Devido à capacidade de um ponteiro para se referem diretamente para o valor que ele aponta. O terceiro é um tanto óbvio. Então. onde tipo é o tipo de dados do valor que o ponteiro se destina a apontar. A declaração de ponteiros segue este formato: nome do tipo *. Cada um deles destina-se a apontar para um tipo de dados diferentes. Eles simplesmente são duas coisas diferentes representados com o mesmo sinal. char * e * float . pode ser lido como "valor apontado por" e. dependendo do tipo eles apontam. Por exemplo: 1 int * número. como acabamos de ver. os dados a que ponto a não ocupar o mesmo espaço nem são do mesmo tipo: o primeiro aponta para um int . Portanto. que retorna o endereço da variável andy . No entanto. . o valor apontado por ted é realmente 25 . considerando que a operação de cessão realizados em andy foi andy = 25 . 2 char caracter *. 3 float greatnumber *.Logo após essas duas afirmações. embora estas três variáveis exemplo são todos os ponteiros que ocupam o mesmo tamanho em memória. que assumiu que para ter um valor de 1776 . mas na verdade todos eles são ponteiros e todos eles vão ocupar o mesmo espaço na memória (o tamanho da memória de um ponteiro depende da plataforma onde o código está acontecendo para executar). todas das seguintes expressões daria certo como resultado: 1 andy == 25 & andy == 1776 1776 == * ted ted == 25 2 3 4 A primeira expressão é bastante clara. A quarta expressão usa o operador de dereferência ( * ) que. você também pode-se inferir que. Estes são três declarações de ponteiros. torna-se necessário especificar em sua declaração de que tipo de dados de um ponteiro que vai apontar. O segundo usa o operador de referência ( & ). já que a segunda expressão era verdade e da operação de cessão realizados em Ted foi ted = & Andy . e não deve ser confundido com o operador dereference que temos visto uma pouco mais cedo. mas que também é escrito com um asterisco ( * ). o segundo para um char eo último a uma bóia . Quero enfatizar que o sinal asterisco ( * ) que usamos quando declarar um ponteiro significa apenas que ele é um ponteiro (que faz parte do seu especificador composto tipo). Este tipo não é o tipo do ponteiro em si! mas o tipo de dados que o ponteiro aponta. Agora dê uma olhada neste código: 1 / / Meu primeiro ponteiro 2 # include <iostream> usando namespace std. respectivamente. Outra coisa que pode chamar sua atenção é a linha: . / / valor apontado por p1 = 20 cout << "firstvalue é" <<firstvalue <<endl. / / valor apontado por p1 = 10 * * p2 = p1. mypointer = & secondValue. A fim de demonstrar que um ponteiro pode tomar vários valores diferentes no mesmo programa que eu tenho repetido o processo com secondValue e que mesmo ponteiro. * = 10. O significado de uma expressão usando o operador de dereferência ( * ) é muito diferente de um que não: Quando este operador precede o nome do ponteiro.} firstv Tenho incluído como um comentário em cada linha como o código pode ser lido: "comercial ( & ) como "endereço de" e um asterisco ( * ) como "valor apontado por". Este é o procedimento: Primeiro. / / p1 = endereço de firstvalue p2 = & secondValue. retornar 0. a expressão se refere ao valor que está sendo apontado. mypointer * = 20 6 "secondValue é" <<secondValue <<endl. / / p2 = endereço do secondValue * p1 = 10. Observe que há expressões com ponteiros p1 e p2 . / / valor apontado por p2 = valor apontado por p1 p1 = p2. 5 int mypointer *. refere-se para o valor do ponteiro em si (ou seja.3 4 int main () { int firstvalue. mypointer .} 8 9 10 11 12 13 14 15 16 17 Observe que. ao mesmo tempo quando um nome de ponteiro aparece sem este operador. int main () { int firstvalue = 5. temos atribuído como valor da mypointer uma referência para firstvalue usando o operador de referência ( & ). secondValue. embora nunca diretamente definir um valor para qualquer firstvalue ou secondValue . int * p1. * p2. tanto acabar com um valor definido indiretamente através do uso de mypointer . p1 = &firstvalue. 7 retornar 0. ambos com e sem operador dereference ( * ). / / p1 = p2 (valor do ponteiro é copiado) * p1 = 20. Aqui está um exemplo um pouco mais elaborada: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 / Mais ponteiros / # include <iostream> usando namespace std. secondValue = 15. o endereço do que o ponteiro está apontando). cout << "secondValue é" <<secondValue <<endl. mypointer = mypointer &firstvalue. todas as expressões que incluem ponteiros no exemplo a seguir são perfeitamente válidas: 1 2 3 4 5 6 7 8 9 / / Ponteiros mais # include <iostream> usando namespace std. Portanto. Mas repare que há um asterisco (*) para cada ponteiro. que é um ponteiro comum. como um ponteiro é equivalente para o endereço do primeiro elemento que chama a atenção para. devido às relações de precedência. ao contrário p . Porque os números é um array. Portanto. * p = 10. Isto é devido às regras de precedência do operador. p + p +. mas p2 teria tipo int (espaços não importa a todos para essa finalidade). retornar 0. * p = 30.} .int * p1. p e números seriam equivalentes e teria as mesmas propriedades. e não podemos atribuir valores para constantes. Ponteiros e matrizes O conceito de matriz é muito ligado ao do ponteiro. números é uma matriz e uma matriz pode ser considerado um ponteiro constante . * p = 40 números. * (p 4) = 50. n <5. o identificador de uma matriz é equivalente para o endereço do seu primeiro elemento. Este declara dois ponteiros usado no exemplo anterior. p2. Mas de qualquer maneira. a atribuição a seguir não seriam válidas: números = p. Por exemplo. * p = & números [2] . A operação de atribuição a seguir seria válido: p = números. int main () { int números [5]. p = número + 3. para ( int n = 0. Se tivéssemos escrito: int * p1. * p2. Devido às características de variáveis. n + +) cout <<números [n] << ". = 20. basta lembrar que você tem que colocar um asterisco por ponteiro é suficiente para a maioria dos usuários do ponteiro. o tipo para a segunda variável declarada em que a linha teria sido int (e não int * )." . de modo que ambos têm o tipo int * (ponteiro para int ). A única diferença é que nós podemos mudar o valor do ponteiro p por outro. 2 int * p. p1 teria certamente int * tipo. então na verdade eles são o mesmo conceito. Depois disso. Caso contrário. por isso funciona como um ponteiro constante. p = números. supondo que estas duas declarações: 1 int números [20]. Na verdade. int * p. ao passo que os números vão sempre apontar para o primeiro dos 20 elementos do tipo int com o qual ele foi definido. ou se um é uma matriz. tommy * = &number.Eles dereference a variável seguem apenas como * faz. devemos tomar cuidado para não confundir com o código anterior: 1 int número. a gente pode querer especificar explicitamente qual a variável que queremos que eles apontam para: 1 int número. se você pensar sobre isso. / / a [deslocamento de 5] = 0 / / apontada por (a 5) = 0 Estas duas expressões são equivalentes e válidas tanto se um é um ponteiro. no momento de declarar um ponteiro. 2 * (a 5) = 0. 3 Quando a inicialização do ponteiro tem lugar sempre estamos atribuindo o valor de referência para onde o ponteiro aponta ( Tommy ). mas também adicionar o número entre parênteses para o endereço a ser dereferenced. 2 int tommy * = &number. Assim. Como no caso de matrizes. 2 int * tommy. O comportamento deste código é equivalente a: 1 int número. inicialização do ponteiro Ao declarar ponteiros. tommy = &number. Bem. Você deve considerar que. 3 que está incorreto. Por exemplo: 1 um [5] = 0. 2 int * tommy. . o asterisco (* ) indica apenas que é um ponteiro. o compilador permite que o caso especial que queremos para inicializar o conteúdo ao qual o ponteiro aponta com constantes no mesmo instante. o ponteiro é declarado: char * terry = "Olá" . Lembre-se. e mesmo assim não teria muito sentido neste caso. ele não é o operador de dereferência (embora ambos usam o mesmo sinal: *). nunca o valor que está sendo apontado ( * tommy ).10 11 12 13 14 15 16 17 No capítulo sobre matrizes usamos colchetes ( [] ) várias vezes a fim de especificar o índice de um elemento da matriz a que queria referir. estes assinam operadores colchete [] também são uma dereference operador conhecido como operador de offset . são duas funções diferentes de um sinal. embora na verdade 1702 é o endereço de ambos. Quando vimos os diferentes tipos de dados fundamentais. Suponha que nós definimos três ponteiros neste compilador: 1 char MyChar *. . ao adicionar um a um ponteiro que estamos fazendo com que ela aponte para o elemento seguinte do mesmo tipo com o qual ele foi definido e. myshort conteria o valor 2002 . myshort + +. podemos representar a declaração anterior como: É importante indicar que terry contém o valor de 1702. e não "h" . ou mais do que outros na memória. Então. portanto. aritmética de ponteiro Para realizar operações aritméticas em ponteiros é um pouco diferente do que para conduzi-los em tipos de dados inteiros regular. como você pode esperar. o espaço de memória é reservada para conter "Olá" e. Por exemplo.Neste caso. Por exemplo. 2000 e 3000 . e que nós sabemos que eles apontam para posições de memória 1000 . deve conter o valor de 1001 . 2 curto myshort *. podemos acessar o quinto elemento do array com qualquer uma dessas duas expressões: 1 * Terry (terry 4) [4] 2 Ambas as expressões têm um valor de 'o' (o quinto elemento da matriz). vimos que alguns ocupam menos espaço. 2 3 MyChar . O ponteiro terry aponta para uma seqüência de caracteres e pode ser lido como se fosse uma matriz (lembrese que uma matriz é igual a um ponteiro constante). 3 longo mylong *. A razão é que. nem "Olá" . apesar de terem sido aumentado cada uma só vez. Mas a adição e subtração têm um comportamento diferente com os ponteiros de acordo com o tamanho do tipo de dados para que eles apontam. Para começar. short ocupa 2 bytes etempo leva 4. se escrever: 1 MyChar + +. Se imaginarmos que "Olá" é armazenado na memória locais que começam em endereços 1702. o tamanho em bytes do tipo apontado é adicionado ao ponteiro. Mas não tão obviamente. e mylong conteria 3004 . os outros não fazem sentido no mundo dos ponteiros. em seguida. respectivamente. a única adição e subtração são operações de poder ser realizado com eles. char tem 1 byte. um ponteiro para o primeiro caractere do bloco de memória é atribuído a Terry . mylong + +. vamos supor que em um dado compilador para uma máquina específica. Porque + + tem uma precedência maior do que * . myshort myshort = + 1. Portanto. 2 3 . Ele iria acontecer exactamente o mesmo se escrever: 1 MyChar MyChar = + 1. mas porque + + é usado como postfix toda a expressão é avaliada como o valor apontado pela referência original (o endereço do ponteiro apontado para antes de ser aumentada).Isto é aplicável tanto ao somar e subtrair qualquer número para um ponteiro. O valor de p (o próprio ponteiro) não seria alterada (o que está sendo modificada é o que está sendo apontada por este ponteiro). q + +. esta expressão é equivalente a * (p + +) . Observe a diferença com: (* P) + + Aqui. mylong mylong = + 1. + + p. Se escrevermos: * P = q + + + + *. ambos p e q são aumentados. mas ambos têm um comportamento especial quando usada como sufixo (a expressão é avaliada com o valor que tinha antes de ser aumentada) . o que faz é aumentar o valor de p (de modo que agora aponta para o elemento seguinte). Portanto. Seria equivalente a: 1 * P = q *. 2 3 Ambos aumentam o ( + + ) e diminuir ( . a expressão teria sido avaliado como o valor apontado por p aumentado em um.) Os operadores têm precedência de operador maior do que o operador de dereferência ( * ). mas porque os operadores aumento ( + + ) são utilizados como postfix e não o prefixo. E então ambos serão aumentados. o valor atribuído à p * é * q antes de ambos p e q são aumentadas . a seguinte expressão pode levar à confusão: * P + + Porque + + tem maior precedência que * . nula ponteiros para os ponteiros que apontam para um valor que não tem nenhum tipo (e. void aumento ( void * dados. a fim de evitar resultados inesperados e para dar maior legibilidade ao código. que pode ser utilizado em três diferentes níveis de indireção. b &a.} y. só precisamos adicionar um asterisco ( * ) para cada nível de referência nas suas declarações: 1 char : um 2 char * b. + + (* PChar). Ponteiros para ponteiros C + + permite o uso de ponteiros que apontam para ponteiros. anular representa a ausência do tipo. Isso permite que os ponteiros void para apontar para qualquer tipo de dados. 4 5 6 Isto. 8092 e 10502 . pode ser representado como: O valor de cada variável é escrito dentro de cada célula. que estes. as células estão sob seus respectivos endereços na memória." <<b <<endl. int b = 1602. e por isso sempre teremos de lançar o endereço do ponteiro nulo para algum tipo outro ponteiro que aponta para um tipo de dados concretos antes de dereferencing-lo. A fim de fazer isso. a partir de um valor inteiro ou um float para uma seqüência de caracteres. supondo que a memória de locais escolhidos aleatoriamente para cada variável de 7230 . eles têm uma grande limitação: os dados apontados por eles não podem ser directamente dereferenced (que é lógico. cout <<a << ". aumento (& b. c = &b. 3 char ** c. também uma duração indeterminada e propriedades dereference indeterminado). a = 'z' . 16 . portanto. cada uma delas corresponderia a um valor diferente: y y y c tem o tipo char ** e um valor de 8092 C * tem um tipo char * e um valor de 7230 ** C tem o tipo char e um valor de 'z' ponteiros void O vazio tipo de ponteiro é um tipo especial de ponteiro. apontam para dados (ou até mesmo para outros ponteiros). pint = ( int *) Dados. A novidade neste exemplo é variável c .}} int main () { char a = 'x' . Mas em troca. Em C + +. sizeof (a)). sizeof (b)). int psize) { se (psize == sizeof ( char )) { char * pchar. aumento (& a. retornar 0.Como sempre. Um de seus usos podem ser para passar parâmetros genéricos para uma função: 1 2 3 4 5 6 7 8 9 10 11 / / Increaser # include <iostream> usando namespace std. + + (* litro). eu recomendo que você use parênteses () .} mais se (psize == sizeof ( int )) { int pint *. pchar = ( char *) Dados. por sua vez. pois não temos nenhum tipo de dereference a). desde que estes não podem ser passados dereferenced.} 8 . int y. Este valor é o resultado de tipo-casting o valor inteiro zero para qualquer tipo de ponteiro. a adição). retorno (g). Assim. p = 0.} int operação ( int x. int b) { retorno (a + b). O uso típico deste é para passar uma função como um argumento para outra função. y).12 13 14 15 16 17 18 19 20 21 sizeof é um operador integrado na linguagem C + + que retorna o tamanho em bytes do seu parâmetro. 1 int * p.} int subtração ( int a. Para tipos de dados dinâmicos não esse valor é uma constante. int b) { retorno (ab). int ) = subtração. int (* functocall) ( int . de menos).} int {main () int m. Para declarar um ponteiro para uma função que temos que declará-la como o protótipo da função. int soma ( int a. int )) { int g. por exemplo. exceto que o nome da função é incluída entre parênteses () e um asterisco ( * ) é inserido antes do nome: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 / / Ponteiro para funções # include <iostream> usando namespace std. g = (* functocall) (x. porque char é um tipo byte. Ponteiros para funções C + + permite operações com ponteiros para funções. n = operação (20. 5. enquanto um ponteiro void é um tipo especial de ponteiro que pode apontar para algum lugar sem um tipo específico. int (* menos) ( int . ponteiro nulo Um ponteiro nulo é um ponteiro regular de qualquer tipo de ponteiro que tem um valor especial que indica que ele não está apontando para qualquer referência válida ou endereço de memória. m operação = (7. retornar 0. n. 2 / p tem um valor de ponteiro nulo Não confundir com ponteiros nulos ponteiros void. sizeof (char) é um . m. Uma se refere ao valor armazenado no ponteiro propriamente dito e outro para o tipo de dados que ele aponta. Um ponteiro nulo é um valor que pode assumir qualquer ponteiro para representar que ele está apontando para "lugar nenhum". cout <<n. Ambos são equivalentes. Neste caso. A dinâmica de memória solicitada pelo nosso programa é atribuído pelo sistema a partir da pilha de . agora. int ) = subtração. O primeiro elemento apontado por Bobby pode ser acessado tanto com a expressão Bobby [0] ou a expressão * Bobby . como acabamos de fazer. que é atribuído a Bobby . tudo em uma única linha: int (* menos) ( int . antes de sua execução. novo é seguido por um tipo de dados e. o sistema atribui dinamicamente espaço para cinco elementos do tipo int e retorna um ponteiro para o primeiro elemento da sequência. se uma seqüência de mais de um elemento é necessário. Memória dinâmica Até agora. tendo o tamanho de todos eles a ser determinado no código-fonte. só temos tido tanta memória disponível como nós declaradas para nossas variáveis. Bobby = novo 2 int [5]. Portanto. em todos os nossos programas. o que limita seu tamanho para o que nós decidimos no momento da concepção do programa. como foi explicado na seção sobre ponteiros. Por exemplo: 1 int * bobby.26 27 No exemplo. a menos é um ponteiro para uma função que tem dois parâmetros do tipo int . bobby aponta para um bloco válido de memória com espaço para cinco elementos do tipo int . O segundo elemento pode ser acessado tanto com Bobby [1] ou * (bobby +1) e assim por diante . onde number_of_elements é um valor inteiro que representa a quantidade destes. usamos o operador de novo . Ela retorna um ponteiro para o início do novo bloco de memória alocada. A resposta é a memória dinâmica . O segundo é usado para atribuir um bloco (uma matriz) de elementos de tipo tipo . Ele é imediatamente atribuído a apontar para a função de subtração . A diferença mais importante é que o tamanho de uma matriz tem que ser um valor constante. para a qual C + + integra os operadores novos e excluir . Os operadores [e novos] Para solicitar a memória dinâmica. no caso em que precisamos de alguma entrada do usuário para determinar a quantidade necessária de espaço de memória. Sua forma é: ponteiro = novo tipo ponteiro = [number_of_elements] novo tipo A primeira expressão é usada para alocar memória para conter um único elemento do tipo do tipo .. o número destes entre colchetes [] . e se precisamos de uma quantidade variável de memória que só pode ser determinada durante a execução? Por exemplo. enquanto que a alocação de memória dinâmica permite atribuir memória durante o execução do programa (runtime) usando qualquer variável ou um valor constante de seu tamanho. Você pode estar se perguntando a diferença entre declarar uma matriz normal e atribuição dinâmica de memória para um ponteiro. Mas.. antes da execução do programa. / / se não uma exceção é lançada O outro método é conhecido como nothrow . Este método pode ser especificado usando um objeto especial chamado nothrow . Bobby = nova (nothrow) int [5]. eo programa continua sua execução . cujo formato é: 1 excluir ponteiro. devido à sua simplicidade. ou um ponteiro nulo (no caso de um ponteiro nulo. Mas. declarado no cabeçalho <new> . e é o utilizado em uma declaração como: bobby = novo int [5]. como argumento para nova : bobby = nova (nothrow) int [5]. o ponteiro retornado por novos é um ponteiro nulo. se a atribuição deste bloco de memória falha. é importante ter algum mecanismo para verificar se o nosso pedido para alocar a memória foi bem sucedida ou não. Operadores de apagar e delete [] Desde a necessidade de memória dinâmica é geralmente limitada a momentos específicos dentro de um programa. ao invés de lançar um bad_alloc exceção ou encerrar o programa. eo que acontece quando ele é usado é que. se essa exceção é lançada e não é tratado por um manipulador específico. por agora você deve saber que. onde o método de exceção é geralmente preferido. O valor passado como argumento para excluir deve ser um ponteiro para um bloco de memória previamente alocado com nova . e pode ser esgotado. excluir não produz nenhum efeito). a memória do computador é um recurso limitado. De qualquer forma esse método pode se tornar tedioso para projetos maiores. 3 }. a execução do programa é encerrado. O método de exceção será explicado em detalhe mais tarde neste tutorial. Usando este método uma exceção do tipo bad_alloc é acionada quando a alocação falhar. C + + fornece dois métodos padrão para verificar se a alocação foi bem sucedida: Uma delas é o tratamento de exceções. Este é o objetivo do operador delete . a falha pode ser detectada verificando se bobby teve um valor de ponteiro nulo: 1 int * bobby. mas vou usá-lo nos nossos exemplos.memória. 2 excluir ponteiro] [. Portanto. As exceções são a C + + poderoso recurso explicado mais tarde nesses tutoriais. 2 se (bobby == 0) { / atribuição de erro de memória /. . uma vez que não é mais necessária que deve ser liberada para que a memória se torna disponível novamente para outras solicitações de memória dinâmica. A primeira expressão deve ser usada para apagar a memória alocada para um único elemento. Tomar medidas. 4 5 Este nothrow método requer mais trabalho do que o método de exceção. uma vez que o valor retornado deve ser verificada após cada alocação de memória. No entanto. Este método de exceção é o método padrão usado pelo novo. eo segundo para a memória alocada para arrays de elementos. Neste caso. quando uma alocação de memória falha. Dinâmica de memória em ANSI-C Operadores de novo e apagar são exclusivos do C + +. e não um valor constante: p = nova (nothrow) int [i]. cin>> p [n]. excluir [] p. n <i. você deve sempre verificar o valor do ponteiro retornado. que também estão disponíveis em C + +. para (n = 0. Por exemplo. use o método de exceção. Os blocos de memória alocada por essas funções não são necessariamente compatíveis com os retornados pelo novo. que se não for tratado termina o programa. n + +) {cout << "Digite o número:" . É uma boa prática de sempre verificar se um bloco de memória dinâmica com êxito foi atribuído. Portanto. Lembre-se que no caso em que tentou alocar a memória. Eles não estão disponíveis na linguagem C. int * p. quando eu tentei dar um valor de 1000 milhões para o "Quantos números" pergunta. se você usar o nothrow método. . mesmo se você não tratar a exceção. sem especificar o parâmetro nothrow na nova expressão. Mas usando a linguagem C pura e sua biblioteca. por isso cada um deve ser manipulada com seu próprio conjunto de funções ou operadores.} cout << "Você digitou:" . cout << "Quantos números que você gostaria de escrever?" . sem causar resultados inesperados de continuar a execução de um código que pressupõe um bloco de memória de ter sido atribuída. Desta forma. quando na verdade ele não tem. o programa será encerrado neste ponto. n <i. realloc e livre .} Quantos números que você gostaria número: 8 Digite o número: 32 Voc Observe como o valor entre parêntesis na nova declaração é um valor variável digitada pelo usuário ( i ). meu sistema não pôde alocar a memória tanto para o programa e recebi a mensagem de texto que preparou para este caso ( erro: memória não pôde ser atribuídos ). Mas o usuário poderia ter entrado um valor para i tão grande que nosso sistema não pode lidar com isso. incluindo o <cstdlib> arquivo de cabeçalho (vejacstdlib para mais informações). Caso contrário. a memória dinâmica também pode ser usado com as funções malloc .1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 / / Rememb-o-matic <iostream> # include # include <new> usando namespace std. n + +) cout <<p [n] << "" . int main () { int n i. outra { para (n = 0. calloc . uma exceção seria lançada. cin>> i.} retornar 0. p = nova (nothrow) int [i]. se (p == 0) cout << "Erro: A memória não pode ser atribuída" . Por exemplo. 2 float preço. cada um de um tipo diferente fundamental. maçã produto. tal como temos feito com maçã . Uma vez declarada. Temos.} maçã. object_name pode ser um conjunto de identificadores válidos para objetos que tenham o tipo desta estrutura. banana e melão no momento em que definir o tipo de estrutura de dados desta forma: 1 struct produto { int peso. Dentro de chaves {} existe uma lista com os membros de dados. com diferentes tipos de dados. podem ter diferentes tipos e tamanhos diferentes. banana e melão como teria feito com qualquer tipo de dados fundamental. um novo tipo de identificador especificado como structure_name é criado e pode ser usado no resto do programa como se fosse qualquer outro tipo. Podemos instanciar muitos objetos (variáveis. cada um é especificado com um tipo e um identificador válido como o seu nome. char ou short e desse ponto em que somos capazes de declarar objetos (variáveis) desse novo tipo de composto. ou seja. usou este nome do tipo de estrutura ( produto ) para declarar três objetos desse tipo: maçã . como maçã . . As estruturas de dados Uma estrutura de dados é um grupo de elementos de dados agrupados sob um nome. Por exemplo: 1 struct produto { int peso. melão. 3 4 É importante diferenciar claramente entre o que é o nome do tipo de estrutura. onde structure_name é um nome para o tipo de estrutura. member_type3 member_name3.}. em seguida. Logo no final da struct declaração.Estruturas de Dados Nós já aprendemos como os grupos de dados seqüenciais podem ser usados em C + +. melão. podemos usar o campo opcional object_name diretamente declarar objetos do tipo de estrutura. conhecidos como membros . mas conjuntos de elementos diferentes. podemos também declarar a estrutura de objetos de maçã . pois em muitas ocasiões que queremos loja não são seqüências simples de todos os elementos do mesmo tipo de dados. Mas isso é um pouco restritivo. banana. A primeira coisa que temos que saber é que uma estrutura de dados cria um novo tipo: Quando uma estrutura de dados é declarado. As estruturas de dados são declarados em C + + usando a seguinte sintaxe: struct {structure_name member_type1 member_name1. e antes do ponto e vírgula final. member_type2 member_name2. . produto banana. banana e melão ) de um tipo de estrutura simples ( produto ). . produto tornou-se um tipo novo nome válido como os fundamentais int . Object_names}. Estes elementos. 3 4 5 6 7 Temos primeiro declarado um tipo de estrutura chamado produto com dois membros: o peso eo preço . eo que é um objeto (variável) que tem esse tipo de estrutura. 2 float preço. banana e melão . getline (cin . mine.price 2 3 4 5 6 Cada um deles tem o tipo de dados correspondente ao membro que se referirem: apple.weight apple. enquanto apple. onde você pode ver como um tipo de estrutura pode ser usado da mesma forma como tipos fundamentais: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 / / Exemplo sobre as estruturas <iostream> # include # include <string> # include <sstream> usando namespace std. mine. cout << "Digit getline (cin. Vamos ver um exemplo real. mystr (stringstream)> yours.} meu. mostrafilme (seu).year << ") \ n" ..price melon. yours. cout << "Digite o ano:" . cout << "(" <<movie. seu. void (movies_t) filme. mystr). retorno 0. Por exemplo. ) inserido entre o nome do objeto eo nome do membro.} O exemplo mostra como podemos usar os membros de um objeto como variáveis regular.title. struct .Uma vez que tenhamos declarado nossos três objetos de um tipo de estrutura determinada ( maçã .weight banana.price são do tipo float . cout <<) (mostrafilme mina "E o seu é: \ n" . Por exemplo.price melon.weight e melon. poderíamos operar com qualquer um desses elementos como se fossem variáveis padrão de seus respectivos tipos: 1 apple.price .price e melon.year = 1968. o .weight banana.weight são do tipo int . Para isso.title). movies_t seqüência {title int ano. "Meu filme favorito é: \ n" . banana e melão ).weight . podemos atuar diretamente com os seus membros. mostrafilme int main () { mystr string.} void mostrafilme (movies_t filme) {tribunal <<movie.title = "2001 Uma Odisséia no Espaço" . usamos um ponto ( . banana. banana. especialmente se considerarmos a possibilidade de construção de matrizes de um deles: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 / / Matriz de estruturas <iostream> # include # include <string> # include <sstream> usando namespace std. cout << "(" <<movie.year é uma variável válida do tipo int . nós passamos a eles a função mostrafilme como teria feito com variáveis regular. movies_t seqüência {title int ano.title. retornar 0. para (n = 0.}. (cin. e mine. N_MOVIES <n.} void movies_t (filme mostrafilme) {cout <<movie. para (n = 0. Portanto. título). n <N_MOVIES. os filmes "Enter ano: " .} cout << "\ nVocê entrou com estes filmes: \ n" . void mostrafilme (filme movies_t). Estruturas de dados são um recurso que pode ser usado para representar bancos de dados. cout <<(cin. stringstream> (mystr)> [filmes n]. int main () mystr {string.year << ") \ n" . getline ano. # define N_MOVIES 3 struct . as estruturas podem ser apontados pelo seu próprio tipo de ponteiros: 1 struct . n + +) mostrafilme (filmes [n]). getline [n].title é uma variável válida do tipo string .} filmes [N_MOVIES]. Os objetos de minas e seu também podem ser tratados como variáveis do tipo válido movies_t . movies_t seqüência {title int ano. por exemplo. 2 3 4 5 6 7 .} Digit o tít (1999 Ponteiros para estruturas Como qualquer outro tipo. mystr). pmovie * movies_t. Amovie movies_t.membro yours. int n. n + +) {cout << "Digite o título:" . uma das vantagens mais importantes das estruturas de dados é que podemos fazer referência aos seus membros individualmente ou para toda a estrutura como um bloco com apenas um identificador. retornar 0. que servem para introduzir um novo operador: o operador seta ( -> ): 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 / / Ponteiros para estruturas <iostream> # include # include <string> # include <sstream> usando namespace std. cout << "(" <<pmovie-> ano << ") \ n" . getline (cin. Então. cout << "Digite o título getline (cin. o seguinte código também seria válido: pmovie = &amovie. struct .Aqui Amovie é um objeto do tipo de estrutura movies_t e pmovie é um ponteiro para apontar para objetos do tipo estrutura movies_t . cout << "Digite o ano:" . (stringstream) mystr>> pmov cout << "\ nNão digitou: \ n" . Amovie movies_t. movies_t seqüência {title int ano. Este é um operador dereference que é usado exclusivamente com ponteiros para objetos com os membros. títulos são válidos e ambos significam que estamos . Este operador serve para acessar um membro de um objeto para o qual temos uma referência. cout <<"title> pmovie. int main () {mystr string.} O código anterior inclui uma introdução importante: o operador seta ( -> ). pmovie * movies_t. Agora vamos ir com outro exemplo que inclui ponteiros. O valor do ponteiro pmovie seria atribuído a uma referência ao objeto Amovie (seu endereço de memória). pmovie = &amovie. No exemplo que usamos: título pmovie-> Qual é para todos os efeitos equivalente a: (* Pmovie).}. mystr). Título Ambas as expressões -title> pmovie e (* pmovie).-title> pmovie). movies_t seqüência {title int ano. 1 struct . B Equivalente Valor apontado por b membro de um objeto * (Ab) Nidificação estruturas Estruturas também podem ser aninhados de modo que um elemento válido de uma estrutura também pode ser. pfriends * friends_t = &charlie.title) E isso poderia acessar o valor apontado pelo ponteiro membro de um hipotético chamado título do objeto estrutura pmovie (que neste caso não seria um ponteiro). aliás.}.avaliando o membro do título da estrutura de dados apontada por um ponteiro chamado pmovie .name maria. podemos usar qualquer uma das seguintes expressões: 1 charlie. 2 3 4 struct } friends_t string {string nome. Deve ser claramente diferenciado: * Pmovie. 5 6 7 8 9 10 11 12 Após a declaração anterior.title que é equivalente a: * (Pmovie. Podemos fazer isso usando a palavra-chave typedef . por sua vez uma outra estrutura.title favorite_movie. O quadro a seguir resume as combinações possíveis de ponteiros e os membros da estrutura: Expressão ab a-> b * Ab O que é avaliado B Membro do objeto a B Membro do objeto apontado por um (* A). Outros tipos de dados Definidos os tipos de dados (typedef) C + + permite a definição de nosso próprios tipos baseados em outros tipos de dados existentes.favorite_movie.favorite_movie. charlie. as duas últimas expressões se referem a um mesmo membro).year pfriends-> 2 charlie. maria. e-mail movies_t.year 3 4 (Onde. cujo formato é: . favorite_movie. f 2 3 cada um com um tipo de dados diferentes.. Neste caso. quando é possível que teremos de alterar o tipo em versões posteriores do nosso programa. Seu tamanho é o de o maior elemento da declaração. nome do campo. char campo [50].typedef tipo_existente novo_nome_de_tipo. Uma vez que todos eles estão se referindo ao mesmo local na memória. ou se um tipo que você quiser usar tem um nome que é muito longo ou confuso. typedef pode ser útil para definir um apelido para um tipo que é usado freqüentemente dentro de um programa. . myword WORD. mas sua funcionalidade é totalmente diferente: union_name union {member_type1 member_name1. Sindicatos Uniões permitem uma mesma porção de memória a ser acessada como diferentes tipos de dados. 3 float f. 4 5 define três elementos: 1 mytypes. . Entrada PTC2 PChar. * ptc1. Não podemos armazenar valores diferentes nas mesmas independentes umas das outras. a modificação de um dos elementos afetará o valor de todos eles. respectivamente. Todos os elementos da união declaração ocupar o mesmo espaço físico na memória. unsigned int . Por exemplo: 1 2 3 4 typedef typedef typedef typedef char C. Ela só cria sinónimos de tipos existentes. char e char [50] .i mytypes. Sua declaração e utilização é semelhante ao de estruturas. que poderíamos perfeitamente usar em declarações posteriores válida como qualquer outro tipo: 1 C MyChar. já que ambos são. PChar e campo como char .} mytypes. Também é útil para definir os tipos. member_type3 member_name3. 2 int i. do mesmo tipo. WORD . Isso significa que o tipo de myword pode ser considerado tanto WORD ou unsigned int . Por exemplo: 1 União mytypes_t { char c. de facto. 2 3 4 typedef não cria tipos diferentes. char * PChar. onde existing_type é um C + + fundamentais ou compostos tipo e new_type_name é o nome para o novo tipo que estamos definindo. temos a definição de quatro tipos de dados: C . member_type2 member_name2. anotherchar. Object_names}. unsigned int WORD. uma vez que todos eles são de fato o mesmo local na memória.c mytypes. Tenho tipos mistos. Para que um objeto do primeiro tipo.dollars book. como se fossem um único longa tipo dados. Portanto. como se fossem duas curtas elementos ou como uma matriz de char elementos. Se declarar uma união sem qualquer nome. 6 7 8 define três nomes que nos permitem acessar o mesmo grupo de 4 bytes: mix.} preço. Anónimo sindicatos Em C + +. seria: 1 book. união {float dólares. A única diferença entre os dois pedaços de código é que no primeiro temos dado um nome para o sindicato ( dos preços ) e na segunda não temos.c e que podemos usar de acordo com a forma como queremos acessar esses bytes. A diferença é visto quando o acesso a membros de dólares e ienes de um objeto desse tipo. mix. porque é uma união e não uma estrutura. olhar para a diferença entre essas duas declarações estrutura: estrutura com o sindicato regularmente estrutura com união anônima struct {char título [50]. seria: 1 book.l .s e mix. Você pode definir um valor para o preço em dólares ou ienes.dollars book. respectivamente. ienes int.yen 2 Mais uma vez devo lembrar que. os membros de dólares e ienes ocupar o mesmo espaço físico na memória de modo que não pode ser usado para armazenar dois valores diferentes em simultâneo. o sindicato será anônimo e seremos capazes de acessar seus membros diretamente por seus nomes de membros. struct {char título [50].price. ienes int. autor char [50].} livro. união {float dólares.price. 5 char c [4]. 2 struct { 3 short oi.} s. 4 curto lo. Por exemplo: 1 União mix_t { longa l. esteja ciente das questões de portabilidade possível com este tipo de uso. Para um little-endian sistema (PC maioria das plataformas). temos a opção de declarar os sindicatos anônimo. esta união pode ser representada como: O alinhamento exato ea ordem dos membros de um sindicato na memória depende da plataforma.}.yen 2 Considerando que para um objeto do segundo tipo.} livro. . matrizes e estruturas na união de modo que você pode ver as diferentes formas que podemos acessar os dados.Um dos usos de uma união pode ter é a de unir um tipo elementar com um conjunto de elementos ou estruturas de menor dimensão. Por exemplo. autor char [50].} mistura. mas não em ambos. 2 outubro. O corpo da declaração pode conter membros. roxo. Observe que não incluem qualquer tipo de dados fundamental na declaração. criamos um todo novo tipo de dados a partir do zero. uma classe seria o tipo. 3 4 Enumerações são tipos compatíveis com as variáveis numéricas. valor3. Um objeto é uma instanciação de uma classe. . branco}. julho. especificadores de acesso. preto seria equivalente a 0. Em termos de variáveis. em nosso tipo de dados colors_t que temos acima definidos. access_specifier_2: member2. Se o valor constante que se segue não é dado um valor inteiro. Para dizê-lo de alguma forma. e assim por diante. verde. dezembro. amarelo. Onde class_name é um identificador válido para a classe. Por exemplo. já fizemos janeiro igual a 1 ) . para que seus constantes são sempre atribuído um valor numérico inteiro internamente. Os possíveis valores que as variáveis deste novo tipo color_t pode tomar é a constante de novos valores incluídos dentro de chaves. uma vez que o colors_tenumeração é declarado as seguintes expressões serão válidos: 1 mycolor colors_t. verde a 2 . mycolor = azul. setembro. object_names é uma lista de nomes para os objetos desta classe. As aulas são geralmente declaradas usando a palavra-chave class . novembro. o equivalente ao valor inteiro possível. Classes (I) Uma classe é um conceito expandido de uma estrutura de dados: em vez de realizar apenas os dados. abril. junho. Por exemplo. Object_names}. ele pode armazenar os dados e funções.Enumerações (enum) Enumerações de criar novos tipos de dados para conter algo diferente que não está limitada aos valores fundamentais tipos de dados podem tomar. Object_names}. vermelho. valor2. Assim. turquesa.. . Podemos especificar explicitamente um valor inteiro para qualquer um dos valores constantes que o nosso tipo enumerado pode assumir. fevereiro. maio. Sua forma é o seguinte: enumeration_name enum {valor1. e um objeto seria a variável. azul. y2k}. e que são equivalentes aos valores entre 1 e 12 (não entre 0 e 11 .. 3 Neste caso. março. agosto. o primeiro valor é equivalente a 0 e as seguintes seguem uma progressão 1. Por exemplo: 1 enum months_t {janeiro = 1. opcionalmente. a variável y2k do tipo enumerado months_t pode conter qualquer um dos 12 possíveis valores que vão de janeiro a dezembro . Se não for especificado. poderíamos criar um novo tipo de variável chamada colors_t para armazenar as cores com a seguinte declaração: enum {colors_t preto. ele é automaticamente assumido o mesmo valor do anterior mais um. 2 se (== mycolor verde) mycolor = vermelho. com o seguinte formato: class_name classe {access_specifier_1: member1. . azul seria equivalente a um . que podem ser dados ou declarações de função e. sem baseá-lo em qualquer outro tipo existente. um tipo) chamado CRectangle e um objeto (ou seja.4).Tudo é muito parecido com a declaração sobre as estruturas de dados. qualquer membro que seja declarada antes de um especificador de classe de outros automaticamente tem acesso privado. exceto que agora podemos incluir também as funções e os membros. 2 pública : 3 void set_values ( int . área . o tipo). com acesso privado (pois privadas é o nível de acesso padrão) e duas funções de membro de acesso público: set_values () e area () . myarea rect. 2 Os únicos membros do rect que não podemos acessar a partir do corpo do nosso programa fora da classe são x e y . protegidos membros são acessíveis a partir de membros da sua mesma classe e de seus amigos. mas também essa coisa nova chamada especificador de acesso .area = (). Tudo muito semelhante ao que fizemos com estruturas de dados comum antes. CRectangle era o nome da classe (ou seja. Por exemplo: 1 classe CRectangle { int x. mas também de membros de suas classes derivadas. públicas integrantes são acessíveis de qualquer lugar onde o objeto é visível. Por exemplo: 1 rect. Portanto. ) e depois o nome do membro.} rect.set_values (3. podemos nos referir dentro do corpo do programa a qualquer um dos membros públicos do objeto rect como se fossem funções normais ou variáveis normal. 5 6 Declara uma classe (ou seja. Finalmente. todos os membros de uma classe declarada com a classe de palavras-chave têm acesso privado para todos os seus membros. enquanto rect era um objeto do tipo CRectangle . uma vez que têm acesso privado e só podem ser encaminhados a partir de outros membros da mesma classe. Essa classe contém quatro membros: dois membros de dados do tipo int (membro x e membro y ). uma variável) desta classe chamado rect . Estes especificadores de modificar os direitos de acesso que os seguintes membros para que adquiram: y y y privado membros de uma classe são acessíveis somente através de outros membros da mesma classe ou de seus amigos . int ). Por padrão. Um especificador de acesso é uma das três seguintes palavras-chave: privado . y. público ou protegido . É a mesma relação int e um tem a seguinte declaração: int a. 4 int área ( void ). apenas colocando objeto o nome seguido por um ponto ( . e não sua definição. das quais para a agora só foram incluídos a sua declaração. Aqui está o exemplo completo da classe CRectangle: 1 / / Exemplo classes 2 # include <iostream> 3 usando namespace std. Após as declarações anteriores do CRectangle e rect . Observe a diferença entre o nome da classe eo nome do objeto: No exemplo anterior. onde int é o nome do tipo (a classe) e um é o nome da variável (o objeto). int ). a função será automaticamente considerado uma função inline. ao passo que set_values () tem apenas o seu protótipo declarado dentro da classe. Isso faz sentido. poderíamos ter declarado o objeto rectb além do objeto rect : 1 2 3 4 5 6 7 / / Exemplo: uma classe. Os membros x e y tem acesso privado (lembre-se que.} 11 12 int main () {CRectangle rect. Por exemplo. que na verdade supõe nenhuma diferença no comportamento. seguindo com o exemplo anterior da classe CRectangle . o resto do programa não precisa de ter acesso direto a eles. como isto. mas em projetos maiores. Por exemplo. o que significa que eles só são acessíveis por outros membros da sua classe. classe CRectangle { int x. O operador de escopo ( :: ) especifica a classe a que o membro que está sendo declarado pertence. Portanto. como qualquer outro tipo. 9 10 void CRectangle: set_values ( int a. devemos usar o operador de escopo ( :: ) para especificar que estamos definindo uma função que é membro da classe CRectangle e não uma função global regular. Ao declarar-los privados negamos acesso a eles de qualquer lugar fora da classe. é difícil ver qualquer utilidade na proteção dessas duas variáveis. rect. Talvez em um exemplo simples assim. 6 pública : 7 void set_values ( int . área . posteriormente. a sua definição. Ele é usado para definir um membro de uma classe a partir de fora da definição da própria classe. se nada for dito.area (). A única diferença entre a definição de um membro da classe funcionar completamente dentro de sua classe ou para incluir somente o protótipo e.4 5 classe CRectangle { int x. Uma das maiores vantagens de uma classe é que. uma vez que já definimos uma função membro para definir valores para os membros dentro do objeto: a função de membro set_values () . todos os membros de uma classe definida com a classe de palavras-chave têm acesso privado). mas sua definição é fora dela.4). podemos declarar vários objetos do mesmo. y.} 13 14 15 16 17 18 19 20 21 22 A coisa mais nova e importante neste código é o operador de escopo ( :: . garantindo exatamente as mesmas propriedades de escopo como se essa definição de função foi directamente incluído na definição de classe. dois-pontos). 8 int area () { retorno (x * y). é que no primeiro caso. Você pode notar que a definição da função de membro area () foi incluída diretamente na definição do CRectangle classe dada a sua extrema simplicidade. que são membros privados da classe CRectangle . cout << "Área:" <<rect. enquanto no segundo ele irá ser um normal (não-inline) função de membro de classe. na função de set_values () do código anterior. y. int b) {x = a. incluído na definição de set_values () .}}. y = b. o compilador.set_values (3. int ). Nesta declaração fora. pode ser muito importante que os valores não podem ser modificadas de forma inesperada (inesperada do ponto de vista do objeto ). retornar 0. dois objetos # include <iostream> usando namespace std. pública : void set_values ( int . temos sido capazes de utilizar as variáveis x e y . Essas funções de membro usado diretamente os membros de dados de seus respectivos objetos rect e rectb . CRectangle rectb (5. Cada um deles tem suas próprias variáveis de membro e funções membro. classe CRectangle { int largura. mas sim como lidamos com objetos que possuem os seus próprios dados e funções incorporados como membros.set_values (3.area () <<endl.} 11 int main () {rect CRectangle. cout << "área 12 rect:" <<rect.}}. rect. a classe (tipo de objetos) para o qual estamos falando é CRectangle .area () <<endl. Isso ocorre porque cada objeto da classe CRectangle tem suas próprias variáveis x e y .area () <<endl. rectb.}} . retornar 0. Vamos implementar CRectangle incluindo um construtor: 1 2 3 4 5 6 7 8 9 10 11 12 13 / / Exemplo: construtor da classe # include <iostream> usando namespace std. Construtores e destrutores Objetos geralmente precisam para inicializar variáveis ou atribuir memória dinâmica durante o seu processo de criação para se tornar operativa e para evitar o retorno de valores inesperados durante a sua execução. A fim de evitar que.6). de alguma forma. cout << "área rect:" <<rect . nem mesmo void . chamamos a função de membro area () antes de ter função chamada set_values () ? Provavelmente. teríamos obtido um resultado indeterminado desde que os membros x e y nunca teria sido atribuído um valor.area ou rectb. int b) {width = a. como parâmetros. height = b. cout << "área rectb:" <<rectb. uma classe pode incluir uma função especial chamado construtor . Esta função construtor deve ter o mesmo nome da classe. CRectangle: CRectangle ( int a.4). int ). e não pode ter qualquer tipo de retorno. int b) {x = a. 9 10 void CRectangle: set_values ( int a. também têm suas próprias funções membros set_value () e área () que cada um usa seu próprio variáveis de seu objeto de operar. uma vez que. 13 retornar 0. Nós já não usam conjuntos de variáveis globais que passamos de uma função para outra. rectb. que é chamado automaticamente sempre que um novo objeto desta classe é criado.area .8 int area () { retorno (x * y). Repare que nós não tivemos a dar os parâmetros em qualquer uma das chamadas para rect. público : CRectangle ( int . area () <<endl. int area () { retorno (altura * largura). o que aconteceria se no exemplo anterior. do qual existem duas instâncias ou objetos: rect e rectb .} int main () {rect CRectangle (3. Por exemplo.4).area () .} área . cout << "área rectb:" <<rectb. Esse é o conceito básico de programação orientada a objeto : Os dados e as funções são ambos membros do objeto. Observe que a chamada para rect. y = b.area () não dá o mesmo resultado que a chamada para rectb.set_values (5. altura.} 14 15 16 17 18 19 20 21 22 23 24 Neste caso concreto.6) . mas precedido de um sinal de til ( ~ ) e ele também deve retornar nenhum valor.14 15 16 17 18 19 20 21 22 23 Como você pode ver.} int main () {rect CRectangle (3. O destruidor cumpre a função oposta. ~ CRectangle (). int area () { retorno (* largura * * altura). largura * = a. Você também pode ver como nem a declaração do protótipo do construtor (dentro da classe).area () <<endl. Observe como esses argumentos são passados para o construtor no momento em que os objetos dessa classe são criadas: 1 CRectangle rect (3. height = novo int . ou porque o seu âmbito de existência. cout << área rectb " : " <<rectb. * height = b. retornar 0.4). excluir altura.6). tem acabado (por exemplo. O destruidor deve ter o mesmo nome da classe.}}. nem mesmo void . e incluíram em vez de um construtor que executa uma ação semelhante: ele inicializa os valores de largura e altura com os parâmetros que são passados para ele. O uso de destrutores é especialmente adequada quando um objeto atribui memória dinâmica durante sua vida útil e no momento de serem destruídos queremos liberar a memória que o objeto foi alocado.6). int ). Mas agora temos removido a função de membro set_values () .area () <<endl. cout << "área rect:" <<rect. CRectangle: CRectangle ( int a. Eles só são executados quando um novo objeto da classe é criada. 2 Construtores não podem ser chamados explicitamente como se fossem funções de membro regular. público : CRectangle ( int . classe CRectangle { int * largura. nem a definição do construtor últimos incluem um valor de retorno. se ele foi definido como um objeto local dentro de uma função ea função termina).} área . o resultado deste exemplo é idêntico ao anterior. É chamado automaticamente quando um objeto é destruído. rectb CRectangle (5. rectb (5.} CRectangle:: ~ CRectangle () { delete largura . ou porque é um objeto dinamicamente atribuído a ele e é liberado usando o operador delete.4). altura *. int b) {width = novo int . 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 / / Exemplo de construtores e destrutores # include <iostream> usando namespace std. que inicializa tanto largura e altura . para que ele tenha sido inicializado com o construtor que não tem parâmetros. cout << "área rect:" <<rect.22 23 24 25 26 27 28 29 30 Sobrecarga de Construtores Como qualquer outra função. / direita 2 rectb CRectangle (). int área ( void ) { retorno (altura * largura). int b) {width = a. No caso dos construtores.area () <<endl.area () <<endl. altura.} int main () {rect CRectangle (3. com um valor de 5. que são automaticamente chamados quando um objeto é criado. rectb foi declarada sem argumentos. / / errado! . Importante: Observe como se declarar um novo objeto e nós queremos usar o construtor padrão (um sem parâmetros). um construtor também pode ser sobrecarregado com mais de uma função que tem o mesmo nome mas diferentes tipos ou número de parâmetros. CRectangle: CRectangle () {width = 5. height = 5.} área Neste caso. CRectangle rectb. público : CRectangle (). CRectangle ( int . cout << "área rectb:" <<rectb. não incluir parênteses () : 1 rectb CRectangle. classe CRectangle { int largura. height = b. int ).4) . o executado é o único que combina os argumentos passados sobre a declaração do objeto: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 / / Construtores de classe sobrecarga # include <iostream> usando namespace std.} CRectangle: CRectangle ( int a.}} . retornar 0. Lembre-se que a sobrecarga de funções que o compilador irá chamar a cujos parâmetros coincidir com os argumentos usados na chamada de função. construtor Default Se você não declarar nenhum construtor em uma definição de classe, o compilador assume que a classe tem um construtor padrão sem argumentos. Portanto, depois de declarar uma classe como esta: 1 classe CExample { público : 2 int , a b, c; 3 void multiplica ( int n, int m) {a = n; m = b, c = a * b;}}; 4 5 O compilador assume que CExample tem um construtor padrão, então você pode declarar os objetos desta classe, basta declará-los sem argumentos: CExample ex; Mas tão logo você declarar seu próprio construtor para uma classe, o compilador não fornece um construtor padrão implícito. Então você tem que declarar todos os objetos dessa classe de acordo com o construtor de protótipos que você definiu para a classe: 1 classe CExample { público : 2 int , a b, c; CExample ( int n, int m) {a = n; m = b;}; 3 void multiplica () {c = a * b;};}; 4 5 6 Aqui temos declarado um construtor que recebe dois parâmetros do tipo int. Portanto, a declaração do objeto a seguir seria correta: CExample ex (2,3); Mas, CExample ex; Poderia não ser correcta, uma vez que temos declarado que a classe tem um construtor explícito, substituindo assim o construtor padrão. Mas o compilador não só cria um construtor padrão para você se você não especificar o seu próprio. Ele fornece três funções membro especiais no total, que são declarados implicitamente, se você não declarar o seu próprio. Estes são o construtor de cópia , o operador de atribuição de cópia , eo destrutor padrão. O construtor de cópia ea cópia cópia operador de atribuição de todos os dados contidos em outro objeto para os membros de dados do objeto atual. Para CExample , o construtor de cópia declarada implicitamente pelo compilador seria algo semelhante a: 1 CExample: CExample ( const CExample & RV) {a = rv.a; rv.b b = c = rv.c;} 2 3 Portanto, as duas declarações de objeto a seguir seria correta: 1 CExample) ex (2,3; CExample ex2 (ex); 2 / construtor de cópia (dados copiados da ex) Ponteiros para classes Isso é perfeitamente válido para criar indicadores que apontam para as aulas. Nós simplesmente temos que considerar que, uma vez declarada, a classe se torna um tipo válido, por isso podemos usar o nome da classe como o tipo de ponteiro. Por exemplo: CRectangle prect *; é um ponteiro para um objeto da classe CRectangle . Como aconteceu com estruturas de dados, a fim de se referir diretamente a um membro de um objeto apontado por um ponteiro, podemos usar o operador seta ( -> ) de engano. Aqui está um exemplo com algumas combinações possíveis: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 / / Ponteiro para classes exemplo # include <iostream> usando namespace std; classe CRectangle { int largura, altura; pública : void set_values ( int , int ); int área ( void ) { retorno (altura * largura);}}; void CRectangle: set_values ( int a, int b) {width = a; height = b;} int * () {CRectangle a, b *, c principal; CRectangle * d = novo CRectangle [2], b = novo CRectangle; = &a (3,4);-> set_values d (5,6); d [1];. set_values (7,8) cout << "um área: " <<a.area () <<endl; cout << "* "área de c *" <<c> área () <<endl; cout << "d [0] área:" <<d [0] <. área () <<endl <tribunal, "d [1] área delete ] [d; excluir b; retornar 0;} Em seguida você tem um resumo sobre como você pode ler alguns ponteiro e operadores de classe ( * , & , . , -> , [] ) que aparecem no exemplo anterior: expressão pode ser lido como *X &X xy x, y> (* X). Y x [0] x [1] [N] x apontado por x Endereço de x membro y do objeto x y membro do objeto apontado por x y membro do objeto apontado por x (equivalente ao anterior) primeiro objeto apontado por x segundo objeto apontado por x (N +1) th objeto apontado por x Tenha certeza que você entender a lógica em todas essas expressões antes de prosseguir com as próximas seções. Se você tiver dúvidas, leia novamente esta seção e / ou consultar as seções anteriores sobre ponteiros e estruturas de dados. Classes definidas com estrutura e união As classes podem ser definidas não só com palavra-chave classe , mas também com palavraschave struct e união . Os conceitos de classe e de estrutura de dados são tão semelhantes que tanto palavras-chave ( struct e classe ) pode ser usado em C + + para declarar classes (ou seja, struct s também pode ter membros de função em C + +, não apenas os membros de dados). A única diferença entre ambos é que os membros das classes declaradas com a palavra-chave struct têm acesso público, por padrão, enquanto os membros das classes declaradas com a palavra-chave classe tem acesso privado. Para todos os fins palavraschave são equivalentes. O conceito de união é diferente da de classes declaradas com struct e classe , já que os sindicatos só armazenam um membro de dados em um momento, mas, no entanto, eles também são classes e assim também pode se prender membros de função. O acesso padrão em classes de união é pública. Classes (II) Sobrecarga de operadores C + + incorpora a opção de utilizar os operadores padrão para realizar operações com classes para além dos tipos fundamentais. Por exemplo: 1 int a, b, c, a = b + c; 2 Isto é obviamente um código válido em C + +, uma vez que as diferentes variáveis da adição são todos os tipos fundamentais. No entanto, não é tão óbvio que poderíamos realizar uma operação semelhante à seguinte: 1 struct produto {string; float preço;} a, b, c, a = b + c; 2 3 4 5 Na verdade, isso irá causar um erro de compilação, já que não temos definido o comportamento de nossa classe deve ter com as operações de adição. No entanto, graças ao C + + recurso para sobrecarregar operadores, nós podemos projetar classes capaz de executar operações usando os operadores padrão. Aqui está uma lista de todos os operadores que podem ser sobrecarregados: considere que alguns deles se referem ao nome da classe (tipo) CVector e alguns outros são funções com esse nome (construtores devem ter o mesmo nome da classe). CVector: : CVector ( param. A adição de dois vetores bidimensionais é uma operação simples como adicionar os dois x coordenadas para obter o resultado x coordenar e adicionando os dois y coordenadas para obter o resultado y . Neste caso. O formato é: Inscreva-se operador de tipo (parâmetros) {} /*.* / = <> + = -= *= / = <<>> <<=>> = == = <=> = + + -!% & ^! | ~ & = ^ = | = & & | | =% [] (). retornar 0.} Pode ser um pouco confuso de ver muitas vezes de modo que o CVector identificador." << cy..2). c = a + b.1).operadores pode ser sobrecarregado + . 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 / / Vetores: a sobrecarga de operadores exemplo # include <iostream> usando namespace std. -> * -> Novo delete] [novo delete [] Para sobrecarregar um operador.y + y = param . CVector b (1. a fim de usá-lo com aulas declaramos funções de operador . Vamos criar uma classe para armazenar vetores bidimensionais e. CVector operador + (CVector). Não confundi-los: 1 CVector ( int . que são funções regulares cujos nomes são os operadores -chave. int )..}. 2 CVector operador + (CVector).1 +2) = (4. CVector () {}.2) . Mas. int ).} int main () {CVector um (3. CVector c.*/ Aqui você tem um exemplo que sobrecarrega o operador de adição ( + ). y retorno (temp)..1) e b (1. cout <<cx << ". / / nome da função CVector (construtor) / função retorna / a CVector A função de operador + de classe CVector é aquele que está encarregado de sobrecarregar o operador de . seguida do sinal do operador que queremos sobrecarga. o resultado será (3 +1.x + (CVector param) {CVector temp.3) . y x. CVector ( int . classe CVector { público : int . em seguida. vamos acrescentar duas delas: uma (3. Esta função pode ser chamado de forma implícita usando o operador. A sobrecarga de operadores não força o seu funcionamento para suportar uma relação com o habitual ou significado matemático do operador. a declaração: CVector c. que é a inicialização de todas as variáveis de membro de sua classe. operador + (b). que. com qualquer número de parâmetros.3). pois temos outro construtor declarado explicitamente: CVector ( int . No nosso caso o construtor deixa as variáveis x e y indefinido. uma definição mais aconselhável seria algo semelhante a isto: CVector () {x = 0. Bem como uma classe inclui um construtor padrão e um construtor de cópia. c = a.}. mesmo que não são declarados. Caso contrário. O comportamento que é definido por padrão é copiar todo o conteúdo dos membros de dados do objeto passado como argumento (o do lado direito do sinal) para o outro no lado esquerdo: 1 CVector d (2. Enfim. y = 0. tenho de avisá-lo que um bloco vazio é uma má aplicação de um construtor. E quando explicitamente declarar todos os construtores. Por exemplo. copiar apenas os membros certa classe ou executar procedimentos de inicialização adicionais. Claro. ou explicitamente usando o nome da função: 1 c = a + b. 2 As duas expressões são equivalentes. mas também inclui uma definição padrão para o operador de atribuição ( = ) com a própria classe como parâmetro. como por exemplo. Isso é necessário. incluído no main () não teria sido válido. você pode redefini-lo para qualquer outra funcionalidade que você deseja. Portanto. para simplificar e mostrar apenas o ponto do código eu não ter incluído no exemplo. 2 3 / / operador de atribuição de cópia A cópia função operador de atribuição é a função de membro único operador implementada por padrão. Observe também que nós incluímos o construtor vazio (sem parâmetros) e temos definido com um bloco vazio: CVector () {}. int ). uma vez que não cumpriu a funcionalidade mínima que geralmente é esperado de um construtor. por isso precisamos declará-la nós mesmos. embora seja recomendado.adição ( + ). CVector e E = d. o código pode não ser muito . o construtor padrão sem parâmetros que o compilador pode declarar automaticamente não seja declarado. a fim de ser capaz de construir objetos desse tipo sem parâmetros . }. e é uma b" . Você pode ver neste painel que existem duas maneiras de sobrecarregar alguns operadores de classe: como uma função de membro e como uma função global.* &! ~ + + ++Operador função de membro A:: operador @ () A:: operador @ (int) função global operador @ (A) operador @ (A.) Um operador::> () - Sempre que um é um objeto da classe A . B) - + . É um ponteiro para o objeto em si. e Também é freqüentemente usada em operador = funções membro que retornam objetos por referência . = se (-> isitme b (a)) cout << "sim. int CDummy: isitme (CDummy e param) { se (e param == presente ) retornar true . Embora o protótipo de uma função de operador + pode parecer óbvio. C.. Seu uso é indistinta. Por exemplo. devo lembrar que as funções que não são membros de uma classe não pode acessar os membros private ou protected da classe a menos que a função global é o seu amigo (a amizade é explicado mais adiante). . A palavra-chave desta A palavra-chave desta representa um ponteiro para o objeto cujo membro função está sendo executada. b é um objeto da classe B e C é um objeto da classe C .) a-> x + . .. int) operador @ (A. uma vez que leva o que está no lado direito do operador como o parâmetro para a função de membro do operador do objeto em seu lado esquerdo. no entanto. Aqui você tem uma tabela com um resumo sobre como funciona o operador diferentes têm de ser declaradas (substitua @ pelo operador. } int main () {CDummy um.^ / *% & | <==> = <=> = <<>> & & | |. mais retornar false . Um de seus usos podem ser para verificar se um parâmetro passado para uma função de membro é o próprio objeto. embora seja perfeitamente possível fazê-lo. se você usar o operador + para subtrair duas classes ouoperador == para preencher com zeros uma classe. classe CDummy { público : int isitme (CDummy e param). A:: operador @ (B) = + = -= *= / =% = & = ^ = | = <<=> = [] A:: operador @ (B) () -> Um operador:: () (B. retornar 0.} sim.intuitivo. CDummy b * &a. a outros operadores pode não ser tão óbvio. em cada caso): Expressão @A um @ um @ b um @ b a (b c. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 / / Este # include <iostream> usando namespace std. retornar 0. que deve incluir uma definição formal fora da classe. no âmbito global. esta função é muito semelhante ao código que o compilador gera implicitamente para esta classe. Por exemplo. Seguindo com os exemplos do vetor visto antes. mas eles gostam de escopo de classe.}. CDummy b [5]. CDummy c * = nova CDummy. Membros de dados estáticos de uma classe também são conhecidos como "variáveis de classe".}. Por esse motivo. como no exemplo a seguir: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 / / Membros estáticos em classes # include <iostream> usando namespace std. mas não a sua definição (sua inicialização). Os membros estáticos Uma classe pode conter estático membros. Seu conteúdo não é diferente de um objeto desta classe para outra. ~ CDummy () {n -. classe CDummy { público : static int n. apagar c. y = param. pode ser referido como um membro de qualquer objeto dessa classe ou mesmo diretamente pelo nome da classe (é claro que isso só é válido para membros estáticos): . CDummy () {n + +. só podemos incluir o protótipo (sua declaração) na declaração da classe. e para evitar que sejam declaradas várias vezes. cout <<CDummy: n <<endl. como no exemplo anterior: int CDummy: n = 0. voltar * este . Porque é um valor variável única para todos os objetos da mesma classe. se não incluir um operador = função de membro para copiar objetos dessa classe.} 7 6 De fato. porque só existe um valor único para todos os objetos da mesma classe.x. poderíamos ter escrito um operador = função semelhante a esta: 1 CVector & CVector: operador = ( const CVector e param) {x = param. dados ou funções. membros estáticos têm as mesmas propriedades como variáveis globais. int CDummy: n = 0. pode ser usado para uma variável dentro de uma classe que pode conter um contador com o número de objetos dessa classe que estão actualmente afectados. Para inicializar um membro de dados estáticos.}. cout <<um <<endl.y.(evitando o uso de objetos temporários).} 2 3 4 5 6 Na verdade. int main () {CDummy um. os membros privados e protegidos de uma classe não pode ser acessado de fora da mesma classe na qual elas são declaradas. Mais uma vez. de facto. essas funções não são membros de qualquer objeto. rectb.1 Cout <<uma. De dentro dessa função. height = b. mas membros diretos da classe. declarando um protótipo desta função externa dentro da classe. se referindo à mesma variável: a variável estática n dentro da classe CDummy compartilhada por todos os objetos dessa classe.} A duplicação da função é um amigo de CRectangle . Eles só podem fazer referência a dados estáticos. altura * 2.3).set_values (2. Amizade e herança funções Amigo Em princípio.} CRectangle duplicado (rectparam CRec rectparam = . em nenhum caso a membros nãoestáticos da classe. int b) {width = a. cout <<CDummy:: n. Assim como podemos incluir dados estáticos em uma classe. bem como não permitir a utilização da palavra-chave deste . esta regra não afeta amigos . pública : void set_values ( int . A única diferença é o seu nome e eventuais restrições de acesso externo à classe. devo lembrar que na verdade é uma variável global.area <() retornar 0. altura.} amigo CRectangle duplicado (CRectangle) . já que faz referência a um ponteiro de objeto e. int ). int area () { retorno (altura * largura).} int main () {rect CRectangle. permitindo assim que esta função para ter acesso aos membros privados e protegidos da classe. rectb = duplicado (rect).}. rect. podemos incluir também funções estáticas. No entanto. 2 Essas duas chamadas incluídas no exemplo anterior. e precedendo-o com a palavra-chave amigo : 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 Amigo / funções / # include <iostream> usando namespace std. retorno (rectres). void CRectangle: set_values ( int a. cout rectb. Amigos são funções ou classes declaradas com o amigo -chave. Se queremos declarar uma função externa. temos sido capazes de acessar . como amigo de uma classe. nós fazemo-lo. Eles representam a mesma coisa: são funções globais que são chamados como se fossem membros do objeto de uma determinada classe. classe CRectangle { int largura. então se não incluir uma declaração vazia anterior para CSquare esta classe não seria visível a partir da definição de CRectangle . No nosso .} int main () { sqr CSquare. que descreve a largura do lado do quadrado. Você também pode ver algo novo no início do programa: uma declaração vazia de classe CSquare . As funções de amigo pode servir. classe CRectangle { int largura. rect.} amigo de classe CRectangle. teria sido mais curto para integrar duplicado () dentro da classe CRectangle . Considere que as amizades não são correspondidos.side =. pública : void set_side ( int a) {lado = a.area (). a realização de operações entre duas classes diferentes. sem ser membro.}. classe CSquare { privado : int lado. altura a. CRectangle rect. garantindo que o acesso de primeira classe para os membros protected e private da segunda. <(rect. Observe que nem na declaração de duplicate () nem em seu uso posterior no main () temos observado duplicar um membro da classe CRectangle . classes amigo Assim como temos a possibilidade de definir uma função de amigo. por exemplo. Mas não é! Ele simplesmente tem acesso aos seus membros privados e protegidos. público : int area () { retorno (altura * largura). A definição deCSquare incluído mais tarde. que são membros privados. se não especificar explicitamente assim. também podemos definir uma classe como amigo do outro. Geralmente.set_side (4). 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 Classe / amigo / # include <iostream> usando namespace std. mais concretamente para CSquare:: lado . o uso de funções é amigo de uma metodologia de programação orientada a objeto. void CRectangle: converter (CSquare a) {width = a. altura. cout < retorn 0. por isso sempre que possível.} 16 Neste exemplo. Tal como no exemplo anterior.} void convert (CSquare a).side.}.convert sqr).os membros de largura e altura de diferentes objetos do tipo CRectangle . Isso é necessário porque dentro da declaração de CRectangle nos referimos CSquare (como um parâmetro em convert () ). declaramos CRectangle como um amigo de CSquare modo que CRectangle funções membro podem ter acesso aos membros protegidos e privados de CSquare . é melhor usar membros da mesma classe para realizar operações com eles. classe CSquare. sqr. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 / / Classes derivadas # include <stdio. A fim de derivar uma classe da outra.. Onde derived_class_name é o nome da classe derivada e base_class_name é o nome da classe em que se baseia.h> class CPolygon { protegida : int largura.. vamos supor que queremos declarar uma série de classes de polígonos que descrevem como a nossa CRectangle . A herança permite criar classes que são derivadas de outras classes. O público especificador de acesso pode ser substituído por qualquer um dos especificadores de acesso a outras protegidas eprivadas . Eles têm algumas propriedades comuns. a classe derivada contém ambos os membros A e B . públic : void set_values ( int a. Isso poderia ser representado no mundo das classes com uma classe CPolygon das quais se derivam as duas outras: CRectangle e CTriangle .*/ {}. com características específicas que são diferentes de um tipo de polígono para o outro. mas CRectangle não considera CSquare ser um amigo.} }. enquanto os membros com mais restritivas de acesso de nível igual ou manter o seu nível restritivas na classe derivada . Por exemplo. de modo que automaticamente inclui alguns dos seus "pais" os membros. além de seus próprios. class CRectangle: public CPolygon { public : int area () { retorn (altura * largura). A classe CPolygon deve conter elementos que são comuns para ambos os tipos de polígono. E CRectangle e CTriangle seriam suas classes derivadas. usamos dois pontos ( : ) na declaração da classe derivada usando o seguinte formato: derived_class_name classe: base_class_name público /*. Outra propriedade das amizades é que eles são não transitivo : O amigo de um amigo não é considerado para ser um amigo a menos que explicitamente especificado. CRectangle é considerada como uma classe amigo por CSquare . int b) {width = a. É claro que poderíamos ter declarado também CSquare como amigo CRectangle se quiséssemos. Isso significa que se uma classe base inclui um membro de A e obtemos que a outra classe com outro membro chamado B . Herança entre classes Uma característica fundamental de classes C + + é a herança.} }. ou como CTriangle . entãoCRectangle pode acessar o e privadas membros protegidos de CSquare mas não da maneira inversa. As classes que são derivadas de outras herdar todos os membros acessível da classe base. height = b. como ambos podem ser descritas por meio de apenas dois lados: altura e base. class CTriangle: public CPolygon { . No nosso caso: largura e altura . altura.exemplo. Este especificador limita o acesso a níveis mais acessíveis para os membros herdados da classe base: Os membros com um nível mais acessíveis são herdadas com este nível em vez disso. como de main () . No nosso exemplo. Estes são: largura . altura e set_values () .area () ). printf (trgl. os membros da classe derivada pode acessar os membros protected herdado da classe base.set_values (4. 22 printf (rect. 20 CTriangle trgl. Sua única diferença ocorre de fato com a herança. O protegido especificador de acesso é semelhante ao privado .5). Desde que queríamos largura e altura para ser acessível aos membros das classes derivadas CRectangle e CTriangle e não apenas por membros da CPolygon . 18 int main () { 19 CRectangle rect.15 public : int area () { retorn (altura * largura / 2). trgl. os membros herdados por CRectangle e CTriangle ter as permissões de acesso mesmo que eles tinham na sua base de classe CPolygon : 1 2 3 4 5 CPolygon: largura CRectangle: largura CPolygon: set_values () CRectangle: set_values () / / acesso protegido / / acesso protegido / / acesso público / acess / public Isto é porque nós usamos o público palavra-chave para definir a relação de herança em cada uma das classes derivadas: . Quando uma classe herda de outra. mas não os seus membros particulares. Podemos resumir os tipos de acesso diferentes de acordo com quem pode acessá-los da seguinte forma: Acesso membros da mesma classe público protegidas privada sim sim sim não sim não não membros de classes derivadas sim não membros sim Onde "não membros" representa qualquer acesso de fora da classe. 21 rect. } 25 26 27 28 29 30 31 32 33 Os objetos das classes CRectangle e CTriangle cada conter membros herdados CPolygon .} 16 17 }.area ()).5). temos utilizado protegida de acesso em vez de privada . 23 24 retorn 0. a partir de outra classe ou de uma função.set_values (4. .} }. o construtor sem parâmetros) e seu destruidor é sempre chamado quando um novo objeto de uma classe derivada é criado ou destruído.} }. que definimos como: classe filha: protegida mãe. Considerando que se especifique mais a restrição de acesso a todos os níveis:privado . Se não especificar explicitamente qualquer nível de acesso para a herança. Se especificar um nível de acesso mais restritivo como protegido . uma classe derivada herda todos os membros de uma classe base. O que é herdado da classe base? Em princípio. Ou seja. todos os membros que estavam no público a mãe ficaria protegida em filha . especificando essa palavra-chave da classe derivada vai herdar todos os membros com os mesmos níveis que tinham na classe base. Desde público é o nível mais acessível. Por exemplo. Esse nível de acesso máxima é definida apenas para os membros herdados da mãe . você pode especificá-lo em cada definição de construtor da classe derivada: derived_constructor_name (parâmetros): base_constructor_name (parâmetros) {. Se a classe base não tem nenhum construtor padrão ou você quer que um construtor sobrecarregado é chamado quando um novo objeto derivado é criado.classe CRectangle: público CPolygon {. todos os membros públicos da classe base são herdadas... que é protegida na classe derivada. isso não restringiria a filha para declarar seus próprios membros do público. o seu construtor padrão (ou seja. o compilador assume particular para as classes declaradas com a classe de palavra-chave e público para as declaradas com struct ..} Por exemplo: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 / / Construtores e classes derivadas # include <stdio> class mãe { public : a mãe () {printf("mãe: sem parâmetros \ n"). Tal conjunto protegido como o nível máximo de acesso para os membros da filha que herdou da mãe . todos os membros da classe base são herdadas como privado. } Este público palavra-chave após os dois pontos ( : ) indica o nível mais acessíveis os membros herdados da classe que se lhe segue (neste caso CPolygon ) terá.} }. retorn 0. daniel filho (0). class filho: public mãe { public : o filho ( int a): mãe () {printf ("o filho: parâmetro int \ \ n \ n").} Mãe . int main () {filha cynthia (0). Claro. se a filha era uma classe derivada da mãe. exceto: y y y seu construtor e seu destruidor seu operador = () membros seus amigos Embora os construtores e destruidores da classe base não são herdados si. class filha: public mãe { public : a filha ( int a) {printf ("filha: parâmetro int \ n \ n").} mãe ( int a) {printf ("mãe: int \ n parâmetro "). }}. . }. } }. classe COutput { públicos : void saída ( int i).}}. se tivéssemos uma classe específica para impressão em tela ( COutput ) e quisemos que nosso classes CRectangle e CTriangle também herdam seus membros. altura. aqui está o exemplo completo: 1 2 3 4 5 6 7 8 9 1 0 1 1 1 2 1 3 1 4 1 5 1 6 1 7 1 / / Herança múltipla # include <stdio. Por exemplo. height = b. public : void set_values ( int a. classe CTriangle: público CPolygon. A diferença é porque a declaração construtor da filha e filho : 1 filha ( int a) / / nada especificado: padrão chamada 2 filho ( int a): mãe (uma) / / construtor especificado: chamar esse Herança múltipla Em C + + é perfeitamente possível que uma classe herda os membros de mais de uma classe. public COutput { public : int area () { retorn (altura * largura / 2). public COutput. para além das de CPolygon podemos escrever: 1 class CRectangle: public CPolygon. int b) { width = a. public COutput { público : int area () { retorn largura (altura * ). void COutput: saída ( int i) {printf (i). 2 class CTriangle: public CPolygon. public COutput. Isso é feito simplesmente separar as classes base diferentes com vírgulas na declaração da classe derivada.17 18 19 20 21 22 23 24 25 26 27 28 29 30 Observe a diferença entre as quais a mãe é construtor é chamado quando um novo filha objeto é criado e que quando é um filho do objeto.} classe CRectangle: public CPolygon.h> classe CPolygon { protegida : int largura. trgl. Amizade e herança .output (rect. você deve rever as seções indicadas: Declaração: int a: b (int c) {} a-> b Explicado em: Classes Estruturas de Dados Classe A: b pública {}. 0 rect.area ()).set_values (4. Se qualquer uma das seguintes afirmações parecer estranho para você. 5). 2 2 retorn 0. 2 trgl.output (trgl.5). 2 } 3 2 4 2 5 2 6 2 7 2 8 2 9 3 0 3 1 3 2 3 3 3 4 3 5 3 6 3 7 3 8 3 9 4 0 4 1 4 2 Polimorfismo Antes de chegar a este ponto. é recomendável que você tenha uma compreensão adequada dos ponteiros e herança de classe. 1 rect.8 1 int main () { 9 CRectangle rect. 2 trgl CTriangle.set_values (4.area ()). classe CPolygon { protegida : int largura. ambos são operações de atribuição é válida.} Em função principal . por isso não pode aplicá-lo na classe base. no final do programa.5). esse membro deve também ter sido declarado na classe CPolygon . quando se tornam membros virtuais em mãos: . cout trgl.}}. Isto é. tivemos de usar diretamente os objetos rect e trgl em vez de os ponteiros ppoly1 * e * ppoly2 . Então vamos atribuir referências ao rect e trgl a esses ponteiros. int main () {CRectangle rect. que traz Metodologias Orientada a Objetos para o seu pleno potencial. Por essa razão. height = b. int b) {width = a. classe CRectangle : público CPolygon { público : int area () { retorno (altura * largura). A única limitação no uso ppoly1 * e * ppoly2 vez de rect e trgl é que ambos ppoly1 * e * ppoly2 são do tipo * CPolygon e.area () <<endl . retornar 0. portanto. trgl CTriangle. criamos dois ponteiros que apontam para objetos de classe CPolygon ( ppoly1 e ppoly2 ). CPolygon * ppoly1 = &rect. mas poderosa e versátil. pública : void set_values ( int a. classe CTriangle: público CPolygon { público : int area () { retorno (altura * largura / 2). -> set_values ppoly1 (4. Vamos começar por reescrever o nosso programa sobre o retângulo eo triângulo da seção anterior.}}. tendo em conta esta propriedade compatibilidade ponteiro: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 / / Ponteiros para classe base # include <iostream> usando namespace std.-> set_values ppoly2 (4. altura. cout <<rect. e não apenas em suas classes derivadas. só podemos utilizar esses ponteiros para se referir aos membros que CRectangle e CTriangle herdam CPolygon . A fim de utilizar área () com os ponteiros para a classe CPolygon .5). CPolygon * ppoly2 = &trgl. e porque ambos são objetos de classes derivadas de CPolygon . mas o problema é que CRectangle e CTriangle implementar diferentes versões de área .Ponteiros para classes base Uma das principais características de classes derivadas é que um ponteiro para uma classe derivada é de tipo compatível com um ponteiro para sua classe base. Polimorfismo é a arte de tirar proveito desse recurso simples.area <() <<endl. quando nós chamamos a área () membros.}}. mais precisamente quando o tipo do ponteiro é um ponteiro para a classe base mas está apontando para um objeto da classe derivada. 10 e 0 . CPolygon * ppoly2 (4.5).}}. CRectangle e CTriangle ) têm todos os membros da mesma: largura . Isso é porque em vez de chamar o correspondente área () função para cada objeto ( CRectangle: area () . pública : void set_values ( int a. classe CRectangle: público CPolygon { público : int area () { retorno (altura * largura). respectivamente). classe CTriangle: público CPolygon { público : int area () { retorno (altura * largura / 2). height = b. set_values () e Area () . CPolygon * ppoly1 = &rect. cout <<. A função de membro area () foi declarada como virtual na classe base.} virtual int area () { retorno (0). CTriangle:: Área () e CPolygon: area () .-> set_values ppoly3 (4. como no exemplo acima. e depois de executar o programa. que deve preceder sua declaração com a palavra-chave virtual : 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 / / Membros virtuais # include <iostream> usando namespace std. altura.> Área ppoly1 () <<endl. cout <<.5). classe CPolygon { protegida : int largura. o resultado será 0 para os três polígonos ao invés de 20 . porque é tarde redefinido em cada classe derivada. Você pode verificar se quiser que se você remover esse virtual palavra-chave da declaração de área () dentro CPolygon . Para declarar um membro de uma classe como virtual. Portanto.> Área ppoly2 () <<endl. cout retornar 0. CPolygon:: Área () será chamado em todos os casos. int b) {width = a. CTriangle trgl.membros Virtual Um membro de uma classe que pode ser redefinida em suas classes derivadas é conhecida como um membro virtual. o que o virtual não é palavra-chave para permitir que um membro de uma classe derivada com o mesmo nome de um na classe base deve ser chamado apropriadamente de um ponteiro e.} Agora as três classes ( CPolygon . int main () {CRectangle rect. . CPolygon poli. uma vez que as chamadas são através de um ponteiro cujo tipo é * CPolygon .}}.}}. altura . .} 6 virtual int área () = 0. 4 pública : 5 void set_values ( int a. altura. Portanto uma declaração como: CPolygon poli. Nós podemos criar ponteiros para isso e tirar proveito de todas as suas capacidades polimórficas. pelo menos. Isso é feito acrescentando = 0 (igual a zero) para a declaração da função. No entanto. porque tenta instanciar um objeto. base de classes abstratas classes base abstratas são algo muito semelhante ao nosso CPolygon classe do nosso exemplo anterior. um dos seus membros não tem aplicação não podemos criar instâncias (objetos) do mesmo. portanto. não seria válida para a classe base abstrata que acabamos de declarar. é uma classe abstrata de base. Aqui você tem o exemplo completo: 1 / / Classe abstrata de base 2 # include <iostream> 3 usando namespace std. int b) {width = a. A principal diferença entre uma classe base abstrata e uma classe regular polimórficos porque é que nas classes de base abstrata. também temos sido capazes de declarar um objeto do tipo CPolygon e chamar o seu próprio domínio () função. CPolygon * ppoly2. que sempre retorna 0. os ponteiros para essa classe abstrata de base pode ser usado para apontar para objetos de classes derivadas. No entanto. temos definido um válido área () função com um mínimo de funcionalidade para os objetos que eram de classe CPolygon (como o objeto poli ). as seguintes indicações: 1 CPolygon * ppoly1. Um resumo da classe base CPolygon poderia ficar assim: 1 / / Classe abstrata CPolygon 2 classe CPolygon { protegida : 3 int largura. apesar da sua virtualidade. e todas as classes que contêm pelo menos uma função virtual pura são classes base abstratas . Isto é assim por quanto tempo CPolygon inclui uma função virtual pura e. Este tipo de função é chamada de função virtual pura . 2 seria perfeitamente válido. 7 8 9 Observe como nós anexado = 0 para área int virtual () em vez de especificar uma aplicação para a função. height = b. A única diferença é que no nosso exemplo anterior.Uma classe que declara ou herda uma função virtual é chamada de classe polimórfica . Note que. Mas uma classe que não pode instanciar objetos não é totalmente inútil.}. enquanto em uma classe abstrata de base poderíamos deixar essaárea () membro funcionar sem a aplicação a todos. trgl CTriangle. Por exemplo. retornar 0.}}. altura. classe CRectangle: público CPolygon { público : int área ( void ) { retorno (altura * largura). height = b. int b) {width = a. Isto pode ser tremendamente útil. trgl CTriangle. classe CTriangle: público CPolygon { público : int área ( void ) { retorno (altura * largura / 2). retornar 0. pública : void set_values ( int a. emboraCPolygon em si não tem aplicação para essa função: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 / / Pure membros virtuais podem ser chamados / / na classe base abstrata # include <iostream> usando namespace std. int main () {CRectangle rect. CPolygon * ppoly1 = &rect.4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 classe CPolygon { protegida : int largura. classe CRectangle: público CPolygon { público : int área ( void ) { retorno (altura * largura).} virtual int área ( void ) = 0. classe CTriangle: público CPolygon { público : int área ( void ) { retorno (altura * largura / 2).-> set set_values (4.5).-> printArea ppoly1 (). agora podemos criar uma função de membro da classe base abstracta CPolygon que é capaz de imprimir na tela o resultado da área () função. height = b. tribunal ppoly2 <ppoly1-> Área <() <<endl.-> set_values ppoly2 (4. cout <<.}}.-> set_valu (4.5).} Se você revisar o programa que você irá notar que nos referimos a objetos de classes diferentes.-> printArea ppoly2 (). int b) {width = a. altura. CPolygon * ppoly2 = &trgl.}.}}.5>).}}.> Área ppoly2 () <<endl.} virtual int área ( void ) = 0.} . mas relacionados com um tipo único de ponteiro ( CPolygon * ). classe CPolygon { protegida : int largura. void printArea ( void ) {cout << este -> Área () <<endl. int main () {CRectangle rect. CPolygon * ppoly1 = CPolygon * ppoly2 = &trgl. pública : void set_values ( int a.}}. classe CPolygon { protegida : int largura. int main () {CPolygon ppoly1 * = nova CRectangle. int b) {width = a.-> printArea ppoly1 (). temos visto muito simples usa esses recursos. Vamos terminar com o mesmo exemplo de novo. pública : void set_values ( int a. classe CTriangle: público CPolygon { público : int área ( void ) { retorno (altura * largura / 2). Claro. CPolygon ppoly2 * = nova CTriangle.}}.-> set_values ppoly1 (4.} virtual int área ( void ) = 0.25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 membros Virtual e classes abstratas conceder C + + as características polimórficas que fazem programação orientada a objetos como um instrumento útil em grandes projetos. altura. classe CRectangle: público CPolygon { público : int área ( void ) { retorno (altura * largura).-> printArea ppoly2 ().}}. excluir ppoly2. retornar 0.}} . mas desta vez com os objetos que são alocados dinamicamente: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 / Alocação dinâmica de / e polimorfismo # include <iostream> usando namespace std. mas esses recursos podem ser aplicados a arrays de objetos ou objetos alocados dinamicamente.-> set_values ppoly2 (4. excluir ppoly1.} . void printArea ( void ) {cout << este -> Área () <<endl. height = b.5).5). Estes modelos de função pode usar esses parâmetros como se fossem qualquer outro tipo regular. Como você pode ver. 2 Quando o compilador encontra esta chamada para uma função de modelo. para criar um modelo de função que retorna o maior um dos dois objetos que podemos usar: 1 template < classe myType> myType GetMax (myType um myType. Modelos Modelos de função Função modelos são funções especiais que podem operar com tipos genéricos . pois ambas as expressões têm exatamente o mesmo significado e se comportam exatamente da mesma maneira.} 3 4 Aqui nós criamos uma função de modelo com myType como parâmetro do modelo. y). CPolygon ppoly2 * = nova CTriangle. b) { 2 retorno (a. Seu uso é indiferente. Isso nos permite criar um modelo de função cuja funcionalidade pode ser adaptado para mais de um tipo ou classe. b> b? a:). GetMax < int > (x. sem repetir o código inteiro para cada tipo. este pode ser conseguido usando parâmetros do modelo . Este parâmetro do modelo representa um tipo que ainda não foi especificado. Um parâmetro do modelo é um tipo especial de parâmetro que pode ser usado para passar um tipo como argumento: como regular os parâmetros de função pode ser usada para passar os valores para uma função. Por exemplo. Por exemplo. 2 são declaradas sendo do tipo ponteiro para CPolygon mas os objetos dinamicamente alocados tenham sido declarados com o tipo de classe derivada diretamente. Para utilizar este modelo de função usamos o seguinte formato para chamar a função: <tipo> function_name (parâmetros). O formato para declarar a função de modelos com parâmetros de tipo é: <class modelo function_declaration identificador>.Observe que o ppoly ponteiros: 1 CPolygon ppoly1 * = nova CRectangle. y. A única diferença entre os dois protótipos é o uso de qualquer palavra-chave classe ou a palavrachave typename . Este processo é realizado automaticamente pelo compilador . template <typename identificador>. mas que pode ser usado na função de modelo como se fosse um tipo normal. Em C + +. ele usa o modelo para gerar automaticamente a função de substituir cada aparição de myType pelo tipo passado como o parâmetro do modelo atual ( int neste caso) e depois chama-lo. podemos escrever: 1 int x. parâmetros do modelo permitem a passagem também tipos para uma função. o modelo de função GetMax retorna o maior dos dois parâmetros deste tipo ainda indefinido. para chamar GetMax para comparar dois valores inteiros do tipo int . } 6 10 . j). o tipo T é usado dentro do GetMax () função de modelo mesmo para declarar novos objetos desse tipo: T resultado. o compilador pode automaticamente descobrir que o parâmetro do modelo só pode ser int . resultado = (a> b)? a: b. Neste caso específico em que o tipo genérico T é usado como parâmetro para GetMax o compilador pode descobrir automaticamente que tipo de dados tem para criar uma instância sem explicitamente especificá-lo nos parênteses em ângulo (como nós fizemos antes de especificar <int> e <longo > ). b>? a. GetMax (i. cout <<k <<endl. k = 6. cout <<n <<endl. retorno (resultado). k = GetMax < int > (i. poderíamos ter escrito em vez disso: 1 int i. modelo < classe T> T GetMax (T a. Aqui está o exemplo completo: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 / Template / função # include <iostream> usando namespace std. j). No exemplo acima foi utilizado o modelo de função GetMax () duas vezes.} 6 10 Neste caso. Mas você pode usar qualquer identificador que quiser. Portanto. j. longa l = 10. O compilador tem instanciado e chamado então cada vez que a versão apropriada da função. resultado será um objeto do mesmo tipo como os parâmetros de um e b quando o modelo é instanciado com um tipo específico. m).} int main () { int i = 5. usamos T como o nome do parâmetro do modelo. retornar 0. m = 5. em vez de myType porque é mais curto e de fato é um modelo de parâmetro de nome muito comum. n = GetMax < longo > (l. j. b). T b) { retorno (a. T b) {resultado T. modelo < classe T> T GetMax (T a. n.e é invisível para o programador. Como você pode ver. Assim. 2 Uma vez que tanto i e j são do tipo int . Este método implícito produz exatamente o mesmo resultado: 1 2 3 4 5 / / Função do modelo II # include <iostream> usando namespace std. A primeira vez com argumentos do tipo int eo segundo com argumentos do tipo longa . l i). n = GetMax (m l). n. k = GetMax (. e neste convite a ele que use objetos de dois tipos diferentes. nosso modelo de função getMin () aceita dois parâmetros de tipos diferentes e retorna um objeto do mesmo tipo do primeiro parâmetro ( T ) que é passado. j. longo > (l. não podemos chamar de nosso modelo de função com dois objetos de diferentes tipos de argumentos: 1 int i. i = getMin < int . uma vez que o compilador pode determinar a instanciação de qualquer maneira adequada. Por exemplo: 1 template < classe T. desde a nossa GetMax modelo de função espera dois argumentos do mesmo tipo. j). ambos da T tipo. Por exemplo. Nós também podemos definir a função de modelos que aceitam mais de um parâmetro do tipo. 8 longa l = 10. chamamos o nosso modelo de função GetMax () sem especificar explicitamente o tipo de ângulo entre parênteses <> . Porque a nossa função de modelo inclui apenas um parâmetro do modelo ( classe T ) e do modelo de função em si aceita dois parâmetros. k = GetMax (i. 2 longa l. 3 ou simplesmente: i = getMin (l. classe U> T getMin (T a. .6 7 int main () { int i = 5 . 9 retornar 0. 2 longa l. k = 6. embora j e l têm diferentes tipos. O compilador determina automaticamente o tipo é necessária em cada chamada. cout <<n << endl. b <b? a:). 3 Isso não seria correto. U b) { retorno (a.} 10 11 12 13 14 15 16 17 18 Note como neste caso. j. j). simplesmente especificando mais parâmetros de modelo entre os colchetes. j).} 2 3 4 Neste caso. cout <<k <<endl. m = 5. depois daquela declaração que poderíamos chamar getMin () com: 1 int i. retval = a> b? a: b. cout <<myobject. No caso de se definir uma função membro fora da declaração do modelo de classe. público : mypair (primeiro T. devemos sempre preceder a definição com o modelo <..> prefixo: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 / / Modelos de classe # include <iostream> usando namespace std. modelo < classe T> T <T> mypair: GetMax () {retval T.} int main () {mypair < int > myobject (100. esta mesma classe também seria usado para criar um objeto para armazenar qualquer outro tipo: mypair < duplo > myfloats (3. 4 5 6 7 8 9 A classe que acabamos de definir serve para armazenar dois elementos de qualquer tipo válido.}}. retorno retval. T segundo) {a = primeiro. valores [1] = 3 segundo. público : mypair (primeiro T. 36).. b = segundo. b.}.18). T segundo) {valores [0] = primeiro.} 100 . Por exemplo: 1 template < classe T> 2 classe mypair {valores de T [2].Modelos de classe Temos também a possibilidade de escrever modelos de classe. de modo que uma classe pode ter membros que utilizam parâmetros do modelo como tipos. 2.} T GetMax () . 75).getmax (). Por exemplo. retornar 0. modelo < classe T> classe mypair {T a. A função de membro somente no modelo de classe anterior foi definido em linha com a declaração de classe em si. se quiséssemos declarar um objeto desta classe para guardar dois valores inteiros do tipo int com os valores de 115 e 36 poderíamos escrever: mypair < int myobject> (115.0. vamos supor que temos uma classe muito simples chamado MyContainer que pode armazenar um elemento de qualquer tipo e que tem apenas uma função de membro chamada aumentar . int main () {MyContainer < int > myint (7). / template / aula: modelo < classe T> classe MyContainer {elemento T.} T aumento () { retorno + + elemento. cout <<myint.} Esta é a sintaxe usada no modelo de especialização da classe: .} char maiúsculas () { se (> elemento (= 'a' ) & & (<= elemento 'z' )) elemento + = 'A' . público : MyContainer (arg T) = elemento {arg. / especialização de modelo de classe: template <> class MyContainer < char > { char elemento.Observe que a sintaxe da definição de GetMax função de membro: 1 template < classe T> T <T> mypair: GetMax () 2 Confuso com tantos T s '? Há três T 's nesta declaração: O primeiro é o parâmetro do modelo.increase () < mychar.uppercase <() <<endl. Por exemplo.}}. Mas nós achamos que quando se armazena um elemento do tipo char que seria mais conveniente ter uma implementação completamente diferente com um membro da função de letras maiúsculas . E o terceiro T (o ângulo entre parênteses) é também uma exigência: Especifica que a função do modelo de parâmetro este também é o parâmetro do modelo de classe. retornar 0. o que aumenta seu valor. O segundo T se refere ao tipo retornado pela função.'a' . <MyContainer char MyChar> ( 'j' ).}}. público : MyContainer ( char arg) {arg = elemento. por isso decidimos declarar uma especialização de modelo para esse tipo de classe: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 / / Especialização modelo # include <iostream> usando namespace std. podemos declarar uma especialização desse modelo. Modelo de especialização Se queremos definir uma implementação diferente para um modelo quando um tipo específico é passado como parâmetro do modelo. retorno elemento. aviso que precede o nome do modelo de classe com um vazio template <> lista de parâmetros. é o <char> parâmetro de especialização após o nome do modelo de classe.. Este é declarar explicitamente como um modelo de especialização. devemos também definir todos os seus membros. }. o valor T). modelos também podem ter regular os parâmetros digitados.} modelo < classe T. Este parâmetro de especialização em si identifica o tipo para o qual vamos declarar uma classe de modelo de especialização ( char ). 5> myInts. T GetMember ( int x).} int main () {mysequence < int . my <<myfloats. pública : void setmember ( int x.N> mysequence: setmember ( int x.template <> class MyContainer < char > {. int N> classe mysequence {T MemBlock [N]. }. int N> <T.getmember (3) << '\ n' . modelo < classe T. 2 template <> class MyContainer < char > {.N> mysequence T :: GetMember ( int x) { retorno MemBlock [x].Observe as diferenças entre o modelo de classe genérica e especialização: 1 template < classe T> classe MyContainer {.. Antes de mais nada. Quando declaramos especializações de uma classe de modelo. int N> void <T.} . }. myints.. mysequence < duplos . modelo < classe T. 5> myfloats.} . retornar 0. A primeira linha é o modelo genérico. ter um olhar para este modelo de classe que é usado para conter sequências de elementos: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 / Template seqüência / # include <iostream> usando namespace std. o valor T) {MemBlock [x] = valor. porque não há "herança" dos membros a partir do modelo genérico para a especialização. ea segunda é a especialização. parâmetros não-tipo para modelos Além dos argumentos de modelo que são precedidas pela classe ou typename palavras-chave. Como exemplo... que representam tipos. Mas mais importante que esse prefixo..setmember (0100). semelhantes aos encontrados em funções. mesmo aqueles exatamente igual à classe de modelo genérico. Namespaces Namespaces permitem entidades do grupo. O formato de namespaces é: namespace identificador { entidades } Onde identificador é qualquer identificador válido e entidades é o conjunto de classes. quando uma instância for necessário. Naquele momento.}. isso força uma restrição para projetos multi-arquivo: a execução (definição) de uma classe de modelo ou a função deve estar no mesmo arquivo como sua declaração. Quando os projetos crescem é usual dividir o código de um programa em diferentes arquivos de código fonte. mysequence Podemos criar objetos usando os parâmetros de modelo padrão. Por exemplo: 1 namespace myNamespace { int a. Desta forma. a interface geralmente consiste de declarações dos protótipos de todas as funções que podem ser chamados. o escopo global podem ser divididos em "sub-espaços. Modelos e projetos de vários arquivos Do ponto de vista do compilador. Por exemplo. Estes são geralmente declarados em um arquivo "header" com uma extensão h. as variáveis de um e b são variáveis normais declarada dentro de um namespace chamado myNamespace . Qual seria equivalente a: mysequence < char . Nestes casos. Ea implementação (a definição dessas funções) está em um arquivo independente. objetos e funções sob um nome. int N = 10> classe {. b. Como os modelos são compilados quando requerido. Já que nenhum código é gerado até que um modelo é instanciado quando necessário. com código C + +. a interface ea implementação são geralmente separados.} 2 3 4 Neste caso. o compilador gera uma função específica para esses argumentos do modelo. objetos e funções que estão incluídos dentro do namespace. significando que o código de uma função de modelo não é compilado até uma instanciação com argumentos de modelo específico é necessário. Eles são compilados em demanda. cada uma com seu próprio nome. e que deve incluir tanto a interface e implementação em qualquer arquivo que usa os modelos. se a definição do modelo anterior de classe foram: template < classe T = char . os modelos não são funções normais ou classes. declarando: mysequence> <myseq.. Isso significa que não podemos separar a interface em um arquivo de cabeçalho separado. compiladores estão dispostos a permitir a inclusão de mais de uma vez o arquivo de mesmo modelo com as duas declarações e definições em um projeto sem gerar erros de ligação. Tomando uma biblioteca de funções como exemplo. Para acessar essas variáveis de fora domyNamespace namespace temos que usar o . como classes.Também é possível definir valores padrão ou tipos de parâmetros do modelo de classe. 10> myseq. } . usando A palavra-chave usando é usada para introduzir um nome de um espaço para a declarativa região atual. Sem erros redefinição acontecer graças aos namespaces. para acessar as variáveis anteriores de fora myNamespace podemos escrever: 1 myNamespace: um myNamespace: b 2 A funcionalidade dos namespaces é especialmente útil no caso em que há uma possibilidade de que um objeto global ou função usa o mesmo identificador como um outro. namespace primeiro { int x = 5. cout <<y <<endl. Uma delas é definida dentro do namespace primeiro e outro no segundo . usando segunda: y. int y = 10.} namespace segundo { dupla x = 3. causando erros de redefinição.} namespace segundo { dupla var = 3. retornar 0. há duas variáveis globais com o mesmo nome: var .1416. cout <<primeira: y <<endl. cout <<x <<endl. duplo y = 2.operador de escopo :: . namespace {primeiro int var = 5.1416 Neste caso. Por exemplo: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 / / Namespaces # include <iostream> usando namespace std. cout <<segunda: x <<endl. Por exemplo. retornar 0. cout <<segunda :: var <<endl.7183.} int main () { usando primeiro: x .} int main () {tribunal <<primeiro: </ var <endl.} 5 3. Por exemplo: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 / / Usando # include <iostream> usando namespace std.1416. {} usando namespace segundo. retornar 0. desde que tenham declarado que estávamos usando o primeiro espaço .} namespace segundo { dupla x = 3. se tivéssemos a intenção de usar primeiro os objetos de um namespace e então os de outro. exatamente como o nossocom as declarações especificadas. cout <<x <<endl.} Neste caso. namespace primeiro { int x = 5.7183. cout <<segunda: x <<endl.1416.} retornar 0. cout <<y <<endl.} int main () { usando namespace tribunal.} int main () {{ usando namespace em primeiro lugar.25 Note como neste código. x (sem qualquer qualificativo nome) refere-se a primeira: x Considerando que y se refere à segunda: y . A palavra-chave usando também pode ser usado como uma directiva relativa à introdução de um namespace inteiro: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 / / Usando # include <iostream> usando namespace std. cout <<se <<endl.} namespace segundo { dupla x = 3. todos os usos diretos de x e y sem qualificadores nome estava se referindo às suas declarações no primeiro espaço .} 5 3. poderíamos fazer algo como: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 / / Namespace exemplo. cout <<x <<endl. usando # include <iostream> usando namespace std. int y = 10. Nós ainda temos acesso à primeira: y e segunda: x usando seus nomes totalmente qualificados. Por exemplo. usando e usando namespace ter validade apenas no mesmo bloco em que estão estabelecidas ou em todo o código se eles são usados diretamente no escopo global. duplo y = 2. primeiro <<x <<endl.1416. namespace {primeiro int x = 5.1416 . Namespace std Todos os arquivos na biblioteca C + + padrão de declarar todas as suas entidades no std namespace. usando a palavra-chave throw de dentro do bloco try.} retorno 0. devemos colocar uma porção de código sob inspeção exceção. declaração em todos os programas que usou qualquer entidade definida no iostream . será apresentada uma exceção que transfere o controle para o manipulador de exceção. Quando uma circunstância excepcional surge dentro desse bloco. Exceção n º O código sob a manipulação de exceção é fechado em uma tentativa de bloco.} catch ( int e) {cout << "Ocorreu uma exceção Nr. Se nenhuma exceção é lançada. exceção". int main () { tentar { throw 20. Para capturar exceções. Uma expressão de jogar aceita um parâmetro (neste caso o valor inteiro 20 ). segue-se . <<e <<endl. Como você pode ver. o código continua normalmente e todos os manipuladores são ignorados.20 21 22 23 24 25 alias Namespace Podemos declarar nomes alternativos para namespaces existentes de acordo com o seguinte formato: namespace new_name current_name =. que deve ser colocado imediatamente após o bloco try: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 / / Exceção # include <iostream> usando namespace std. manipuladores de exceção são declarados com a palavra-chave catch . É por isso que geralmente incluíram o using namespace std. que é passada como um argumento para o manipulador de exceção. Isto é feito colocando a parte do código em um bloco try . Uma exceção é lançada. O manipulador de exceção é declarada com a captura de palavras-chave. Exceções Exceções fornecem uma maneira de reagir a circunstâncias excepcionais (como erros de runtime) no nosso programa de transferência de controle para funções especiais chamados manipuladores .} Uma exceção ocorreu. esse código simplesmente gera uma exceção: jogar 20. Neste exemplo. A única exceção que esta função pode lançar uma exceção do tipo int .. direta ou indiretamente lançar anexando um lancesufixo para a declaração de função: float myfunction ( char param) throw ( int ).Por exemplo: 1 tente { tentar { 2 / / Código aqui 3 } 4 catch ( int n) { 5 throw . e não após o lance indicação!.. sem argumentos.) {cout << "Exceção" . Se esse lance especificador for deixado vazio sem nenhum tipo.... que sempre tem pelo menos um parâmetro. cada uma com um tipo de parâmetro diferentes.} (. que o manipulador vai pegar qualquer exceção. e somente no caso de eles corresponderem. Nestes casos. O formato de captura é semelhante a uma função normal.} ( char param) {cout << "Exceção char" .imediatamente a chave de fechamento das tentar bloquear. Podemos encadear vários manipuladores (catch expressões). o último manipulador iria pegar qualquer exceção lançada com qualquer parâmetro que não é nem um int nem umchar . Isso pode ser usado como um manipulador padrão que captura todas as exceções não capturadas pelos manipuladores. Também é possível aninhar try-catch blocos dentro de mais externa tente blocos. pois o tipo do argumento passado pela expressão throw é marcada contra ele.) {cout << exceção padrão " " . Se usamos reticências ( .} 7 8 9 10 11 especificações de exceção Quando declarar uma função que pode limitar o tipo de exceção que possam. temos a possibilidade de que um interno de captura para a frente do bloco a excepção ao seu nível externo. isso significa que a função não é permitido . Após uma exceção tem sido tratado o programa de execução é retomada após o try-catch bloco. directa ou indirectamente. não importa qual o tipo do lance exceção é.} Neste caso. Isso é feito com a expressão throw. não pode ser capturada por um regular int tipo de manipulador. Apenas o manipulador que corresponde ao seu tipo com o argumento especificado na instrução throw é executado. se isso é especificado no passado: 1 2 3 4 5 6 tente / / } catch catch catch { código aqui ( int param) {cout << "Exceção int" . Se ele lança uma exceção com um tipo diferente. Isto declara uma função chamada myfunction que leva um agument do tipo char e retorna um elemento do tipo float .. a exceção é capturada. O tipo desse parâmetro é muito importante. ) como o parâmetro de captura .}} 6 catch (. int main ( ) { tentar { throw myex.}} myex.} retornar 0.} Meu exceção aconteceu.São eles: exceção bad_alloc bad_cast descrição Descartado pelo novo em caso de falha de alocação Descartado por dynamic_cast quando não com um tipo de referência bad_exception Descartado quando um tipo de exceção não corresponde a nenhuma das capturas bad_typeid Descartado por typeid ios_base: falha Descartado por funções na biblioteca iostream Por exemplo. exceções Standard A biblioteca C + + padrão fornece uma classe base especificamente concebido para declarar objetos a serem lançados como exceções. como o nosso myex objeto da classe MyException . operadores e destruidores. Ela é chamada de exceção e é definido no <exception> arquivo de cabeçalho sob o namespace std . uma exceção do tipo bad_alloc é lançada: . pois esta captura também classes derivadas de exceção . Nós colocamos um manipulador de exceção que pega objetos por referência (note o comercial e depois o tipo). se usamos o operador de novo ea memória não pode ser atribuído. / sem exceções permitidas / / todas as exceções permitidas 2 int myfunction ( int param). classe MyException: público exceção { virtual const char * que () const jogar () { retorno "Minha exceção aconteceu" .} catch (exceção & e) {tribunal <<e.what () <<endl. Essa classe tem o padrão normal e copiar os construtores.Funções sem jogar especificador (funções regulares) estão autorizados a lançar exceções de qualquer tipo: 1 int myfunction ( int param) throw (). além de uma função membro virtual adicional chamado o que retorna uma seqüência de caracteres NULL-finalizada ( char * ) e que pode ser substituído em classes derivadas para conter algum tipo de descrição do exceção. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 / / Exceções padrão # include <iostream> # include <exception> usando namespace std.lançar exceções. Todas as exceções geradas por componentes da biblioteca C + + padrão lançar exceções derivadas deste std: exceção: classe. que afetam as classes que incluem construtores ou funções específicas do operador para realizar conversões. No meu sistema. As conversões implícitas incluem também construtor ou operador de conversões. Se quiser forçar uma bad_alloc exceção para vê-lo em ação. tais como a conversão entre tipos numéricos ( curto para int .1 tente 2 { int * myarray = novos int [1000]. dobro para int . que o compilador pode sinalizar com uma advertência. Por exemplo: 1 curto = 2000. Isto pode ser evitado com uma conversão explícita. o valor de um foi promovido a partir curto para int e nós não tivemos que especificar qualquer tipo de vazamento do operador. int para float ." <<endl.} 4 5 6 7 8 Recomenda-se incluir todas as alocações de memória dinâmica dentro de um bloco try que trava esse tipo de exceção para realizar uma ação de limpeza em vez de uma finalização anormal do programa. Isso é conhecido como uma conversão padrão. ou de bool .} catch (exceção & e) {cout << "exceção padrão: " <e. bem como permitir conversões. b = a. um 2 int b. Por exemplo: . podemos lidar com essa mesma exceção pegando referências àexcepção da classe: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 / / Padrão de exceção bad_alloc <iostream> # include # include <exception> usando namespace std. você pode tentar alocar uma enorme variedade.} Tipo casting Convertendo a expressão de um determinado tipo em outro tipo é conhecido como tipo-casting .} retornar 0.. conversões Standard afetam os tipos de dados fundamentais.). que é o que acontece quando esse tipo de exceção é lançada e não pegou. Porque bad_alloc é derivado do padrão da classe base exceção . Algumas destas conversões pode implicar uma perda de precisão. int main () { tentar { int * myarray = novos int [1000]. Nós já vimos algumas maneiras de conversão de tipo: Conversão implícita As conversões implícitas não requerem qualquer operador.what <() <<endl.000 milhões int s jogou uma bad_alloc exceção. 3 Aqui. e algumas conversões de ponteiro. Eles são executados automaticamente quando o valor é copiado para um tipo compatível..} 3 catch (bad_alloc &) {cout << "Erro ao alocar memória. tentando alocar 1. int main () {CDummy d. em seguida. mas. independentemente dos tipos eles apontam. público : CAddition ( int a. classe CDummy { float i. o código a seguir está sintaticamente correta: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 / / Classe do tipo-casting # include <iostream> usando namespace std. como a notação 2 int b. pois B tem um construtor que leva um objeto da classe A como parâmetro. conversão explícita C + + é uma linguagem fortemente tipada. 2 classe B { público : B (A a) {}}. No entanto. b = ( int ) a.} int resultado () { retorno x + y. CAddition * padd. / funcional notação / 3 b = int (a). Já vimos duas notações para a conversão explícita: funcional e c-como a seleção de elenco: 1 short a = 2000. / c-cast. y = b. = a b a A. Tradicional explícita tipo de fundição permite converter qualquer ponteiro ponteiro em qualquer outro tipo. que pode levar a um código que ao ser sintaticamente correta pode causar erros de execução. retornar 0. A chamada subseqüente ao membro resultado vai produzir tanto um erro em tempo de execução ou de um resultado inesperado. .}. especialmente aqueles que implicam uma interpretação diferente do valor. necessitam de uma conversão explícita. int b) {x = a. padd = (CAddition *) &D. 4 A funcionalidade destes operadores de conversão explícita é suficiente para a maioria das necessidades de tipos de dados fundamentais. Por exemplo. Muitas conversões. ele atribui a ele uma referência a um objeto de outro tipo incompatível com explícita tipo-casting: padd = (CAddition *) &D. estes operadores podem ser aplicados indiscriminadamente em classes e ponteiros para classes. cout padd-> resultado <(). B.1 class A {}.} O programa declara um ponteiro para CAddition . Portanto conversões implícitas de um para B são permitidos. j. uma conversão implícita aconteceu entre os objetos da classe A e classe B . y. 3 4 5 Aqui.}}. classe CAddition { int x. Para controlar esses tipos de conversões entre as classes. CDerived d. what (). dynamic_cast realiza uma verificação especial durante o tempo de execução para garantir que a expressão produz uma completa válido objeto da classe solicitada: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 / / Dynamic_cast <iostream> # include # include <exception> usando namespace std. static_cast e const_cast . cBase pb *. temos quatro operadores de casting específico: dynamic_cast . a expressão a ser convertido entre parênteses. se (pd == 0) cout << "ponteiro nulo no segundo tipo fundido" <<endl. pd = dynamic_cast <CDerived*> (PBA). se (pd == 0) cout << "ponteiro nulo no primeiro tipo fundido" <<endl. / / ok: derivado-a-base pd = dynamic_cast <CDerived*> (& b). classe cBase { virtual void dummy () {}}.} retornar 0. Sua finalidade é garantir que o resultado da conversão de tipo é um objeto válido completo da classe solicitada. neste pedaço de código produziria um erro de compilação desde a derivados de conversões de base não são permitidas com dynamic_cast a menos que a classe base é polimórfico. Portanto. Quando uma classe é polimórfico.} catch (exceção & e) {cout << "Exceção:" <<e . reinterpret_cast . int main () { tentar {cBase * pba = novo CDerived. O seu formato é seguir o novo tipo de ângulo fechado entre colchetes ( <> ) e logo após. classe CDerived: público cBase { int a.}. <new_type> <new_type> <new_type> <new_type> dynamic_cast (expressão) reinterpret_cast (expressão) static_cast (expressão) const_cast (expressão) Os equivalentes a tradicional carcaça tipo para essas expressões seriam: (New_type) expressão new_type (expressão) mas cada um com suas próprias características especiais: dynamic_cast dynamic_cast pode ser usado somente com ponteiros e referências a objetos. cBase b.} Ponte . CDerived * pd. cBase * PBB = novo cBase. / / errado: base para derivados A segunda conversão. CDerived * pd. dynamic_cast sempre é bem sucedida quando lançamos uma classe para uma das suas classes base: 1 2 3 4 5 6 7 8 classe cBase {}. pd = dynamic_cast <CDerived*> (PBB). classe CDerived: público cBase {}. pb = dynamic_cast <CBase*> (& d). O código tenta executar duas dinâmicas lança a partir de objetos do tipo ponteiro * cBase ( PBA e PBB ) para um objeto do tipo ponteiro CDerived * . porque não é um objeto completo do requerido de classe como a conversão em segundo lugar no exemplo anterior. enquanto PBB está apontando para um objeto da classe cBase . static_cast também pode ser usado para executar qualquer não-ponteiro conversão de outros que também poderiam ser realizados implicitamente. não só da classe derivada de sua base. se dereferenced. Este deve estar habilitado para a verificação de tipo em tempo de execução usando dynamic_cast para funcionar corretamente. Se dynamic_cast é usado para converter para um tipo de referência e na conversão não for possível. mas também de uma classe base de seus derivados. cBase * a = nova cBase. 4 Isso seria válido. . mas não há verificação de segurança durante a execução é realizada para verificar se o objeto a ser convertido é de fato um objeto completo do tipo de destino. Por outro lado. uma exceção do tipo bad_cast é acionada em seu lugar. e também pode lançar qualquer tipo de ponteiros para ponteiros ( void * ). 2 classe CDerived: público cBase {}. mesmo entre os ponteiros para classes independentes.23 Nota de Compatibilidade: dynamic_cast requer o Run-Time Type Information (RTTI) para manter o controle dos tipos de dinâmicas. Assim. dynamic_cast também pode lançar ponteiros nulos. quando as respectivas tipo de peças fundidas são realizadas usando dynamic_cast .14159265. enquanto PBB aponta para um objeto do tipo cBase . Portanto. a sobrecarga dos controlos de segurança do tipo de dynamic_cast é evitado. que é um objeto da classe incompleta CDerived . mas só o primeiro é bem sucedida. ele retorna um ponteiro nulo para indicar a falha. PBB cBase * = nova cBase. Observe as suas respectivas inicializações: 1 CBase pba * = nova CDerived. pba está apontando para um objeto cheio de classe CDerived . 1 classe cBase {}. é responsabilidade do programador para garantir que a conversão é segura. Alguns compiladores suportam esse recurso como uma opção que está desabilitada por padrão. CDerived * b = static_cast 3 <CDerived*> (a). como por exemplo a conversão de padrão entre os tipos fundamentais: 1 dupla d = 3. apesar de b seria apontar para um objeto da classe incompleta e poderia levar a erros de execução. 2 int i = static_cast < int > (d). static_cast static_cast pode realizar conversões entre os ponteiros para classes relacionadas. Isso garante que pelo menos as classes são compatíveis se o próprio objeto é convertido. pba aponta para um objeto do tipo CDerived . Quando dynamic_cast não pode converter um ponteiro. 2 Mesmo que ambos são indicadores do tipo * cBase . portanto.Ou qualquer conversão entre classes com construtores explícitos ou funções de operador conforme descrito em "conversões implícitas" acima. As conversões que podem ser executadas por reinterpret_cast mas não por static_cast não têm usos específicos. O resultado da operação é um binário simples cópia do valor de um ponteiro para o outro. B = b * reinterpret_cast <B*> (a). portanto. é concedido a poder ser lançado de volta para um ponteiro válido. já que agora temos um ponteiro que aponta para um objeto de uma classe de incompatibilidade e. impressão ( const_cast < char * > (c)). cuja interpretação resulta em um código. a e b s . Todas as conversões de ponteiro são permitidos: nem o conteúdo apontado nem o tipo de ponteiro em si é marcada. O formato em que este valor representa um ponteiro inteiro é específico de plataforma. A * a = nova A. em C + + são operações de baixo nível. dereferencing é inseguro. seja para fixar ou a ser removido. void print ( char * str) {cout <<str <<endl.} texto typeid typeid permite verificar o tipo de uma expressão: typeid (expressão) Este operador retorna uma referência a um objeto de constante do tipo type_info que é definido no cabeçalho do arquivo padrão <typeinfo> . Este valor retornado pode ser comparada com outra usando os operadores == e ! = ou pode servir para obter uma seqüência terminada por caractere nulo que representa o tipo de dados ou nome da classe usando o seu nome () membro. apesar de não fazer muito sentido. A única garantia é que um pointer cast para um tipo inteiro grande o suficiente para contê-la plenamente. para passar a const argumento para uma função que espera um parâmetro de não-constante: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 / / Const_cast # include <iostream> usando namespace std. Por exemplo. não-portáteis. Por exemplo: 1 class A {}. 2 classe B {}. 3 4 Isto é válido C + + código. Ele também pode converter ponteiros ou de tipos inteiros.} int main () { const char * c = "texto de exemplo" . que geralmente é específico do sistema e. reinterpret_cast reinterpret_cast converte qualquer tipo de ponteiro para ponteiro qualquer outro tipo. retornar 0. 1 2 3 4 / / Typeid <iostream> # include # include <typeinfo> usando namespace std. mesmo de classes independentes. const_cast Este tipo de vazamento manipula o constness de um objeto. 5 6 int main () { int * a, b, a = 0, b = 0; 7 se ( typeid (a) =! typeid (b)) { cout << "a e b são de diferentes tipos: \ n" ; cout << "é:" << 8 typeid (a) <. name () < '\ n' ; cout << "b é:" < < typeid b). (nome () << '\ n' ;} 9 retornar 0;} 10 11 12 13 14 15 16 Quando typeid é aplicada às classes typeid usa o RTTI para controlar o tipo de objetos dinâmicos. Quando typeid é aplicado a uma expressão cujo tipo é uma classe polimórfica, o resultado é o tipo de derivado objeto mais completa: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 / / Polimórficos, classe typeid <iostream> # include # include <typeinfo> # include <exception> usando namespace std; classe cBase { virtual void f () {}}; classe CDerived: público cBase {}; int main () { tente cBase * {a = nova cBase; cBase b * = nova CDerived; cout << "é:" << typeid (a) <. name () < '\ n' (nome () << '\ n' ; cout << "* é:" << typeid (* a) <. name () < '\ n' ; cout << "b * é : " << typeid b *) (exceção & e) {cout << "Exceção:" <e.what <() <<endl;} retornar 0;} Observe como o tipo que typeid considera para ponteiros é o tipo de ponteiro em si (tanto um e b são do tipo classe cBase * ). No entanto, quando typeid é aplicado a objetos (como a * e * b ) typeid produz seu tipo dinâmico (ou seja, o tipo de seus derivados objeto mais completa). Se o tipo de typeid avalia é um ponteiro precedido pelo operador dereference ( * ), e este ponteiro tem um valor nulo, typeid lança um bad_typeid exceção. directivas Preprocessor directivas Preprocessor são linhas incluídas no código dos nossos programas que não são declarações do programa, mas diretrizes para o pré-processamento. Estas linhas são sempre precedidas por um cardinal ( # ). O pré-processador é executado antes da compilação real de código começa, portanto, o pré-processador digere todas estas diretrizes antes de qualquer código é gerado pelas declarações. Estas directivas de pré-processamento abrange apenas através de uma única linha de código. Assim como um caractere de nova linha é encontrada, a directiva de pré-processamento é considerada como final. Nenhum ponto e vírgula (;) é esperado no final de uma directiva de pré-processamento. A única forma de uma directiva de pré-processamento pode se estender por mais de uma linha é precedendo o caractere newline no final da linha por uma barra invertida ( \ ). definições de macro (# define, # undef) Para definir macros pré-processamento, podemos usar # define . Seu formato é: # Define identificador de substituição Quando o pré-processador encontra presente directiva, que substitui qualquer ocorrência de identificador no resto do código por substituição . Esta substituição pode ser uma expressão, uma declaração, um bloco ou simplesmente nada. O pré-processador não entende C + +, ele simplesmente substitui qualquer ocorrência de identificador de substituição . 1 # Define TABLE_SIZE 100 2 int table1 [TABLE_SIZE]; 3 int tabela2 [TABLE_SIZE]; Após o pré-processador substitui TABLE_SIZE , o código torna-se equivalente a: 1 int table1 [100], 2 int tabela2 [100]; Este uso de # define como definidor constante já é conhecido por nós de tutoriais anteriores, mas # define pode trabalhar também com os parâmetros para definir macros de função: # Define GetMax (a, b) a, b> a:? B Isso substituir qualquer ocorrência de GetMax seguido por dois argumentos a expressão de substituição, mas também substituindo cada argumento por seu identificador, exatamente como seria de esperar se fosse uma função: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 / / Macro função # include <iostream> usando namespace std; # define GetMax (a, b) ((a)> (b):? (a) (b)) int main () { int x = 5, y; y = GetMax (x, 2); cout <<y <<endl; cout <<GetMax (7, x) <<endl; retornar 0;} 5 7 macros definido não são afetados pela estrutura do bloco. Uma macro dura até que é indefinido com a directiva de pré-processamento # undef: 1 2 3 4 5 # Define TABLE_SIZE 100 int table1 [TABLE_SIZE]; # undef TABLE_SIZE # define TABLE_SIZE 200 int tabela2 [TABLE_SIZE]; Isto irá resultar no mesmo código: 1 int table1 [100], 2 int tabela2 [200]; As definições de função macro aceitar dois operadores especiais ( # e # # ) na seqüência de substituição: Se o operador # é usado antes de um parâmetro é usado na seqüência de substituição, esse parâmetro é substituído por uma seqüência literal (como se fosse entre aspas duplas) 1 # Define str (x) # x 2 cout <<str (teste); Isso seria traduzido em: Cout << "teste" ; O operador # # concatena dois argumentos não deixando espaços em branco entre eles: 1 # Define cola (a, b) um # # b 2 cola (c, a) << "teste" ; Isto também ser traduzido em: Cout << "teste" ; Porque as substituições de pré-processamento acontecer antes de qualquer C + + verificar a sintaxe, as definições de macro pode ser uma característica difícil, mas tenha cuidado: um código que depende fortemente de macros complicadas podem parecer obscuras para outros programadores, uma vez que a sintaxe que eles esperam é, em muitas ocasiões diferentes das expressões regulares programadores esperam em C + +. inclusões condicional (# ifdef, # ifndef, # if, # endif, # else e # elif) Essas diretrizes permitem incluir ou descartar parte do código de um programa, se uma determinada condição seja atendida. # ifdef permite uma seção de um programa a ser compilado somente se a macro que é especificado como o parâmetro foi definido, não importa qual o seu valor. Por exemplo: 1 # Ifdef TABLE_SIZE 2 int tabela [TABLE_SIZE]; 3 # endif Neste caso, a linha de código int tabela [TABLE_SIZE]; só é compilado se TABLE_SIZE foi previamente definido com # define , independentemente do seu valor. Se não foi definida, essa linha não será incluída na compilação do programa. respectivamente. Linha de comando (# line) Ao compilar um programa e um erro acontece durante o processo de compilação.# Ifndef serve para o exato oposto: o código entre # ifndef e # endif directivas só é compilado se o identificador especificado não foi previamente definido. # elif e # else directivas acorrentado termina com # endif . seria manter o valor anterior já que o # define directiva não seria executado. por isso é mais fácil encontrar o código gerando o erro. quando chegar a este pedaço de código. incluindo expressões macro. em qualquer # if ou # elif directiva: 1 2 3 4 5 if! # definido TABLE_SIZE # define TABLE_SIZE 100 # elif definido ARRAY_SIZE # define TABLE_SIZE ARRAY_SIZE int tabela [TABLE_SIZE]. que seria definida como um valor de 100. os números de linha dentro do código de arquivos. # else e # elif (ou seja. o compilador mostra uma mensagem de erro com referências ao nome do arquivo onde o erro ocorreu e um número de linha. se. Por exemplo: . Os números de linha de sucessivas linhas será aumentado um por um a partir deste ponto. A condição que segue # if ou # elif só pode avaliar expressões constantes. Observe como toda a estrutura de # if . bem como o nome do arquivo que queremos que aparece quando um erro ocorre. Se ele já existisse. O # if . A linha # directiva permite-nos controlar ambas as coisas. Seu formato é: # Número da linha "filename" Onde número é o número da linha nova que será atribuído para a linha de código seguinte. o TABLE_SIZE macro não foi definido ainda. Neste caso. Por exemplo: 1 2 3 4 # TABLE_SIZE ifndef # define TABLE_SIZE 100 # endif int tabela [TABLE_SIZE]. O comportamento do # ifdef e # ifndef também pode ser conseguido usando os operadores especiais definidos e definidos! . "Nome" é um parâmetro opcional que permite redefinir o nome do arquivo que será mostrado. Por exemplo: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 # If TABLE_SIZE> 200 # undef TABLE_SIZE # define TABLE_SIZE 200 # elif TABLE_SIZE <50 # undef TABLE_SIZE # define TABLE_SIZE 50 # # # # else undef TABLE_SIZE define TABLE_SIZE 100 endif int tabela [TABLE_SIZE]. "else if") as directivas servem para especificar algumas condições a serem cumpridas para que a parte do código que cercam a ser compilado. nenhum erro é gerado. . os arquivos de cabeçalho padrão são normalmente incluídos no ângulo entre parênteses. Se o compilador não oferece suporte a um argumento específico para o # pragma . contendo a data em que começou o processo de compilação. Consulte o manual ou a referência do seu compilador para obter mais informações sobre os possíveis parâmetros que podem ser definidos com # pragma . Pragma directiva (# pragma) Esta diretiva é usada para especificar diversas opções para o compilador. Essas opções são específicas para a plataforma e compilador que você usa. gerando uma compilação de erros que pode ser especificado como parâmetro: 1 # __cplusplus Ifndef 2 # Um erro de compilador C + + é necessário! 3 # endif Este exemplo aborta o processo de compilação se o nome da macro __cplusplus não está definido (este nome de macro é definido por padrão em todos os compiladores C + +). enquanto outros arquivos de cabeçalho específicos estão incluídos o uso de aspas. o arquivo é procurado no mesmo diretório que inclui o arquivo que contém a directiva. No primeiro caso. Uma string literal contendo o nome da presumida do arquivo fonte a ser compilado. é ignorado . Fonte arquivo de inclusão (# include) Esta directiva também tem sido usado assiduamente em outras seções deste tutorial. Se o nome do arquivo é colocado entre parênteses de ângulo > < o arquivo é procurado diretamente onde o compilador está configurado para procurar pelos arquivos de cabeçalho padrão. Há duas maneiras para especificar um arquivo para ser incluído: 1 # Include "arquivo" 2 # include <file> A única diferença entre as duas expressões são os locais (diretórios) onde o compilador vai olhar para o arquivo. Predefinidos nomes de macro Os nomes de macro a seguir são definidos a qualquer momento: macro __LINE__ __FILE__ __DATE__ valor Valor inteiro que representa a linha atual do arquivo de código fonte a ser compilado. onde o nome do arquivo é especificado entre aspas.1 # Linha 20 "variável atribuindo" 2 int a?. No caso de que ele não está lá. directiva de erro (erro #) Esta directiva aborta o processo de compilação quando ele for encontrado. Este código irá gerar um erro que será mostrado como erro no arquivo "variável de atribuição" . Portanto. sob a forma "Mmm dd / aaaa". Quando o préprocessador encontra um # include directiva substitui-lo por todo o conteúdo do arquivo especificado. linha 20. o compilador procura o arquivo no diretório padrão onde ele está configurado para procurar pelos arquivos de cabeçalho padrão. Uma seqüência literal. "\ n " . Nós já usamos objetos cujos tipos eram essas classes: cin é um objeto da classe istream e tribunal é um objeto da classe ostream . retornar 0. já estamos utilizando as classes que estão relacionadas com o nosso arquivo de córregos. <<myfile escrevendo isso para um arquivo. cout << "do arquivo" <<__FILE__ << . cout << "a" <<__TIME__ << "n \". myfile. Mas vamos ir passo a passo: .__TIME__ Uma seqüência literal. int main () {ofstream myfile. cout << "Sua elaboração começou" <__DATE__ <. Um valor inteiro. direta ou indiretamente das classes istream e ostream . .open ( "example.} E c Entrada / Saída com arquivos C + + fornece as seguintes classes para realizar a saída ea entrada de caracteres para / de arquivos: y y y ofstream: classe Stream para escrever em arquivos ifstream: classe Stream para ler arquivos fstream: classe Stream para ler e escrever de / para arquivos. myfile. com a única diferença que temos de associar esses riachos com arquivos físicos.} [Arqu Esse código cria um arquivo chamado example. int main () {cout << "Este é o número da linha" <<__LINE__.close (). Vamos ver um exemplo: 1 2 3 4 5 6 7 8 9 10 11 12 / / Operações básicas com arquivos # include <iostream> # include <fstream> usando namespace std. Essas classes são derivadas.txt" ). "\ n" . sob a forma "hh: mm: ss" com o momento em que começou o processo de compilação. cout << "O compilador dá um valor __cplusplus de" <__cplusplus <. podemos usar o nosso arquivo de córregos da mesma forma que já são usados para usar cin e judiciais . Therfore. retornar 0. Todos os compiladores C + + tem este constante definida para algum valor. E. Se o __cplusplus compilador é totalmente compatível com o padrão C + + o seu valor for igual ou superior a 199711L dependendo da versão da norma que respeitar. Por exemplo: 1 2 3 4 5 6 7 8 9 10 11 12 13 / / Padrão de nomes de macro # include <iostream> usando namespace std. de fato. mas usando o fluxo de arquivo myfile vez.txt e insere uma frase para ele da mesma maneira que estamos acostumados a ver com a tribunal . open ( "example. sem um segundo argumento: classe parâmetro modo padrão ofstream ios:: out ifstream ios:: in fstream ios:: in | ios:: out Para ifstream e ofstream classes. Todos estes sinalizadores podem ser combinados usando o operador OR bit a bit ( | ). 2 Cada um dos (aberto) funções de membro das classes ofstream . ifstream e fstream tem um modo padrão que é usada se o arquivo é aberto. ios:: out | ios:: app | ios:: binary). Este procedimento é conhecido como a abrir um arquivo . Onde nome é uma seqüência terminada por caractere nulo do tipo char * const (do mesmo tipo que tem strings literais). Todas as operações de saída são realizadas no final do arquivo. anexando o conteúdo com o conteúdo ios:: app atual do arquivo. Se este sinalizador não estiver definido para qualquer valor. seu conteúdo anterior é apagado e substituído por um novo. mesmo que de um modo que não incluí-los é passado como segundo argumento para o open () função de membro. Por exemplo. Esta bandeira só pode ser usada em correntes abertas para as operações de saída apenas. que representa o nome do arquivo a ser aberto. ios:: trunc Se o arquivo aberto para operações de saída já existia antes. se queremos abrir o arquivo example. não .bin em modo binário para adicionar dados que poderia fazê-lo pelo seguinte chamada para função de membro do open () : 1 ofstream myfile. myfile. a posição inicial é o começo do arquivo. este foi myfile ) e qualquer operação de entrada ou de saída realizada sobre este objeto de fluxo será aplicado ao arquivo físico que lhe estão associados . O valor padrão é aplicado somente se a função é chamada sem especificar qualquer valor para o parâmetro mode. eo modo é um parâmetro opcional com uma combinação das seguintes bandeiras: ios:: in Aberto para as operações de entrada. Defina a posição inicial no final do arquivo. ios:: binary ios:: comeu Abra no modo binário. ios:: in e ios:: out . Se a função é chamada com qualquer valor nesse parâmetro o modo padrão é substituído. Para abrir um arquivo com um objeto de fluxo que usamos a função de membro do open () : open (filename.bin" . um objeto de fluxo (uma instância de uma dessas classes. ios:: out Aberto para as operações de saída. no exemplo anterior. Um arquivo aberto é representado por um programa. respectivamente. estão automaticamente e assumiu. mode).Abrir um arquivo A primeira operação executada em um objeto de uma dessas classes é associá-lo a um arquivo real. Esses arquivos são projetados para armazenar texto e.close (). Arquivos de texto arquivo de texto correntes são aqueles em que não incluem o ios:: binary bandeira no seu modo de abertura. essas três classes incluem um construtor que chama automaticamente o open () função de membro e tem os mesmos parâmetros exatamente como esse membro. Esta função de membro retorna um valor bool da verdade no caso que de fato o objeto stream está associado a um arquivo aberto. . Para verificar se um fluxo de arquivo foi bem-sucedida abertura de um arquivo. Desde a primeira tarefa que é executada em um objeto de fluxo de arquivos é geralmente para abrir um arquivo. eo arquivo está disponível novamente para ser aberto por outros processos. No caso em que um objeto é destruído enquanto ainda associado a um arquivo aberto.txt" ). que não necessariamente correspondem às suas binário valor literal. e algumas traduções podem ocorrer devido a formatação de alguns caracteres especiais (como a nova linha e caracteres de retorno de carro).combinado.close (). e que ele faz é para liberar os buffers associados e feche o arquivo: myfile. continue com saída * / } Fechando um arquivo Quando terminarmos com a nossa entrada e saída de operações em um arquivo devemos fechá-lo para que seus recursos estejam disponíveis novamente. Uma vez que esta função membro é chamado. se (myfile. <<myfile "é outra linha. o objeto de fluxo pode ser usado para abrir um outro arquivo.is_open ()) { / * ok. portanto. Ambas as formas de abrir um arquivo são válidos e equivalentes. o destruidor chama automaticamente a função de membro close () . Este \ n" . ios:: out | ios:: app | ios:: binary). Combinando a construção do objeto e da abertura de fluxo em uma única instrução. A fim de fazer isso temos que chamar o fluxo da função de membro close () . Fluxos de arquivo aberto em modo binário e executar operações de entrada e de saída independentemente de quaisquer considerações formato. Esta função de membro leva sem parâmetros. Portanto. myfile. todos os valores que a entrada ou saída de / para eles pode sofrer algumas transformações de formatação.bin" . retornar 0. operações de saída de dados em arquivos de texto são executadas da mesma maneira que nós operamos com tribunal : 1 2 3 4 5 6 7 8 9 / / Escrita em um arquivo de texto <iostream> # include # include <fstream> usando namespace std. você pode fazê-lo.is_open ()) {myfile << "Este é uma linha n \ ". também poderíamos ter declarado o anterior myfile objeto e conduziu a operação de abertura mesmo em nosso exemplo anterior. ou false caso contrário: se (myfile. int main () {myfile ofstream ( "example. por escrito: myfile ofstream ( "example. Binário arquivos não são conhecidos como arquivos de texto . chamando ao membro nome esta_aberta () sem argumentos.} [Examp .} mais cout << "Não foi possível abrir o arquivo" . no caso em que tentamos escrever para um arquivo que não está aberto para a escrita ou se o dispositivo em que tento escrever não tem espaço sobrando. Criamos um laço while que termina quando na verdade myfile. se (myfile. Verificando as bandeiras do estado Além de bom () .is_open () ) { tempo (myfile.good ()) {getline (linha.} mais cout << "Não foi possível abrir o arquivo" . eof () Retorna true se um arquivo aberto para leitura chegou ao fim.txt" ). int main () {string linha. bom () .close (). myfile). mas também no caso de um erro de formato acontece. retornar 0. myfile ifstream ( "example. Por exemplo.10 11 12 13 14 15 16 A entrada de dados de um arquivo também pode ser realizada da mesma forma que fizemos com cin : 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 / / Ler um arquivo de texto <iostream> # include # include <fstream> # include <string> usando namespace std. Observe como usamos uma função de membro novo. como quando um caractere alfabético é extraído quando estamos a tentar ler um número inteiro. que verifica se o fluxo está pronto para / saída de operações de entrada. chamado bom () que retorna verdadeiro no caso em que o fluxo está pronto para / saída de operações de entrada. existem outras funções de membro para verificar a estados específicos de um riacho (todos eles retornam um valor booleano): ruim () Retorna true se uma operação de leitura ou gravação falha.} Esta Este último exemplo lê um arquivo texto e imprime seu conteúdo na tela. fail () Retorna true nos mesmos casos tão ruim ().good () não é mais verdade.} myfile. cout <linha <<<endl. o que vai acontecer ou se o fim do arquivo foi alcançado ou se algum outro erro ocorreu. O protótipo outros para estas funções é: seekg (offset. um ponteiro de fluxo interno: ifstream . chegar e colocar os ponteiros fluxo Tudo o que eu / o córregos objetos têm. . herda tanto. Finalmente. ofstream . tem um ponteiro conhecido como o ponteiro começar que aponta para o elemento a ser lido na próxima operação de entrada. contados do término do fluxo O exemplo a seguir usa as funções de membro que acabamos de ver para obter o tamanho de um arquivo: 1 2 3 4 / / Tamanho do ficheiro obtenção <iostream> # include # include <fstream> usando namespace std. que leva sem parâmetros. seekg () e seekp () Estas funções permitem alterar a posição dos ponteiros stream get e put. E direção é do tipo seekdir . O tipo para este parâmetro é o mesmo que aquele retornado por funções tellg e tellp : o tipo de membro pos_type . que é um valor inteiro. O primeiro protótipo é: seekg (posição). Esses ponteiros internos córrego que apontam para a leitura ou escrita locais dentro de um fluxo pode ser manipulado usando as funções de membro a seguir: tellg () e tellp () Estas duas funções de membro não tem parâmetros e retorna um valor do tipo membro pos_type .É a bandeira do estado mais genérico: ele retorna false nos mesmos casos em que chamar qualquer uma das funções anteriores retornaria verdadeiro. contados a partir do fluxo de ios:: act offset contados a partir da posição atual do ponteiro de fluxo ios:: end offset. tem um ponteiro conhecido como o ponteiro colocado que aponta para o local onde o elemento seguinte tem de ser escrito. como istream . que é um tipo de dados inteiro que representa a posição atual do ponteiro do stream get (no caso de tellg ) ou o ponteiro de fluxo de venda (no caso de tellp ). a chegar e colocar os ponteiros. que também é um tipo inteiro. fstream . offset é do tipo membro off_type . a posição do ponteiro ou colocar recebe é definido para um valor de deslocamento em relação a algum ponto específico determinado pelo parâmetro sentido . Ambas as funções são sobrecarregadas com dois tipos de protótipos. como ostream . seekp (offset. A fim de restaurar as bandeiras de estado marcado por qualquer dessas funções membro já vimos que podemos usar a função de membro clear () . direção). pelo menos. que é um tipo enumerado ( enum ) que determina o ponto de onde é contada a partir de deslocamento. Usando este protótipo do ponteiro de fluxo é alterado para a posição absoluta posição (contando a partir do início do arquivo). Usando este protótipo. seekp (posição). direção). de iostream (que é derivada de ambos os istream e ostream ). e que pode ter qualquer dos seguintes valores: ios:: beg compensado. begin = myfile. int main () {ifstream arquivo ( "example. Objetos da classe fstream têm ambos os membros. MemBlock = novo char [tamanho]. onde os elementos de dados são armazenados ou lidos a partir do qual os elementos de dados a serem gravados são tomadas. Seus protótipos são: write (tamanho memory_block). retornar 0. retornar 0.tellg = (). \" . 6 7 cout << "O tamanho é:" <<(fim-de começar) << "n bytes. já que não precisam de qualquer formato de dados. etc .tellg (). e os dados não podem utilizar os códigos usados por separação arquivos de texto para separar os elementos (como..bin" . Onde memory_block é do tipo "ponteiro para char ( char * ). myfile. leia (tamanho memory_block).seekg (0. espaço. E ler é uma função membro de istream que é herdado porifstream . ifstream:: size pos_type.} mais cout << "Não foi possível abrir o arquivo" .txt" ). file. myfile ifstream ( "example. newline. e representa o endereço de um array de bytes. se (file.seekg (0. Vamos examinar como isso é feito: . 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 / / Ler um arquivo binário completo <iostream> # include # include <fstream> usando namespace std. ios:: be cout << "o conteúdo do arquivo completo está na memória" . excluir MemBlock] [. O primeiro ( escrever ) é uma função de membro do ostream herdada por ofstream .5 int main () { tempo com início e final.is_open ()) {tamanho file. O tamanho do parâmetro é um valor inteiro que especifica o número de caracteres a ser lida ou escrita de / para o bloco de memória. o arquivo inteiro é lido e armazenado em um bloco de memória. Fluxos de arquivo incluem duas funções de membro projetado especificamente para entrada e saída de dados binários em seqüência: escrever e ler . ios:: in | ios:: binary | ios:: comeu). char MemBlock *. para entrada e saída de dados com os operadores de inserção e extração ( << e > ) e funciona como getline não é eficiente.). } 8 9 10 11 12 13 14 15 Os arquivos binários Em arquivos binários.} Neste exemplo. Dessa forma. Caso contrário (se o buffer corrente foi sincronizada com êxito) ele retorna 0 . quando chamamos ao membro tellg () . todos os dados contidos nele são gravados no meio físico (se é um fluxo de saída). Amortecedores e sincronização Quando operar com fluxos de arquivo.tellg) (). pedimos a atribuição de um bloco de memória grande o suficiente para manter o arquivo inteiro: MemBlock = novo char [tamanho]. Quando o buffer estiver cheio. o que significa que o ponteiro começa será posicionado no final do arquivo. finalmente.read (tamanho MemBlock). Nosso programa simplesmente anuncia que o conteúdo do arquivo está na memória e depois termina. Este buffer é um bloco de memória. o personagem não foi escrita diretamente para o arquivo físico com o qual o fluxo é associado. Estes manipuladores são: flush e endl . file.Primeiro. cada vez que a função de membro colocar (que escreve um único personagem) é chamado. em seguida. 2 3 Neste ponto. Este processo é chamado de sincronização e tem lugar em qualquer das seguintes circunstâncias: y y y y Quando o arquivo é fechado: antes de fechar um arquivo de todos os buffers que ainda não foram liberados estão sincronizados e todos os dados pendentes são escritos ou lidos ao meio físico.: ifstream: ifstream:: pos_type é um tipo específico usado para o posicionamento e arquivo de buffer e é o tipo retornado por file. Quando o buffer é liberado. com um ofstream . Em vez disso. Explicitamente.close (). ou simplesmente libertado (se é um fluxo de entrada). poderia operar com os dados obtidos a partir do arquivo. que age como intermediário entre o fluxo eo arquivo físico. Para um arquivo com um tamanho de 2GB em que poderíamos usar int : 1 int size. com manipuladores: Quando certos manipuladores são utilizados em rios. ios:: beg). File. por isso podemos realizar nela as mesmas operações que realizamos sobre qualquer outro valor inteiro. Este tipo é definido como um tipo inteiro. 2 Uma vez que tenhamos obtido o tamanho do arquivo. Logo depois.seekg (0. o personagem está inserido no buffer de fluxo de intermediários que. uma sincronização explícita ocorre. fechá-lo: 1 file. Quando o buffer está cheio: amortecedores têm um determinado tamanho. faz uma sincronização imediata. Explicitamente. o arquivo é aberto com o ios:: comeu bandeira. size = ( int file.tellg () . e pode seguramente ser convertidos para outro tipo inteiro grande o suficiente para conter o tamanho do arquivo. . Esta função retorna um int valor igual a -1 se o fluxo não tem buffer associado ou em caso de falha. Por exemplo. estes estão associados a um buffer interno do tipo streambuf . vamos obter diretamente o tamanho do arquivo. ler o arquivo inteiro e. passamos a definir o ponteiro começar no início do arquivo (lembre-se que abrimos o arquivo com este ponteiro no final). Observe o tipo que temos usado para declarar variáveis de tamanho : tamanho pos_type. a função de sincronização com o membro (): chamada de fluxo de função de membro sync () . é automaticamente sincronizado. que leva sem parâmetros. verdadeiro ou falso. E (&) um b a & b 0 0 1 1 00 10 00 11 OU ou OR Esta operação é realizada entre dois bits ( um e b ). O resultado é 1 se qualquer um dos dois bits for 1. mas não no caso em que ambos são. sem qualquer possibilidade de sombras. etc . O resultado da aplicação da presente operação e é 1 se os dois uma e b são iguais a 1 e 0 nos demais casos (isto é. se nem deles ou ambos são iguais a 1. o resultado é 0. Em seguida.Operações booleanas Um bit é a quantidade mínima de informações que podemos imaginar. uma palavra que vem do nome de um dos matemáticos que contribuíram mais para esse campo: George Boole (1815-1864). XOR (^) um b a ^ b 0 00 . Vamos considerar que os dois possíveis valores de um bit são 0 e 1. ou se ambos são 1. OR (|) um b a | b 0 0 1 1 00 11 01 11 XOR (ou exclusivo) Esta operação é realizada entre dois bits ( um e b ). o resultado é 0. Essas operações recebem o nome de operações booleanas . E ou AND Esta operação é realizada entre dois bits. que chamaremos de um e b . Todas estas operações têm um comportamento estabelecidos e todos eles podem ser aplicados a qualquer bit. Há pois. se uma ou ambas as variáveis é 0). não importa qual o valor que eles contêm (0 ou 1). O resultado é 1 se qualquer um dos dois bits é 1. uma vez que apenas armazena um valor 1 ou 0. o que representa sim ou não. Se nenhum for igual a 1. Várias operações podem ser realizadas com bits. quer em conjunto com outros pedaços ou sozinhos. ou seja: dois estados possíveis de cada um frente ao outro.. você tem uma lista das operações booleanas básicas e uma tabela com o comportamento de que a operação com cada combinação possível de bits. ligado ou desligado. Seu resultado é a inversão do valor real do bit: se ele foi definido para 1 se torna 0. onde um contém 195 (11000011 em binário) e b contém 87 (ou 01010111 em binário). que não tem lugar em nosso sistema decimal. eo terceiro. Em C + +. até que a operação é realizada entre todos os pedaços de ambas as variáveis (cada um apenas com o mesmo pedaço de outra variável). cada símbolo que eles escreveram para expressar um número sempre representou o mesmo valor: I 1 II 2 III 3 IV 4 V 5 Tudo o que eu sempre sinais representa o valor de 1 (um) onde eles são colocados. XOR e NOT). podemos obter qualquer resultado possível a partir de dois bits. a operação booleana é realizado para todos os bits de cada variável envolvida.0 1 1 11 01 10 NÃO ou not Esta operação é realizada em um único bit. char c. eo V signo sempre representa um valor de 5 (cinco). OR. 67 em números decimais. ambos do tipo unsigned char . char b = 87. torna-se 1: NÃO (~) um ~ A 0 1 1 0 Estas são as quatro operações básicas booleano (AND. Se escrever o seguinte código: 1 unsigned 2 unsigned 3 unsigned 4 char a = 195. No entanto. Bases Numéricas Desde que éramos crianças. e se ele for 0. estes operadores podem ser usados com variáveis de qualquer tipo de dados inteiro. todos nós temos usado para expressar quantidades decimais. Esta nomenclatura que parece tão lógico para nós pode não parecer assim para um habitante de Roma Clássica. A operação é realizada entre os bits das duas variáveis que estão localizados na mesma posição: O bit mais à direita de c vai conter o resultado de realizar a operação AND entre os bits mais à direita de um e b : A mesma operação também é realizada entre a segunda bits de ambas as variáveis. Quando nós . Combinando estas operações. e assim por diante. Por exemplo. O binário valor final de c é 01000011. supondo-se duas variáveis: uma e b . ou seja. Para eles. Isso quer dizer que fizemos um bit a bit E operação entre um e b . 195 e 87 é igual a 67 . c = &b. Assim. Como tal o valor de um algarismo depende de sua posição dentro do número inteiro a ser representada. Em C + + números octais são denotados por início sempre com um 0 dígito.------. e assim por diante: números octais (base 8) Tal como o nosso "normal" são números de base 10 (ou radix 10). com 10 0 . Todo o acima pode ser matematicamente representado em uma forma muito simples. no segundo caso. por conseguinte. 1 representa um valor de cem (ou C). o primeiro "2" sinal é equivalente a 200 (2 x 100). 10 2 . Isso é porque o nosso sistema é um sistema numeral posicional. Vamos ver como é que iria escrever os primeiros números em octal: octal decimal ----. a sua base matemática é 8. Por exemplo. o segundo "7" sinal é equivalente a 70 (7 x 10) Considerando que o último sinal que corresponde ao valor de cinco (5 x 1). Por exemplo: 1 I 10 X 100 C Nestes casos. a partir da direita. na sequência com 10 1 .0 0 (zero) 01 1 (um) 02 2 (dois) 03 3 (três) 04 4 (quatro) 05 5 (cinco) 06 6 (seis) 07 7 (sete) 010 8 (oito) 011 9 (nove) 012 10 (dez) 013 11 (onze) 014 12 (doze) 015 13 (treze) 016 14 (quatorze) 017 15 (quinze) 020 16 (dezesseis) 021 17 (dezessete) Assim. em romano) é expresso 021 como um número octal em C + +. Por exemplo. para representar o valor 182. Por exemplo: 275 não é equivalente a 2 7 5. o símbolo de uma representa um valor de dez (ou X em romano) e no terceiro. poderia ser decomposto em vez de 200 70 5: 200 + 70 5 --. porque temos 10 algarismos diferentes (do 0 ao 9): 0123456789 octals os números incluem apenas as representações para os valores de 0-7: 01234567 e.escrevemos o símbolo decimal 1 não estamos sempre a falar de um valor de um (I em algarismos romanos). o número 17 (dezessete.736 podemos supor que cada algarismo é o produto de si mesmo. Podemos aplicar o mesmo mecanismo que vimos anteriormente para números decimais para os números octal simplesmente por considerar que sua base é 8. Por exemplo. por exemplo. o nosso símbolo 1 não tem sempre um valor de um (ou eu em algarismos romanos).275 portanto. se o número octal 071263 : . ou XVII. multiplicada por 10 powered para o seu lugar como expoente. D. juntos. números hexadecimais são precedidos por 0x (zero. No entanto a passagem desta seqüência em octal só vai nos levar de alguns segundos e até mesmo os menos qualificados em matemática. o que nos permite realizar conversões mais fácil a partir dessas bases para binário do que de números decimais (cuja base é 2x5). o número octal 071263 é expressa em 29. E e F.0 0 (zero) 0x1 1 (um) 0x2 2 (dois) 0x3 3 (três) 0x4 4 (quatro) 0x5 5 (cinco) 0x6 6 (seis) 0x7 7 (sete) 0x8 8 (oito) 0x9 9 (nove) 0xA 10 (dez) 0xB 11 (onze) 0xC 12 (doze) 0xD 13 (treze) 0xE 14 (quatorze) 0xF 15 (quinze) 0x10 16 (dezesseis) 0x11 17 (dezessete) Em C + +. Esse mesmo processo pode ser inversamente realizados para passar . vamos separar o valor binário em grupos de 3 números: 110 011 111 010 010 100 e agora só temos de traduzir para radix numberal octal cada grupo separadamente: 110 011 111 010 010 100 6 3 7 2 2 4 dando o número 637. o que nos daria o número decimal 212628. que são representados pelos números 0-9 e as letras A. que. servem-nos para representar os 16 símbolos diferentes que precisamos expressar base 16 números: decimal hexadecimal ----------. e é que as suas bases (8 e 16) são múltiplos perfeito de 2 (dois 3 e 2 4 . pode fazê-lo apenas por vê-la: Desde 8 é 2 3 . B.224 como resultado.------. Por exemplo.363 em números decimais. números hexadecimais ter 16 dígitos diferentes. C. x). suponha que queremos traduzir a seguinte seqüência binária para números de outras bases: 110011111010010100 A fim de traduzi-lo em decimal seria preciso realizar uma operação matemática semelhante ao que usamos anteriormente para converter de hexadecimal ou octal. Os números hexadecimais (base 16) Como os números decimais possuem 10 dígitos diferentes para serem representadas (0123456789) e números octal tem 8 (01234567). Mais uma vez podemos utilizar o mesmo método para traduzir um número de uma base para outra: representações binárias Octal e hexadecimal números têm uma vantagem considerável sobre os nossos números decimais no mundo dos bits. respectivamente).portanto. 224 (octal) ou como 0x33e94 (hexadecimal). como aulas de interagir com o sistema operacional. com 0. porque 16 = 2 4 : 11 0011 1110 1001 0100 E 3 3 9 4 Portanto.h) cctype (ctype. a fim de ter acesso aos seus componentes: algoritmo bitset cassert cctype cerrno cfloat ciso646 climits clocale CMATH complexo csetjmp csignal cstdarg cstddef cstdio cstdlib cstring ctime deque exceção fstream funcionais iomanip ios iosfwd iostream istream iterador limites lista localidade mapa memória novo numéricos ostream fila conjunto sstream pilha stdexcept strstream streambuf string typeinfo utilitário valarray vector Ela pode ser dividida em: Biblioteca C Os elementos da biblioteca da linguagem C também estão incluídos como um subconjunto da biblioteca C + + padrão. os computadores são baseados em bytes composto de 8 bits binários e. As declarações dos diferentes elementos fornecidos pela biblioteca são divididas em vários cabeçalhos que devem ser incluídas no código. constantes. Estes abrangem muitos aspectos. classes. manipuladores de operar com eles e algoritmos comumente necessário. Por isso.h) cerrno (errno. os recipientes de dados. Referência Referência da Linguagem C + + Biblioteca. mas separar o valor binário em grupos de 4 números. com descrições detalhadas dos seus elementos e exemplos sobre como utilizar as suas funções O padrão C + + biblioteca é uma coleção de funções. objetos e modelos que estende a linguagem C + + fornecendo funcionalidade básica para executar várias tarefas. é tão freqüentemente utilizada para representar valores traduzidos para ou de base binária. portanto. A fim de realizar a operação com os números de hexadecimal só temos para executar o mesmo processo. O código hexadecimal é especialmente interessante em ciência da computação desde hoje. a partir de funções de utilidade geral e macros para funções de entrada / saída e funções de gerenciamento dinâmico de memória: cassert (assert.637.h) Biblioteca C Diagnostics (cabeçalho) Personagem funções de manipulação (cabeçalho) C erros (cabeçalho) . a expressão 110011111010010100 binários podem ser representados em C + + ou como 212628 (decimal). corresponde a cada byte com o intervalo que 2 números hexadecimal pode representar.de octal para binário. h) cstdlib (stdlib.h) CMATH (math.h) csetjmp (setjmp.h) csignal (signal.h) ciso646 (iso646.cfloat (float.h) cstdarg (stdarg.h) cstddef (stddef.h) clocale (locale.h) ctime Características dos tipos de ponto flutuante (cabeçalho) ISO 646 grafias alternativas operador (cabeçalho) Tamanhos dos tipos integrais (cabeçalho) C biblioteca de localização (cabeçalho) Biblioteca C numéricos (cabeçalho) local não pula (cabeçalho) biblioteca C para lidar com sinais (cabeçalho) tratamento de argumentos variável (cabeçalho) Standard definições C (cabeçalho) biblioteca C para executar / Output operações de entrada (cabeçalho) Standard C Library General Utilitários (cabeçalho) C Strings (cabeçalho) C Time Library (cabeçalho) C + + biblioteca padrão: as bibliotecas Diversos Idioma biblioteca de apoio : limites novo typeinfo exceção limites numéricos (cabeçalho) Dinâmica de memória (cabeçalho) Digite informações (cabeçalho) Standard classe de exceção (classe) biblioteca de Diagnóstico : stdexcept classes de exceção (cabeçalho) Biblioteca Geral utilitários : utilitário funcionais memória componentes Utility (cabeçalho) Função objetos (cabeçalho) Os elementos de memória (cabeçalho) biblioteca de Strings : .h) cstdio (stdio.h) climits (limits.h) cstring (string. string Biblioteca C + + Strings (biblioteca) biblioteca Localização : localidade Localização biblioteca (cabeçalho) Biblioteca C + + Padrão: Standard Template Library (STL) biblioteca Contentores : bitset deque lista mapa Multimap multiset priority_queue fila conjunto pilha vector Bitset (modelo de classe) Dupla fila acabou (modelo de classe) Lista (modelo de classe) Mapa (modelo de classe) Chave-mapa múltipla (modelo de classe) -Set múltiplo (modelo de classe) Prioridade da fila (modelo de classe) Fila FIFO (modelo de classe) Set (modelo de classe) Pilha LIFO (modelo de classe) Vector (modelo de classe) biblioteca iteradores : iterador definições Iterator (cabeçalho) Biblioteca de Algoritmos : STL Algoritmos Standard Template Library: Algoritmos (biblioteca) biblioteca numérica : complexo valarray numéricos biblioteca de números complexos (cabeçalho) Biblioteca para matrizes de valores numéricos (cabeçalho) numéricos operações generalizadas (cabeçalho) Biblioteca C + + padrão: Input / Biblioteca fluxo de saída Fornece funcionalidade de usar uma abstração chamada córregos especialmente projetado para realizar operações de entrada e saída em seqüências de caracteres. . como arquivos ou strings. como mostra no mapa seguinte relação com os nomes de cabeçalho do arquivo correspondente no topo: .Essa funcionalidade é fornecida através de várias classes.
Copyright © 2024 DOKUMEN.SITE Inc.