A linguagem C Conceitos gerais Novas facilidades da

  • Slides: 12
Download presentation
A linguagem C++ Conceitos gerais Novas facilidades da linguagem C++ A linguagem de programação

A linguagem C++ Conceitos gerais Novas facilidades da linguagem C++ A linguagem de programação C++ foi concebida para: · Ser um C melhorado · Suportar Abstracção de Dados · Suportar Programação Orientada por Objectos

O suporte mínimo para a programação procedimental consiste em funções, operadores aritméticos, instruções de

O suporte mínimo para a programação procedimental consiste em funções, operadores aritméticos, instruções de selecção, ciclos e entrada/saída de dados. O C++ herda todos estes mecanismos básicos e inclui alguns novos 1. Entrada/saída de dados Tal como em C, o C++ também define streams para os dispositivos de entrada e saída que são abertos quando um programa é executado Os streams são: 1. cout, equivalente ao stdout; 2. cin, equivalente ao stdin; 3. cerr, equivalente ao stderr; De facto cout é um objecto do tipo ostream. A classe ostream foi definida com o operador operator<< (“put to”) para fornecer as saídas dos tipos predefinidos nas linguagens C/C++.

Vamos abordar um exemplo: #include <iostream. h> int main() { cout << "This is

Vamos abordar um exemplo: #include <iostream. h> int main() { cout << "This is the second argumentn"; } Isto é o primeiro argumento do operador (da função) operator<< Isto é o segundo argumento do operador (da função) operator<< O operador << (“put to”) escreve o valor do segundo argumento no primeiro argumento. Isto significa que, no exemplo, o texto This is the second argumentn será escrito no dispositivo de saída standard cout. cerr é um outro objecto do tipo ostream.

Por analogia cin é um objecto do tipo istream. A classe istream foi definida

Por analogia cin é um objecto do tipo istream. A classe istream foi definida com o operador operator>> (“get from”) para fornecer as entradas dos tipos predefinidos nas linguagens C/C++. Vamos considerar o exemplo: int a; float b; char c; cin >> a >> b >> c; Os streams são declarados no ficheiro iostream. h Um programa poderá usar para entradas e saídas tanto a biblioteca standard de C como a de C++ (ou as duas)

2. Overloading (Sobrecarga) do nome das funções Funções diferentes têm geralmente nomes diferentes. Contudo,

2. Overloading (Sobrecarga) do nome das funções Funções diferentes têm geralmente nomes diferentes. Contudo, para funções que realizam tarefas semelhantes em tipos de objectos diferentes, por vezes é preferível que essas funções mantenham o mesmo nome. Quando o tipo dos seus argumentos é diferente, o compilador consegue diferenciá-las e escolher a função correcta a invocar. Por exemplo, podemos ter uma função potência para inteiros e outra para variáveis de vírgula flutuante. Vamos abordar o exemplo: int pow(int, int); double pow(double, double); //. . . x = pow (3, 5); // chamada pow(int, int) y = pow (2. 0, 4. 0); // chamada pow(double, double)

Este tipo de uso múltiplo de um nome de uma função é designado por

Este tipo de uso múltiplo de um nome de uma função é designado por function-name overloading ou simplesmente overloading. Os argumentos de uma função podem ser passados quer “por valor”, quer “por ponteiro”, quer “por referência”. void swap(int* a, int* b) { int temp = *a; *a = *b; *b = temp; } void swap(int& a, int& b) { int temp = a; a = b; b = temp; } void f(int i, int j) { swap(&i, &j); } void f(int i, int j) { swap(i, j); } Usando a passagem por referência podemos trabalhar com ponteiros implícitos

3. Referências Uma referência é um nome alternativo para um objecto Tal como um

3. Referências Uma referência é um nome alternativo para um objecto Tal como um apontador, uma referência corresponde a um local onde se situa uma variável Com o tipo de dados referência, criamos um nome alternativo para uma variável previamente declarada Numa declaração, a notação T& significa referência para um valor do tipo T Seja, por exemplo: int i=3; int &j=i; j=2; //. . . A diferença entre os ponteiros e as referências é a seguinte: o utilizador pode usar uma referência como um objecto ordinário ainda que o acesso seja fornecido através do endereço

void main(void) { int i=3; int &j=i; j=2; //. . . void main(void) {

void main(void) { int i=3; int &j=i; j=2; //. . . void main(void) { int i=3; int *j=&i; * j=2; //. . . Uma referência é um ponteiro implícito 6] les es , bx [ bp i=3 ss bp-2 bp // mov word ptr [bp-2], 3 Isto // mov [bp-4], ss // mov [bp-6], ax ; lea ax, [bp-2] j=2 and i=2 mov es: word ptr [bx], 2 bx ss é um ponteiro explícito mov word ptr[bp-2], 3 lea ax, [bp-2] mov [bp-4], ss mov [bp-6], ax les bx, [bp-6] mov es: word ptr [bx], 2

Como uma referência é um ponteiro podemos obter um resultado inesperado, por exemplo int

Como uma referência é um ponteiro podemos obter um resultado inesperado, por exemplo int F(int& ri) { ++ri; return ri; } int main(. . . ) { int m 1=1; cout << F(m 1) << endl; cout << m 1 << endl; // o resultado é 2 } A referência para o objecto m 1 é passada à função F. Esta função alterou o valor da variável m 1 indirectamente através da referência De facto, uma referência é implementada pelo compilador como um apontador constante que é desreferenciado automaticamente de cada vez que foi usado

Na maioria dos casos as referências e os apontadores têm uma relação de equivalência,

Na maioria dos casos as referências e os apontadores têm uma relação de equivalência, por exemplo: O seguinte código usa uma referência: O seguinte código usa um ponteiro: int ii=5; int *rii=&ii; cout << ii << 't' << *rii << endl; *rii = 10; cout << ii << 't' << *rii << endl; int i=5; int &ri=i; cout << i << 't' << ri << endl; ri = 10; cout << i << 't' << ri << endl; Os resultados são iguais: 5 10 int &a, &b, &c; As referências devem ser inicializadas, por exemplo: int *aa, *bb, *cc; int k; int &a=k, &b=k, &c=k; // erro // Ok

Vamos considerar o seguinte código: X = Y; Esta atribuição está correcta se a

Vamos considerar o seguinte código: X = Y; Esta atribuição está correcta se a expressão esquerda for um endereço (lvalue - a left value) e se a expressão direita produzir um valor (rvalue - a right value), que é um valor permissível. Como resultado o valor do lado direito (Y) vai ser copiado para a célula da memória que tem o endereço X. Uma referência é um endereço e por isso pode ser considerada como lvalue. Então, a referência pode ser escrita no lado esquerdo da expressão. Vamos considerar uma função. Podemos passar o argumento à função como valor. Neste caso este valor (de facto rvalue) vai ser copiado na pilha da função. A função não tem acesso ao valor da variável original que foi passada.

Podemos passar o argumento à função como referência. Neste caso o endereço (de facto

Podemos passar o argumento à função como referência. Neste caso o endereço (de facto lvalue) vai ser copiado na pilha da função. Usando este endereço (esta referência) podemos alterar o valor da variável original que foi passada. Por outras palavras a referência pode ser usada como um apontador implícito. A referência pode ser devolvida da função. Neste caso a função pode aparecer no lado esquerdo da expressão. Vamos abordar das seguintes funções: 1. int F(int& i) { return i; } 2. int& RF(int& j) { return j; } F(x) = 6; // erro RF(x) = 6; // Ok podemos, por exemplo obter um resultado inesperado int x=3; cout << " x = " << x << endl; RF(x) = 6; cout << " x = " << x << endl; // x=3 // x=6