OTServ



Você não está conectado. Conecte-se ou registre-se

[Tutorial 2] Extensões ao C

Ir em baixo  Mensagem [Página 1 de 1]

1 [Tutorial 2] Extensões ao C em 29/8/2011, 13:21

Dark Side

avatar


2.0 - Introdução
Tudo o que você já escreveu em C funciona em C++. No entanto, em muitos casos C++ oferece um modo melhor de se realizar o mesmo trabalho. Em outros casos C++ oferece mais de uma maneira de se fazer a mesma coisa, e isso lhe dá maior flexibilidade no desenvolvimento de programas. Nessa seção vamos examinas as extensões do C++ em relação ao C. Muitas dessas extensões não foram adicionadas gratuitamente, mas sim para viabilizar programação orientada a objeto, conforme se verá mais adiante em outros tutoriais dessa série.

Esse tutorial em especial apresenta muitos detalhes do C++. Nada de pânico. Se preferir apenas percorra o texto e volte mais tarde estudando cada seção, na medida de sua necessidade. Os conceitos apresentados a seguir foram todos reunidos aqui para simplificação de referência, já que serão usados em vários outros pontos dessa série de tutoriais.

2.1 - Comentários

C++ suporta o antigo modo multi-linha de comentário, bem como a nova forma linha-única representado pelo símbolo //. Por exemplo:
// get_it function reads in input values
void get_it()
{
// do something.
}
O C++ ignora tudo o que estiver escrito após o // e até o final da linha. Você pode usar ambas as formas de comentário em um programa C++.

2.2 - Conversão de tipos de dados
Em C você pode determinar a conversão de tipos de dados, colocando o nome do tipo entre parêntesis imediatamente antes do nome da variável, como no exemplo seguinte:
int i;
float f;

f = (float) i;
C++ suporta um segundo modo de conversão de tipos, que faz com que a especificação de conversão se pareça mais com a chamada de uma função:
int i;
float f;

f = float(i);
Vamos ver mais adiante, quando começarmos a tratar de classes, que há uma razão para esse novo formato.

2.3 - Input/Output
2.3.1 - I/O em Terminal

Uma das mais óbvias diferenças entre C e C++ é a substituição da biblioteca stdio do C pela iostream do C++. A biblioteca iostream beneficia-se de um grande número de extensões do C++ voltadas a orientação a objeto, conforme veremos mais adiante. Mais ainda, torna mais fácil a adição de novos tipos de dados definidos pelo programador. A biblioteca iostream contém todas as capacidades encontradas na stdio, mas as viabiliza de uma nova forma. Portanto, é importante conhecer como usar as funções básicas da iostream se você estiver convertendo seu código de C para C++. O uso de iostream para as funções básicas de input/output é de compreensão quase imediata. Veja os seguintes exemplos:
cout << "hello\n";
ou o equivalente:
cout << "hello" << endl;
Ambos os exemplos produzem a mesma saída, e fazem com que a palavra hello seguida de um newline seja escrita na unidade padrão de saída. A palavra cout indica stdout como destinação para a operação de saída, e o operador << (que significa inserção) é usado para transferir os itens de dados. Há duas outras saídas-padrão pré-definidas: cerr para notificações imediatas de erro, e clog para acumulação de notificações de erro.

Pode-se escrever em qualquer saída padrão usando-se as técnicas mostradas no exemplo anterior. Múltiplos itens de dados podem ser enfileirados em uma única linha de comando, ou empilhados em várias linhas. Por exemplo:
int i = 2;
float f = 3.14
char c = 'A';
char *s = "hello";

cout << s << c << f << i << endl;
produz a saída:

helloA3.142

da mesma forma que
cout << s << c;
cout << f;
cout i << endl;
O mecanismo cout compreende valores de endereços de memória automaticamente, e os formata para apresentação em hexadecimal. Por exemplo, se i é um inteiro, então o comando
cout << &i << endl;
Há casos, no entanto, em que essa regra de conversão para hexadecimal não se aplica. Imprimir s, onde s é um pointer para um caracter, produz a impressão do string apontado por s em lugar do endereço contido em s. Para remediar essa situação, converta s para um pointer void, como mostrado a seguir, se o que você quer é a impressão do endereço contido de s:
cout << (void *) s;
Agora o endereço contido em s será apresentado em formato hexadecimal. Se você quiser o endereço apresentado em formato decimal, converta-o para um inteiro longo:
cout << long(& i);
Essa linha imprime o endereço de i em formato decimal.

Da mesma forma, uma conversão para int é usada para imprimir o valor inteiro de um caracter:
cout << int('A'); // produces 65 as output
Você pode estranhar que o operador << - conhecido em C como shift left operator - tenha sido roubado para manejar operações de saída em C++. Se você quiser usá-lo para operação de shift left dentro de uma linha de saída, use-o entre parêntesis:
cout << (2 << 4); // produces 32 as output
Você pode usar várias técnicas para formatar a saída. Informações podem ser espaçadas acrescentando-se espaços, tabs ou strings literais, como mostrado a seguir:
int i = 2;
float f = 3.14
char c = 'A';
char *s = "hello";

cout << s << " " << c << "\t" << f
<< "\t" << i << endl;
Há ainda vários outros manipuladores que podem ser inseridos em um fluxo de saída (em alguns sistemas você precisará incluir iomanip.h para poder usá-las):
dec Usa base decimal
oct Usa base octal
hex Usa base hexadecimal
endl Finaliza a linha
ends Finaliza o string ('\0')
flush Descarrega o buffer de saída
setw(w) Estabelece a largura da saída para o valor de w
(0 é o default)
setfill(c) Estabelece o caracter de preenchimento para conteúdo de c (blank é o default)
setprecision(p) Estabelece a precisão flutuante para o valor de p
O código
cout << "[" << setw (6) << setfill('*') << 192;
cout << "]" << endl;
cout << hex << "[" << setw (6);
cout << setfill('*') << 192 << "]" << endl;
cout << setprecision(4) << 3.14159 << endl;
produz

[***192]
[****c0]
3.142
A saída de números em ponto flutuante pode truncar ou não zeros a direita, independente de como você estabeleça a precisão. Essa é uma característica determinada pelo compilador que você estiver usando.

Você deve ter notado nos exemplos recém apresentados que não se deve usar certos nomes para variáveis ou funções para não se perder a possibilidade de usar os manipuladores intrínsecos à biblioteca iostream.

As operações de entrada são manejadas de uma maneira semelhante às operações de saída, usando-se cin para fluxo de entrada e >> como operador de extração. Por exemplo, o comando
int i,j,k;
cin >> i >> j >> k;
O fluxo de entrada cin automaticamente divide o string de entrada em palavras e termina quando recebe EOF.
2.3.2 - I/O em arquivos
Input e output para arquivos texto são manejados pela inclusão do arquivo fstream.h, e pela declaração de variáveis do tipo ifstream e ofstream respectivamente. Por exemplo, o seguinte programa lê um arquivo denominado xxx e escreve em um arquivo denominado yyy:
#include
#include

void main()
{
char c;
ifstream infile("xxx");
ofstream outfile("yyy");

if (outfile && infile) // They will be 0 on err.
while (infile >> c)
outfile << c;
}
As variáveis infile e outfile recebem o nome do arquivo na inicialização e são usadas exatamente como cin e cout. O código desse exemplo não funciona como seria de esperar porque brancos, tabs e caracteres \0 ao final de cada linha são ignorados, do mesmo modo que espaço em branco quando se usa <<. Nesse caso, melhor usar a função get, como mostrado a seguir:
while (infile.get(c))
outfile << c;
ou
while (infile.get(c))
outfile.put(c);
É ainda possível ler linhas inteiras usando-se a função getline, da mesma maneira que se usa a função get. Para abrir um arquivo para acrescentar dados, use o seguinte:
ofstream("xxx", iosapp);
Essa linha, bem como a notação da função .get, fará mais sentido na medida em que você conheça mais sobre o C++. O fato de ofstream algumas vezes receber um, outras vezes dois parâmetros é uma característica intrínseca ao C++.

Note que não há necessidade de uma função close para os arquivos de entrada ou de saída. O arquivo é fechado automaticamente quando se encera o escopo da variável que denomina o arquivo. Se você precisar fechar explicitamente um arquivo, use
outfile.close();

2.3.3 - I/O em string
Entradas podem ser lidas a partir de string na memória, e saídas pode ser enviadas para strings na memória, duplicando-se assim as ações de sscanf e sprintf. Para tanto você deve incluir o arquivo strstream.h e declarar a entrada e a saída em string. Uma saída em string e mostrada a seguir:
char s[100];
ostrstream outstring(s,100);

outstring << 3.14 << " is pi" << ends;
cout << s;
O string s é preenchido com o texto

3.14 is pi.

Se o tamanho de s for atingido, outstring vai automaticamente interromper a colocação de valores em s.

Se um string s já existe e você deseja ler dados a partir dele, você pode usar um fluxo de entrada string como mostrado a seguir:
char *s = "3.14 12 cat";
istrstream instring(s, strlen(s));
float f;
int i;
char t[100];

instring >> f >> i >> t;
A biblioteca iostream tem muitas e muitas outras capacidades não discutidas aqui. Para maiores informações, veja a documentação fornecida junto com o seu compilador. Ela geralmente contém uma referência completa para a biblioteca de I/O

2.4 - Declarações de variáveis
Variáveis são declaradas em C++ assim como o são em C. As variáveis podem ser declaradas em qualquer ponto do código em C++, estabelecendo um nível de flexibilidade quase como o que existe em FORTRAN. A variável torna-se existente quando é declarada, e deixa de existir quando o } do bloco corrente é encontrado. Por exemplo, na seguinte codificação:
{
int i;
... code ...
int j;
... code ...
int k=func(i,j);
... code ...
}
todas as três variáveis passam a existir no ponto em que são declaradas, e desaparecem ao }.

2.5 - Constantes
Em C você cria uma constante usando uma macro do pré-processador, como no seguinte exemplo:
#define MAX 100
Quando o programa é compilado, o pré-processador encontra cada ocorrência da palavra MAX e a substitui pelo string 100.

Em C++ usa-se a palavra const, que é aplicável normalmente às declarações de variáveis:
const int MAX=100;
A codificação int MAX=100; é formatada exatamente da mesma maneira que uma declaração normal. O termo const que precede a declaração simplesmente define que a variável MAX não pode ser modificada. O uso de letras maiúsculas para nomes de variáveis constantes é uma tradição em C, que você pode preservar ou abandonar.

O modificador const pode também ser usado em listas de parâmetros para especificar o uso correto do parâmetro. As três funções a seguir exemplificam diferentes usos de const.
void func1(const int i)
{
i=5; // cannot modify a constant
}

void func2(char * const s)
{
s="hello"; // cannot modify the pointer
}

void func3(const char * s)
{
s="hello"; // this is OK
*s='A'; // cannot modify what is pointed to
}
A notação mostrada em func2 deve, sempre que possível, ser usada quando um parâmetro char* é passado para a função.

2.6 - Sobrecarregando funções
Um dos mais poderosos novos recursos do C++ é denominado sobrecarga de função. Uma função sobrecarregada possui várias e diferentes listas de parâmetros. A linguagem distingue qual das opções de chamada da função deve ser usada, com base no padrão das listas de parâmetros. Aqui está uma demonstração extremamente simples desse processo:
#include

void func(int i)
{
cout << "function 1 called" << endl;
cout << "parameter = " << i << endl;
}

void func(char c)
{
cout << "function 2 called" << endl;
cout << "parameter = " << c << endl;
}

void func(char *s)
{
cout << "function 3 called" << endl;
cout << "parameter = " << s << endl;
}

void func(char *s, int i)
{
cout << "function 4 called" << endl;
cout << "parameter = " << s;
cout << ", parameter = " << i << endl;
}

main()
{
func(10);
func('B');
func("hello");
func("string", 4);
return 0;
}
Quando esse código é executado, cada versão da função func é escolhida, e chamada, de acordo com as correspondências entre as listas de parâmetros. Você vai conseguir usar essa capacidade, que é uma grande característica do C++, uma vez que você encare sobrecarga de função como uma solução para muitos dos problemas de programação. Por exemplo, se você cria uma função para inicializar um módulo, você pode ter uma chamada diferente, para a mesma função, dependendo da característica do parâmetro que é passado; um string, um inteiro, um ponto flutuante, e assim por diante.

2.7 - Argumentos default
C++ também permite que você determine valores default para os parâmetros. Se o parâmetro não for passado, o valor default é usado. Essa capacidade é demonstrada no seguinte código:
#include

void sample(char *s, int i=5)
{
cout << "parameter 1 = " << s << endl;
cout << "parameter 2 = " << i << endl;
}

main()
{
sample("test1");
sample("test1",10);
return 0;
}
A primeira chamada da função vai apresentar o valor default 5 para o parâmetro i, enquanto a segunda chamada vai apresentar o valor 10.

Quando criando parâmetros default, você precisa evitar ambigüidade entre as listas de parâmetros default e as demais listas de parâmetros. Examinando a função de nosso último exemplo, não é possível criar uma versão sobrecarregada que aceite um parâmetro char* isolado, porque o compilador não conseguiria escolher que versão chamar no caso de se passar um string.

2.8 - Alocação de memória
C++ substitui as funções C de alocação e de desalocação de memória , malloc e free, pelas novas funções new e delete, respectivamente e torna esse processo muito mais fácil para o programador. new e delete permitem que tipos de dados definidos pelo programador sejam alocados e desalocados tão facilmente quanto os tipos já existentes em C++.

O código seguinte exemplifica o modo mais simples de uso de new e delete. Um pointer para um inteiro aponta para um bloco de memória criado por new:
int *p;
p = new int;
*p = 12;
cout << *p;
delete p;
É ainda possível alocar blocos compostos de matrizes de tamanhos variados, usando uma técnica similar. Repare o uso de [] para excluir a matriz:
int *p;
p = new int[100];
p[10] = 12;
cout << p[10];
delete [] p;
O valor 100 poderia ser uma variável, se desejável.

Quando aplicada a tipos de dados definidos pelo programador, new funciona do mesmo modo. Por exemplo:
typedef node
{
int data;
node *next;
} node;

main()
{
node *p;
p=new node;
p->date = 10;
delete p;
}
Conforme veremos mais adiante nessa série de tutoriais, o operador delete é bastante sofisticado quando opera com classes definidas pelo programador.

2.9 - Declarações de referência
Em C, pointers são freqüentemente usados para passar parâmetros para funções. Por exemplo, a seguinte função swap inverte dois valores que lhe são passados:
void swap(int *i, int *j)
{
int t = *i;
*i = *j;
*j = t;
}

main()
{
int a=10, b=5;

swap(& a, & b);
cout << a << b << endl;
}
C++ provê um novo operador de referência que simplifica muito essa sintaxe. O seguinte código funciona em C++
void swap(int& i, int& j)
{
int t = i;
i = j;
j = t;
}

main()
{
int a=10, b=5;

swap(a, b);
cout << a << b << endl;
}
Os parâmetros i e j declarados como tipo int& atuam como referências para os inteiros passados (leia int& como uma referência para um inteiro). Quando uma variável é atribuída à referência de uma outra variável, a referência toma o endereço da variável e opera a atribuição para a localização real para a variável . Por exemplo:

int a;
int & b=a;

a=0;
b=5;
cout << a << endl;

O código acima produz 5 como saída porque b referencia a. É o mesmo que usar pointer e operadores de endereços em C, mas a sintaxe aqui é muito mais simples. Note que b deve ser inicializado quando de sua criação, como mostrado no exemplo.

Fonte : Arnaut



Ola, Convidado Gostou ? Da REP++


[Você precisa estar registrado e conectado para ver este link.]

Spoiler:

http://www.otserver.forumeiros.com

Voltar ao Topo  Mensagem [Página 1 de 1]

Permissão deste fórum:
Você não pode responder aos tópicos neste fórum