quarta-feira, 11 de junho de 2014

C++

Programa mínimo

Este é um exemplo de um programa mínimo que faz nada. Ele começa sua execução e logo termina. A função main é definida como o ponto de início de qualquer programa C++.
Notas com questões de compilador
Ainda que o padrão C++ não exija return 0; na função main, alguns compiladores antigos como o Microsoft Visual C++ 6 retornam avisos ou erros com tal situação e podem não gerar código objeto correto.
int main()
{
}
O padrão C++ exige que main() retorne o tipo de dado int (inteiro).1 Tradicionalmente, o valor do retorno dessa função representa o valor de retorno do próprio programa, o qual é informado para o processo que o executou. Um término mal sucedido pode ser indicado com um valor diferente de zero. O valor assumido por padrão é zero,1 que representa retorno bem sucedido.

Programa Olá Mundo

Este é um exemplo do Programa Olá Mundo aplicado à linguagem C++ que utiliza a biblioteca padrão para a entrada e saída de dados.2
Notas com questões de compilador
A adição da biblioteca padrão <ostream> pode ser necessária para alguns compiladores. Isto deve-se ao fato do padrão ISO C++ exigir que a biblioteca padrão <iostream> declare o objetostd::cout como uma instância da classe std::ostream, mas não obriga que <iostream> defina a classestd::ostream e seus operadores3 .
# include <iostream> // Necessário para std::cout e std::endl

int main()
{
std::cout << "Olá, Mundo!" << std::endl;
}
Nota-se no exemplo acima a declaração local de quais espaços de nomes estão sendo utilizados.

Gabaritos[editar | editar código-fonte]

Este é um exemplo da utilização de gabaritos para a substituição da seguinte macro de programação comumente utilizada em C, apesar de bastante insegura4 , para o retorno do maior entre dois elementos dados:
// versão utilizando macros

# define max( x, y ) ( x > y ? (x) : (y) )

// versão utilizando gabaritos, muito mais segura e com checagem de tipo

template <typename T>
T max(T x, T y)
{
return (x > y) ? x : y;
}

Polimorfismo estático

Este é um exemplo de polimorfismo resolvido em tempo de compilação de código, representando a sobrecarga de funções.
extern void EnviaTrabalhoParaImpressora( TrabalhoTexto *, ImpressoraLaser * );
extern void EnviaTrabalhoParaImpressora( TrabalhoTexto *, ImpressoraTinta * );
extern void EnviaTrabalhoParaImpressora( TrabalhoHTML *, ImpressoraLaser * );
extern void EnviaTrabalhoParaImpressora( TrabalhoHTML *, ImpressoraTinta * );

Polimorfismo dinâmico

Este é um exemplo de polimorfismo resolvido em tempo de execução de código, representando funções virtuais.
# include <iostream>

class Passaro // classe base
{
public:
virtual void MostraNome()
{
std::cout << "um passaro";
}
virtual ~Passaro() {}
};

class Cisne: public Passaro // Cisne é um pássaro
{
public:
void MostraNome()
{
std::cout << "um cisne"; // sobrecarrega a função virtual
}
};

int main()
{
Passaro* passaro = new Cisne;

passaro->MostraNome(); // produz na saída "um cisne", e não "um pássaro"

delete passaro;
}

Utilizando a biblioteca padrão

Este é um exemplo de programa que utiliza elementos da Standard Template Library.
# include <iostream>   // std::cout
# include <vector> // std::vector<>
# include <map> // std::map<> and std::pair<>
# include <algorithm> // std::for_each()
# include <string> // std::string

using namespace std; // importa o espaço de nomes "std" ao espaço de nomes global

void mostra_quantidade_de_itens(pair< string const, vector<string> > const& pessoa)
{
// "pessoa" é um par de objetos: pessoa.first é o nome da pessoa,
// pessoa.second é uma lista dos itens da pessoa (arranjo de cadeias de caracteres)
cout << pessoa.first << " esta carregando " << pessoa.second.size() << " itens\n";
}

int main()
{
// Declara um mapeamento com chaves de cadeias de caracteres e arranjos de cadeias
// de caracteres como dado
map< string, vector<string> > itens;

// Adiciona algumas pessoas no mapeamento e permite que elas carreguem alguns itens
itens["Anya"].push_back("livro");
itens["Dimitri"].push_back("computador pessoal");
itens["Anya"].push_back("casaco");

// Percorre por todos os itens do container
for_each(itens.begin(), itens.end(), mostra_quantidade_de_itens);
}
Nota-se no exemplo acima a declaração global de quais espaços de nome estão sendo utilizados.

Busca de nomes dependente de argumento

O exemplo clássico de busca de nomes dependente de argumento, também chamada Koenig lookup, é mostrado abaixo:
namespace NS
{
class A {};
void f( A ) {}
}
m
int main()
{
NS::A a;
f( a ); // invoca NS::f
}
Note que não foi necessário especificar o espaço de nomes da função f, ainda que ela foi encontrada devido à sua associação com a classe A utilizada como argumento.

Tratamento de exceções

Abaixo é mostrado um exemplo do tratamento de exceções. A divisão de um número por zero não é autorizada por processadores. Como possui uma variável como divisor, a função seguinte divisao_de_dez_por deve primeiramente tratar casos inválidos de entrada. Caso a estrada seja zero, uma exceção será lançada, e o código será redirecionado para o tratamento da exceção (indicado por catch).
# include <iostream>

using namespace std;

int divisao_de_dez_por( int divisor )
{
// prevendo entrada inválida
if( divisor == 0 )
{
throw "divisão por zero";
}

return 10 / divisor;
}

int main()
{
int div, resultado;

cin >> div; // obtém do usuário um número inteiro

try
{
resultado = divisao_de_dez_por( div );
}
catch( const char *e )
{ // código será redirecionado para cá caso ( div == 0 )
resultado = 0; // recuperação do sistema
cout << "Houve uma exceção: " << e << endl;
}
}

Manipulação de argumentos da linha de comando

Uma necessidade comum aos desenvolvedores é a comparação de cadeias de caracteres passados pela linha de comando. Um exemplo de sua interpretação segue abaixo:
# include <iostream>   // biblioteca necessária para a função std::cout

using namespace std; // declaração global do espaço de nomes

int main( int argc, char *argv[] )
{
int arg; // declara uma variável inteiro com o nome arg

// atribui-se 1 a arg; enquanto arg for menor que argc, executa-se o bloco e arg é incrementado em cada iteração
for( arg = 1; arg < argc; arg++ )
{
if( argv[arg][0] != '-' )
{
break;
}

switch( argv[arg][1] )
{
case 'r': // caso possua um r após o hífen
cout << "Argumento -r usado\n\n";
break;
case 'v': // caso possua um v após o hífen
cout << "Argumento -v usado\n\n";
break;
default: // este é o valor de escape e sua respectiva mensagem:
cout << "Nenhum argumento foi usado\n\n";
break;
}
}
}
Diferente do restante de exemplos, notar que no exemplo acima a função main recebe argumentos em uma assinatura especial e que não pode ser alterada. É com esses parâmetros que o programa pode acessar as informações passadas pela linha de comando. O primeiro parâmetro passado indica a quantidade de parâmetros passados, e o segundo armazena uma cadeia de carateres de cada parâmetro.

Ambiguidade da linguagem

Abaixo é mostrado um exemplo de código que demonstra um tipo de ambiguidade na linguagem C++, mostrando porque um analisador sintático trivial não é o suficiente para gerar uma árvore de sintaxe. Apesar da cadeia de caracteres foo<1>(3) aparecer duas vezes no código (linhas 11 e 23), ela está empregada em situações bastante diferentes, e envolvendo identificadores diferentes. Na primeira situação o identificador foo é uma variável local da função teste1, cujo valor é comparado com o literal 1. O resultado é finalmente comparado com o literal 3. Na segunda situação, o identificador foo é a invocação de uma instância da função gabarito definida no início do código, alimentando o gabarito com literal 1 e alimentando o parâmetro da função com o literal 3.
  1. template <int N>
  2. void foo( const int t )
  3. {
  4.    // processa alguma coisa
  5. }
  6.  
  7. void teste1()
  8. {
  9.    int foo = 3;
  10.  
  11.    if( foo<1>(3) ) // situação 1
  12.    {
  13.       // processa alguma coisa
  14.    }
  15.    else
  16.    {
  17.       // processa alguma coisa
  18.    }
  19. }
  20.  
  21. void teste2()
  22. {
  23.    foo<1>(3); // situação 2
  24. }
  25.  
  26. int main()
  27. {
  28.    teste1;
  29.    teste2;
  30. }

Metaprogramação com gabarito

Um exemplo difundido no cálculo de fatorial é o uso de recursividade, como demonstrado abaixo:
int factorial( int n ) 
{
if( n == 0 )
return 1;
return n * factorial( n - 1 );
}

int x = factorial(4); // == (4 * 3 * 2 * 1) == 24
int y = factorial(0); // == 0! == 1
Note que no exemplo acima o cálculo é realizado em tempo de execução, o que implica que para cada chamada da função o processamento é feito novamente. É possível realizar tais cálculos recursivos em tempo de compilação através da metaprogramação com gabaritos, fazendo uso da especialização de gabaritos, com o seguinte código:
template <int N>
struct Factorial
{
enum { value = N * Factorial<N - 1>::value };
};

template <>
struct Factorial<0>
{
enum { value = 1 };
};

int z = Factorial<5>::value; // == 120
int x = Factorial<4>::value; // == 24
int y = Factorial<0>::value; // == 1
No exemplo acima, a metaprogramação com gabaritos permite a recursividade do gabarito, sendo que a condição de saída é dada pela especialização no valor literal "0". Para cada ocorrência de Factorial<4>::value no código fonte, o compilador realiza a chamada recursiva e substitui pelo resultado, 24. Em tempo de execução resta somente o valor literal, evitando o cálculo.

Referências

  1. ↑ Ir para:a b Bjarne Stroustrup. Bjarne Stroustrup's C++ Style and Technique FAQ :: Can I write "void main()"? (em inglês). Página visitada em 19 de junho de 2008.
  2. Ir para cima Juan Soulie (24 de abril de 2007). C++ : Documentation : C++ Language Tutorial : Structure of a program (em inglês). Página visitada em 24 de outubro de 2007.
  3. Ir para cima Stroustrup discute sobre o assunto ao comentar sobre o erro em seu livro em relação ao padrão C++. Bjarne Stroustrup (4 de novembro de 2003). Open issues for The C++ Programming Language (3rd Edition) (em inglês). Página pessoal de Bjarne Stroustrup. Página visitada em 2 de setembro de 2007. ""pg 633: I say "Manipulators taking istream and ostream are presented in and < ostream> respectively, and also in < iostream>. The rest of the standard manipulators are presented in < iomanip>." However, the standard disagrees and provides no manipulators in < iostream>…""
  4. Ir para cima Uma explicação genérica sobre a insegurança de macros encontra-se em:
    Marshall Cline (25 de setembro de 2006). Inline functions: Why should I use inline functions instead of plain old #define macros? (em inglês). Página visitada em 10 de setembro de2007.

Nenhum comentário:

Postar um comentário