escola superior de tecnologialtodi.est.ips.pt/jcordeiro/disciplinas/poo/transição do c para...

25
Escola Superior de Tecnologia TRANSIÇÃO PARA C C + + + + Para programadores de C José Cordeiro © 1998

Upload: others

Post on 03-Aug-2020

0 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Escola Superior de Tecnologialtodi.est.ips.pt/jcordeiro/disciplinas/POO/Transição do C para C++.pdf · Notação Funcional do Operador de Coerção (cast) 16 ... de novas operações

Escola Superior de Tecnologia

TRANSIÇÃO PARA CC++++ Para programadores de C

José Cordeiro © 1998

Page 2: Escola Superior de Tecnologialtodi.est.ips.pt/jcordeiro/disciplinas/POO/Transição do C para C++.pdf · Notação Funcional do Operador de Coerção (cast) 16 ... de novas operações

E S C O L A S U P E R I O R D E T E C N O L O G I A / I N S T I T U T O P O L I T É C N I C O D E S E T Ú B A L

Transição para CC++++

Para programadores de C

Dezembro 1998 José A. M. Cordeiro Escola Superior de Tecnologia / Instituto Politécnico de Setúbal

Rua do Vale de Chaves, Estefanilha • 2910 Setúbal Telefone (065) 790000 • Fax (065) 721869

[email protected]

Page 3: Escola Superior de Tecnologialtodi.est.ips.pt/jcordeiro/disciplinas/POO/Transição do C para C++.pdf · Notação Funcional do Operador de Coerção (cast) 16 ... de novas operações

Índice

ÍNDICE 2

INTRODUÇÃO 3

ALTERAÇÕES À LINGUAGEM C 3

ESTRUTURA DO PROGRAMA 3

Ficheiros Fonte 4

Comentários 4

Constantes 4

Variáveis 4

ENTRADA E SAÍDA DE DADOS 5

Entrada e Saída de Dados Simples 5

Saída de Dados Formatada 9

FUNÇÕES 10

Funções inline 10

Redefinição de Funções 11

Argumentos Pré-definidos 12

Transmissão de Parâmetros por Referência 12

Retorno de Valores por Referência 13

ESTRUTURAS DE DADOS DINÂMICAS 14

Operador new 14

Operador delete 14

TÓPICOS VARIADOS 16

Notação Funcional do Operador de Coerção (cast) 16

Inicialização Dinâmica de Variáveis 16

Variáveis por Referência 16

FICHEIROS 16

MODELOS (TEMPLATES) 20

REDEFINIÇÃO DE OPERADORES 22

Page 4: Escola Superior de Tecnologialtodi.est.ips.pt/jcordeiro/disciplinas/POO/Transição do C para C++.pdf · Notação Funcional do Operador de Coerção (cast) 16 ... de novas operações

33

Introdução A linguagem C++ surge como uma extensão à linguagem C trazendo consigo dois importantes conjuntos de novidades:

1. Melhorias e acrescentos à linguagem C

2. Possibilidade de programação orientada por objectos

Informalmente diz-se que o primeiro conjunto leva àquilo a que se chama um C melhorado (“a better C”) e é representado pelo primeiro símbolo + do nome da linguagem. O segundo símbolo + vem das novas capacidades de programação orientada por objectos.

As melhorias da linguagem C e algumas diferenças que apesar de tudo existem em relação ao C++ serão descritas neste manual. A programação orientada por objectos não será abordada.

Alterações à Linguagem C Apesar da linguagem C++ ser uma extensão da linguagem C existem, contudo, algumas alterações.

As principais diferenças entre o C e o C++ envolvem a declaração de funções. Em C++ é obrigatório fornecer a declaração ou definição de uma função antes da sua utilização. Como boa prática deve-se sempre declarar todas as funções mesmo quando se faz a sua definição.

Outra alteração relacionada com a declaração de uma função diz respeito à omissão dos parâmetros na declaração. Em C isto significava que nada se dizia em relação aos argumentos da função, em C++ isto significa que a função não leva argumentos, sendo void.

Estrutura do Programa Embora os programas em C++ apresentem uma estrutura semelhante à dos programas em C, a utilização de algumas das novas características leva-os a apresentarem um aspecto diferente. Assim, as entradas e saídas de dados que utilizavam anteriormente as funções printf e scanf passam a utilizar as novas “operações” >> e << com um formato bastante diferente e que será descrito na próxima secção.

Também os comentários e a definição de constantes sofrem algumas alterações. O local de definição de variáveis é outra das novidades.

!!11

Declaração de funções obrigatória.

11

Page 5: Escola Superior de Tecnologialtodi.est.ips.pt/jcordeiro/disciplinas/POO/Transição do C para C++.pdf · Notação Funcional do Operador de Coerção (cast) 16 ... de novas operações

44

Ficheiros Fonte Uma actualização a ter em consideração é o nome dos ficheiros fonte. Uma vez que a linguagem C++ é uma nova linguagem os seus ficheiros fonte irão ter uma extensão diferente: habitualmente .cpp (C plus plus ou seja C++) ou .C ( letra maiúscula) em alguns compiladores para Unix, em contraste com a extensão .c dos programas em C.

Comentários Em C++ além de se poderem usar os comentários no estilo do C (ou seja '/*' para iniciar o comentário e '*/' para terminar o comentário), é acrescentado um novo tipo de comentário: o comentário de uma linha.

O comentário de uma linha é iniciado pela sequência de símbolos '//', e leva o compilador a ignorar qualquer caracter que se encontre a seguir a esses símbolos dentro da mesma linha. Esta forma de comentar é preferível por ser mais fácil de gerir e originar menos erros.

Constantes As constantes em C++ devem ser definidas a partir do modificador const, ou seja, serem definidas como variáveis acrescentando-se antes do tipo a palavra const. Convém recordar que sempre que se defina uma constante desta forma deve-se obrigatoriamente inicializar a mesma.

A forma anterior de definir constantes que utilizava a directiva #define deve ser abandonada, uma vez que é menos eficiente e pode originar erros de programação de difícil detecção.

Variáveis Em C as variáveis apenas podiam ser declaradas a seguir ao inicio de um bloco (após o caracter '{' ).

Em C++ é agora possível declarar uma variável em qualquer linha de código. Recomenda-se, no entanto, que as variáveis sejam declaradas o mais próximo possível do local onde são utilizadas. Esta recomendação não se aplica se forem usadas em vários conjuntos de instruções distintos dentro de um mesmo bloco, pelo que neste caso será preferível a sua declaração no início do bloco.

Outra novidade relaciona-se com as variáveis do tipo struct. Em C quando se declarava uma variável deste tipo era necessário escrever a palavra struct antes do nome da estrutura. Em C++ pode-se omitir a palavra struct e em consequência não ser necessária a criação de um novo tipo definido pelo utilizador para esse efeito.

Na listagem 1 apresentam-se alguns exemplos da declaração de constantes e variáveis

Extensão cpp para os ficheiros fonte

Comentários começados pelos símbolos // e válidos apenas na linha corrente

Definição de constantes a partir do modificador const

Declaração de variáveis em qualquer linha de código

Page 6: Escola Superior de Tecnologialtodi.est.ips.pt/jcordeiro/disciplinas/POO/Transição do C para C++.pdf · Notação Funcional do Operador de Coerção (cast) 16 ... de novas operações

55

LISTAGEM 1 Declarações de constantes e variáveis

Entrada e Saída de Dados Entrada e Saída de Dados Simples Muito embora as funções de entrada e saída da linguagem C funcionem em C++, estas não deverão ser utilizadas. Assim, existe um conjunto de novas operações de entrada e saída standard para a linguagem C++. Este conjunto de novas operações encontra-se declarado no ficheiro <iostream.h>, que vem assim substituir o antigo <stdio.h> da linguagem C.

As operações básicas de escrita no ecrã e de leitura do teclado irão ser protagonizadas pelas novas “operações” << e >> em vez dos antigos e confusos printf e scanf.

Para a escrita no ecrã utiliza-se cout e o operador binário << denominado neste contexto como operador de inserção. Na operação referida o primeiro operando é a ”variável” cout que representa o ecrã, e o segundo operando é o valor que se pretende escrever. Assim, para se visualizar o valor inteiro 15 pode-se escrever a seguinte linha de código:

cout << 15; Da mesma forma o valor real 15.5 pode ser escrito através de:

cout << 15.5;

Saída de dados feita através do operador de inserção << usado em conjunto com a “variável” cout

C C++

#include <stdio.h> #define JANEIRO 1 #define FEVEREIRO 2 . . . struct DATA{ int dia; int mes; int ano; }; /* Comentário estilo C */ void main(void) { struct DATA hoje; int dias[31]; /* declaração de dias */ int i; /* Declaração de i */ hoje.dia = 1; hoje.mes = JANEIRO; hoje.ano = 1998; for( i=0; i<31; i++ ) { dias[i] = 0; . . . } }

#include <iostream.h> const int JANEIRO = 1; const int FEVEREIRO = 2; . . . struct DATA{ int dia; int mes; int ano; }; // Comentário estilo C++ void main(void) { DATA hoje; // Sem a palavra struct hoje.dia = 1; hoje.mes = JANEIRO; hoje.ano = 1998; int dias[31]; // Declaração de dias for( int i=0; i<31; i++ ) // declaração de i { dias[i] = 0; . . . } }

Page 7: Escola Superior de Tecnologialtodi.est.ips.pt/jcordeiro/disciplinas/POO/Transição do C para C++.pdf · Notação Funcional do Operador de Coerção (cast) 16 ... de novas operações

66

De uma maneira geral o operando do lado direito pode ser um inteiro, um real (double ou float) ou qualquer outro dos tipos básicos. Também os tipos char* e void* são reconhecidos, sendo interpretados como, respectivamente, uma cadeia de caracteres e um endereço de memória e escritos no ecrã de acordo. Exemplo:

char *str="Teste do sistema\n"; cout << str; cout << (void *)str; Resultado:

Teste do sistema 0x25660098

É ainda possível escrever mais que um valor a partir da mesma instrução, bastando para isso encadear os diversos valores através do operador de inserção como no seguinte exemplo:

cout << "Peso: " << 12.2 << " Kgs.\n"; Resultado:

Peso: 12.2 Kgs.

De uma forma análoga, a leitura de valores a partir do teclado, é efectuada usando cin e o operador >> (operador de extracção). Os valores lidos são colocados na variável fornecida como segundo operando da operação de extracção, cin é o primeiro operando. Como exemplo da leitura de dois valores, um do tipo double e um inteiro (int) temos:

double dval; int ival; cout << "Valor real: "; cin >> dval; cout << "Valor inteiro: "; cin >> ival; A leitura para uma variável do tipo char* ou char[] equivale a ler uma palavra para o endereço de memória respectivo. Apenas uma palavra é lida, terminando a operação de leitura quando se encontrar um espaço branco. É de referir que também a leitura de valores, incluindo do tipo char, não recebe os espaços em branco.

Também é possível ler vários valores para um grupo de variáveis a partir de uma única instrução de leitura. Isto é conseguido fornecendo as variáveis separadas pelo operador de extracção como no seguinte exemplo:

cin >> dval >> ival;

Na listagem 2 mostram-se alguns exemplos de operações de escrita e leitura de dados simples.

::

Entrada de dados feita através do operador de extracção >> usado em conjunto com a “variável” cin

77

Page 8: Escola Superior de Tecnologialtodi.est.ips.pt/jcordeiro/disciplinas/POO/Transição do C para C++.pdf · Notação Funcional do Operador de Coerção (cast) 16 ... de novas operações

77

NOTA

Os símbolos '>>' e '<<' usados, respectivamente, nas operações de leitura e escrita de valores representam a direcção do fluxo de informação. Assim, para cin utiliza-se o símbolo '>>' a indicar que a informação flúi de cin para as variáveis e com cout '<<', fluindo a informação, aqui, no sentido dos valores para cout.

LISTAGEM 2 Instruções de entrada e saída de dados

Existem ainda outras formas de escrita e leitura de valores, entre elas será importante referir as funções de leitura get e getline e de escrita put.

A função get possui vários formatos adaptados a diferentes objectivos:

1. Leitura de caracteres - sem argumentos, é retornado o caracter lido do dispositivo de entrada.

2. Leitura de caracteres - com um argumento do tipo char em que o caracter é lido por referência para dentro da variável char passada como argumento.

C C++

#include <stdio.h> void main(void) { int i; char str[[80]]; printf("Olá mundo\n"); /* Leitura de um valor */ printf("Introduza um número: "); scanf("%d",&i); /* Mostrar o valor lido */ printf("O número introduzido foi: %d \n", i ); /* Leitura de uma palavra */ printf("Introduza uma palavra: " ); scanf("%s", str); /* Mostrar a palavra lida */ printf("A palavra intorduzida foi: "); printf("%s", str); }

Resultado: Olá mundo Introduza um número: 12 O número introduzido foi: 12 Introduza uma palavra: carro A palavra introduzida foi: carro

#include <iostream.h> void main(void) { int i; char str[[80]]; cout << "Olá mundo" << endl; // Leitura de um valor cout << "Introduza um número: "; cin >> i; // Mostrar o valor lido cout << "O número introduzido foi: " << i << "\n"; // Leitura de uma palavra cout << "Introduza uma palavra: "; cin >> str; // Mostrar a palavra lida cout << "A palavra introduzida foi: "; cout << str; }

Resultado:

Olá mundo

Introduza um número: 12

O número introduzido foi: 12

Introduza uma palavra: carro

A palavra introduzida foi: carro

Page 9: Escola Superior de Tecnologialtodi.est.ips.pt/jcordeiro/disciplinas/POO/Transição do C para C++.pdf · Notação Funcional do Operador de Coerção (cast) 16 ... de novas operações

88

3. Leitura de texto – com três argumentos em que o primeiro é a cadeia de caracteres que vai receber o texto, o segundo é o número de caracteres possíveis de armazenar na referida cadeia de caracteres e o terceiro, que se pode omitir, é o caracter que indica o fim da leitura que é por omissão o caracter ’\n’.

A função getline é idêntica na sua forma e funcionamento à função get usada com três argumentos com a diferença que o caracter que termina o texto é lido e descartado. A função get não descarta o referido caracter.

A função put leva como argumento um char e escreve-o no dispositivo de saída.

A utilização destas funções aparece associada à “variável” cin duma forma que pode parecer um pouco estranha: a seguir ao nome da variável segue-se um ponto e a chamada à função. A razão para este facto tem a ver com a programação orientada por objectos. A listagem 3 apresenta alguns exemplos de utilização destas funções.

O grupo de funções descrito tem como equivalente na linguagem C as funções getchar, putchar e gets (ou fgets).

LISTAGEM 3 Leitura de textos

C C++

#include <stdio.h> void main() { int i; char str[129]; char z1; printf("Ler uma linha de texto: "); /* Forma 1: int getchar() */ i=0; while ( (z1=getchar()) != '\n' ) str[i++]=z1; str[i] = '\0'; printf( "\nTexto: %s\n", str ); printf("Ler uma linha de texto: "); /* Forma 3: fgets(char *, int, FILE *) */ fgets(str, 129, stdin); printf( "\nTexto: %s\n", str ); }

#include <iostream.h> void main() { int i; char str[129]; char z1; cout << "Ler uma linha de texto: "; // Forma 1: int cin.get() i=0; while ( (z1=cin.get()) != '\n' ) str[i++]=z1; str[i] = '\0'; cout << endl << "Texto: "<< str << endl; cout << "Ler uma linha de texto: "; // Forma 2: cin.get(char &) i=0; do { cin.get(z1); str[i++]=z1; } while ( z1 != '\n' ); str[--i] = '\0'; cout << endl << "Texto: "<< str << endl; cout << "Ler uma linha de texto: "; // Forma 3: // cin.get(char *, int, char='\n') cin.get(str, 129); cout << endl << "Texto: "<< str << endl; }

Page 10: Escola Superior de Tecnologialtodi.est.ips.pt/jcordeiro/disciplinas/POO/Transição do C para C++.pdf · Notação Funcional do Operador de Coerção (cast) 16 ... de novas operações

99

Saída de Dados Formatada Em C era possível efectuar uma saída de dados formatada utilizando a instrução printf. Entre as funcionalidades oferecidas tinham-se o número mínimo de caracteres na escrita de um valor, o número de casas decimais de um valor real, a apresentação do sinal ou não para valores numéricos positivos, etc. Em C++ utilizando cout existem igualmente várias possibilidades de formatação da saída de dados.

A formatação da saída de dados em C++ é efectuada através de um “comando” especial, o manipulador, que é incluído na lista de informação a enviar para o ecrã através da operação de inserção. Os manipuladores podem levar argumentos. Os principais manipuladores e a sua funcionalidade encontram-se descritos na tabela 1.

ManipuladoresManipuladores Nome Argumento Descrição

endl --- Semelhante a ’\n’ em C. Limpa também o buffer de escrita

setw Número de caracteres

Total de caracteres com que se escreve o próximo valor

hex --- Passa a mostrar os valores inteiros na notação hexadecimal

oct --- Passa a mostrar os valores inteiros na notação octal

dec --- Passa a mostrar os valores inteiros na notação decimal

setprecision Número de casas decimais

Número de casas decimais para valores reais.

setiosflags (ios::fixed) Não mostrar o expoente.

setiosflags (ios::scientific) Notação cientifica (com expoente).

setiosflags (ios::showpoint) Mostrar as casas decimais, mesmo que sejam zeros .

setiosflags (ios::showpos) Mostrar sempre o sinal para números positivos

setiosflags (ios::internal) Colocar espaços no centro.

setiosflags (ios::left) Encostar à esquerda (espaços à direita)

setiosflags (ios::right) Encostar à direita (espaços à esquerda)

TABELA 1 Principais manipuladores para formatação de dados em C++

A exemplificação do uso dos manipuladores é feita na listagem 4.

Na operação de leitura de dados também existe um manipulador especial: ws cuja funcionalidade é descartar todos os espaços em branco que apareçam na leitura de dados.

NOTA

Quando se utilizam manipuladores em C++ deve-se incluir o ficheiro iomanip.h no início do programa, ou seja acrescentar a linha: #include <iomanip.h>.

A formatação da saída de dados é obtida através dos novos manipuladores da linguagem C++.

¿¿

Page 11: Escola Superior de Tecnologialtodi.est.ips.pt/jcordeiro/disciplinas/POO/Transição do C para C++.pdf · Notação Funcional do Operador de Coerção (cast) 16 ... de novas operações

1010

LISTAGEM 4 Exemplo de saída de dados formatada.

Funções No capítulo das funções em C++ foram introduzidas novidades muito importantes, entre elas estão a possibilidade de definir várias funções com o mesmo nome, a possibilidade de os argumentos poderem ser passados por referência e de estes poderem também possuir valores pré-definidos.

Funções inline A novidade mais simples no que diz respeito às funções é o novo modificador inline. Este modificador colocado na declaração da função antes do tipo de retorno leva a que o compilador em vez de colocar um salto para o código da função, nos locais em que esta for chamada, coloque directamente o código da função.

A vantagem da utilização de funções inline tem a ver com questões de eficiência, uma vez que o código está no local de chamada da função esta irá ser executada mais rapidamente, como desvantagem se a mesma for chamada diversas vezes o código dela irá estar repetido as mesmas vezes. Neste caso o executável do programa irá normalmente ocupar mais memória. Esta novidade foi introduzida principalmente devido a questões relacionadas com a eficiência na programação orientada por objectos.

O modificador inline deverá ser utilizado principalmente em funções pequenas que não possuam ciclos ou instruções de selecção do tipo switch. Também é necessário que o compilador veja a definição da função inline antes do local em que esta é chamada para que seja possível obter e colocar o seu código no local de chamada.

A utilização do modificador inline não obriga o compilador a colocar o código da função no local de chamada, é apenas um pedido para que isso aconteça.

Funções inline permitem a colocação directa do código da função nos locais em que esta é chamada

C C++

#include <stdio.h> int main(void) { printf("\n"); printf("%8.2lf\n",3298.2341); printf("Teste"); printf("\n%15s", "Hello there "); printf("----" ); } RESULTADO:

3298.23 Teste Hello there ----

#include <iostream.h> #include <iomanip.h> int main(void) { cout << endl << setw(8) // Total de caracteres << setprecision(2) // Casas decimais << setiosflags(ios::fixed) // s/ expoente << 3298.2341 << endl << "Teste"; cout << endl << setw(15) << "Hello there "; cout << "----"; return 0; } RESULTADO:

3298.23

Teste

Hello there ----

Page 12: Escola Superior de Tecnologialtodi.est.ips.pt/jcordeiro/disciplinas/POO/Transição do C para C++.pdf · Notação Funcional do Operador de Coerção (cast) 16 ... de novas operações

1111

Redefinição de Funções Uma das novidades mais importantes do C++ diz respeito à redefinição de funções. Em C++ é possível definir várias funções com o mesmo nome.

Uma vez que as funções redefinidas irão ter o mesmo nome a distinção entre elas é feita pelos argumentos com que são chamadas. Os argumentos podem ser diferenciados pelo número e/ou pelo seu tipo.

O tipo de retorno não permite diferenciar duas funções com o mesmo nome e o mesmo tipo e número de argumentos.

LISTAGEM 5 Redefinição de funções.

NOTA

Quando existirem dúvidas por parte do compilador sobre qual a função redefinida a ser chamada é gerado um erro de compilação onde se menciona uma chamada de função ambígua

Funções com o mesmo nome são possíveis e distinguem-se pelo número e/ou tipo dos seus parâmetros

C C++ #include <stdio.h> void equalline(); void minusline(); void astline(); void main(void) { astline(); printf(" Aluno Nota\n"); minusline(); printf(" Joao Martins 14 \n"); printf(" Pedro Oliveira 9 \n"); printf(" Jose Silva 11 \n"); equalline(); } void astline() { int j; for (j=0; j<30; j++) printf("*"); printf("\n"); } void equalline( void ) { int j; for (j=0; j<30; j++) printf("="); printf("\n"); } void minusline( void ) { int j; for (j=0; j<25; j++) printf("-"); printf("\n"); }

#include <iostream.h> void charline( void ); void charline( char car ); void charline( char car, int ncar ); void main(void) { charline(); cout << " Aluno Nota" << endl; charline('-',25); cout << " Joao Martins 14 " << endl << " Pedro Oliveira 9 " << endl << " Jose Silva 11 " << endl; charline('='); } void charline( void ) { for (int j=0; j<30; j++) cout << '*'; cout << endl; } void charline( char car ) { for (int j=0; j<30; j++) cout << car; cout << endl; } void charline( char car, int ncar ) { for (int j=0; j<ncar; j++) cout << car; cout << endl; }

RESULTADO: ******************************

Aluno Nota

-------------------------

Joao Martins 14

Pedro Oliveira 9

Jose Silva 11

Page 13: Escola Superior de Tecnologialtodi.est.ips.pt/jcordeiro/disciplinas/POO/Transição do C para C++.pdf · Notação Funcional do Operador de Coerção (cast) 16 ... de novas operações

1212

No exemplo da listagem 5 mostra-se como três funções com objectivos semelhantes (escrever uma linha de caracteres no ecrã), que em C necessitavam de ter identificadores diferentes, podem ser definidas em C++ com um nome apenas.

Argumentos Pré-definidos É possível omitir alguns argumentos na chamada de uma função desde que na declaração ou na definição da função (e em apenas um dos sítios) apareça o valor que o argumento irá ter se for omitido.

O valor por omissão é fornecido juntando um sinal de igual seguido desse valor a seguir ao nome do argumento.

NOTA

Os argumentos por omissão são sempre fornecidos a começar no último e sequencialmente

LISTAGEM 6 Versão com argumentos pré-definidos do programa da listagem 5

Transmissão de Parâmetros por Referência Em C++ é possível passar parâmetros por valor e por referência. Os

argumentos passados para uma função podem agora ser passados por referência à semelhança do que acontece na linguagem PASCAL quando se utiliza a palavra VAR antes do argumento formal.

Apenas as variáveis podem ser passadas como parâmetros por referência.

Omissão de argumentos na chamada de uma função através da atribuição de valores pré-definidos aos parâmetros na declaração ou na definição da função

#include <iostream.h> void charline( char car='*', int ncar=30 ); void main(void) { charline(); cout << " Aluno Nota" << endl; charline('-',25); cout << " Joao Martins 14 " << endl << " Pedro Oliveira 9 " << endl << " Jose Silva 11 " << endl; charline('='); } void charline( char car, int ncar ) { for (int j=0; j<ncar; j++) cout << car; cout << endl; }

Page 14: Escola Superior de Tecnologialtodi.est.ips.pt/jcordeiro/disciplinas/POO/Transição do C para C++.pdf · Notação Funcional do Operador de Coerção (cast) 16 ... de novas operações

1313

Para indicar um argumento por referência utiliza-se o símbolo & imediatamente antes do nome do parâmetro.

As variáveis passadas por referência irão reflectir as alterações ao seu valor feitas no interior da função.

LISTAGEM 7 Passagem de parâmetros por referência e redefinição de funções

Retorno de Valores por Referência Tal como é possível passar valores por referência, também é possível retornar por referência. O retorno por referência funciona como se retornasse uma variável. A principal vantagem deste método é evitar que se produza uma cópia da variável no retorno da função o que resultaria numa perda de eficiência.

É preciso tomar cuidado com esta forma de retornar, uma vez que a variável retornada tem que ter existência fora da função que a retornou, o que impossibilita o retorno de variáveis locais.

Passagem por referência de parâmetros é possível usando o operador & antes do nome do argumento no cabeçalho da função

Retorno por referência é possível usando o operador & antes do nome da função no cabeçalho da função

C C++

#include <stdio.h> #include <math.h> struct complex { double x,y; }; int iabs( int val ) { if( val < 0 ) return( -val ); return( val ); } /* passagem por valor de val */ double cabs( struct complex val ) { return sqrt(val.x*val.x + val.y*val.y); } void main( void ) { int i=-10; double d=-15.0; struct complex c={-2.0,3.0}; long l=-10L; printf("Int i -> %d\n" , iabs(i) ); printf("Double d -> %lf\n", fabs(d) ); printf("Complex c -> %lf\n", cabs(c) ); printf("Long l -> %ld\n", labs(l) ); }

#include <iostream.h> #include <math.h> struct complex { double x,y; }; inline double abs( double val ) { if( val < 0.0 ) return( -val ); return( val ); } inline long abs( long val ) { if( val < 0 ) return( -val ); return( val ); } // passagem por referência de val inline double abs( complex &val ) { return sqrt(val.x*val.x + val.y*val.y); }

void main( void ) { int i=-10; double d=abs(-15.0); complex c={-2.0,3.0}; long l=-10L; cout << "Int i ->" << abs(i) << endl; cout << "Double d ->" << abs(d) << endl; cout << "Complex c ->" << abs(c) << endl; cout << "Long l ->" << abs(l) << endl; }

Page 15: Escola Superior de Tecnologialtodi.est.ips.pt/jcordeiro/disciplinas/POO/Transição do C para C++.pdf · Notação Funcional do Operador de Coerção (cast) 16 ... de novas operações

1414

Estruturas de Dados Dinâmicas Em C++ a reserva e a libertação de memória deixam de utilizar respectivamente as funções do C malloc (ou equivalente) e free, passando a usar os novos operadores new e delete.

Operador new O operador new é utilizado em C++ em substituição de malloc. Uma vantagem na utilização deste operador é o facto de não ser necessário utilizar a operação de cast para converter o ponteiro retornado num ponteiro compatível com a variável de afectação.

A forma de utilização deste operador é:

<ponteiro> = new <tipo>;

ou

<ponteiro> = new <tipo> [<total de elementos a alocar>];

Exemplo: char *str = new char [20+1];

Operador delete O operador delete é utilizado em C++ com o objectivo de libertar a memória previamente alocada por new.

Uma nota importante na utilização deste operador é que se torna possível libertar memória a partir dum ponteiro que possua o valor NULL, esta acção que seria desastrosa em C na função free, não irá surtir qualquer efeito em C++.

Forma de utilização:

delete <ponteiro>;

ou

delete [ ] <ponteiro>;

Exemplo: delete [] str;

Na listagem 8 apresenta-se um exemplo da utilização de estruturas de dados dinâmicas através dos operadores new e delete.

Reserva de memória utiliza o novo operador new em vez da função malloc

Libertação de memória reservada utiliza o novo operador delete em vez da função free

Page 16: Escola Superior de Tecnologialtodi.est.ips.pt/jcordeiro/disciplinas/POO/Transição do C para C++.pdf · Notação Funcional do Operador de Coerção (cast) 16 ... de novas operações

1515

LISTAGEM 8 Alocação e libertação de memória

C C++ #include <stdio.h> #include <string.h> typedef struct telefone{ char *nome; long *telefone; }TELEFONE; #define max_numeros 100 void main( void ) { TELEFONE *agenda; char str[128+1]; long tf; char resp; int i,j; str[0] = '\0'; agenda = (TELEFONE *)malloc( sizeof(TELEFONE)*max_numeros)); /* Alocar array de telefones */ if( agenda == NULL) return; printf("%30s", "AGENDA TELEFONICA"); for( i=0; i<max_numeros; i++ ) { printf("\n\n"); printf("Deseja inserir mais números ? "); fflush(stdin); scanf("%c", &resp); if( resp == 'n' || resp == 'N' ) break; printf("Nome: "); fflush(stdin); fgets(str,128,stdin); printf("Telefone: "); scanf(" %ld", &tf); agenda[i].nome = malloc( strlen(str)+1 ); if( agenda[i].nome ) strcpy(agenda[i].nome, str); agenda[i].telefone = (long *) malloc( sizeof(long) ); if( agenda[i].telefone ) *(agenda[i].telefone) = tf; } if( i ) printf("%30s","AGENDA TELEFONICA"); for( j=0; j<i; j++ ) { printf("\nNome: %s",agenda[j].nome); printf("\nTelefone: %ld\n", *agenda[j].telefone); } /* Libertar toda a memória alocada */ for( j=0; j<i; j++) { if( agenda[j].nome ) free(agenda[j].nome); if( agenda[j].telefone ) free(agenda[j].telefone); } free( agenda ); }

#include <iostream.h> #include <iomanip.h> #include <string.h> struct TELEFONE{ char *nome; long *telefone; }; const max_numeros = 100; void main( void ) { TELEFONE *agenda; char str[128+1]; long tf; char resp; str[0] = '\0'; agenda = new TELEFONE [max_numeros]; //Alocar array de telefones if( agenda == NULL ) return; cout << setw(30) << "AGENDA TELEFONICA"; for( int i=0; i<max_numeros; i++ ) { cout << endl << endl << "Deseja inserir mais números ? "; cin >> ws >> resp; if( resp == 'n' || resp == 'N' ) break; cout << "Nome: "; cin >> ws; cin.getline(str,128); cout << "Telefone: "; cin >> tf; agenda[i].nome=new char [strlen(str)+1]; if( agenda[i].nome ) strcpy(agenda[i].nome, str); agenda[i].telefone = new long; if( agenda[i].telefone ) *(agenda[i].telefone) = tf; } if( i ) cout << endl << endl << setw(30) << "AGENDA TELEFONICA"; for( int j=0; j<i; j++ ) { cout << endl << "Nome: " << agenda[j].nome << endl; cout << "Telefone: " << *(agenda[j].telefone) << endl; } // Libertar toda a memória alocada for( j=0; j<i; j++) { delete [] agenda[j].nome; delete agenda[j].telefone; } delete [] agenda; }

Page 17: Escola Superior de Tecnologialtodi.est.ips.pt/jcordeiro/disciplinas/POO/Transição do C para C++.pdf · Notação Funcional do Operador de Coerção (cast) 16 ... de novas operações

1616

Tópicos variados Notação Funcional do Operador de Coerção (cast) A operação de coerção (cast) que permite a conversão entre tipos diferentes, possui uma nova notação em C++. Enquanto em C esta operação obtinha-se colocando o tipo, para o qual se pretendia converter, entre parênteses antes do valor a converter (Ex. Conversão de double para int à (int)32.3), agora em C++ deve-se fazer colocando entre parênteses o valor e não o tipo (Ex. double para int à int(32.3) ). Esta notação tem uma sintaxe semelhante à das funções cujo nome é dado pelo tipo da conversão e o argumento pelo valor a converter.

Inicialização Dinâmica de Variáveis Outra novidade importante é que se podem inicializar dinamicamente as variáveis locais e globais, ou seja, o seu valor inicial pode ser obtido através de uma expressão ou da chamada de uma função.

Variáveis por Referência Um novo tipo de variáveis que aparece em C++ são as variáveis de referência. É possível criar variáveis que não são mais que referências a variáveis que já existem. Isto funciona como se fosse um outro nome para uma mesma variável. Estas variáveis devem ser obrigatoriamente inicializadas quando são criadas.

Ficheiros O tratamento de ficheiros em C++ é feito principalmente com base em variáveis dos novos tipos ifstream (para ficheiros de leitura), ofstream (para ficheiros de escrita) e fstream (para escrita e leitura). Os ficheiros de texto possuem também uma abordagem diferente da dos ficheiros binários.

As operações básicas com ficheiros mantêm-se inalteradas em C++. Assim é possível abrir e fechar ficheiros, efectuar operações de leitura e escrita e gerir o ponteiro de escrita e leitura dentro dos ficheiros.

Em primeiro lugar a abertura de ficheiros é feita declarando uma variável do tipo ifstream para operações de leitura ou do tipo ofstream para operações de escrita. O nome do ficheiro pode ser fornecido entre parênteses directamente na declaração da variável ou através de uma função open que é chamada associada à variável referida. Por exemplo, para abrir o ficheiro “teste.txt” para escrita poderia-se escrever:

ofstream fich( "teste.txt" );

ou alternativamente:

ofstream fich;

fich.open("teste.txt");

O ficheiro é automaticamente fechado quando a variável que lhe deu origem deixa de existir, ou seja no fim do bloco onde foi declarada.

É possível, de qualquer forma, fechar um ficheiro através de uma função close associada à variável que lhe deu origem:

fich.close();

Operação de cast utiliza os parênteses para os valores e não para o tipo

11

Page 18: Escola Superior de Tecnologialtodi.est.ips.pt/jcordeiro/disciplinas/POO/Transição do C para C++.pdf · Notação Funcional do Operador de Coerção (cast) 16 ... de novas operações

1717

Quando se trabalha com ficheiros de texto utiliza-se a mesma forma de escrita e leitura que quando se trabalha com o ecrã e o teclado. Por exemplo para escrever a linha “Hoje é Sábado dia 10” poderia-se fazer:

fich << ”Hoje é Sábado dia ” << 10 << endl;

Neste caso apenas a “variável” cout é substituída pela variável que representa o ficheiro.

As funções get, getline e put referidas na secção de escrita e leitura de dados também podem ser utilizadas.

Em relação à utilização de ficheiros binários, estes requerem uma abertura efectuada de forma diferente. A função de abertura de ficheiro descrita anteriormente, utiliza na realidade a nova funcionalidade da linguagem C++ que possibilita os argumentos por omissão. De facto, a função referida aplicada a variáveis do tipo ofstream possui os seguintes argumentos:

open(char*,int=ios::out,int=filebuf::openprot);

O primeiro argumento leva o nome do ficheiro a abrir e o segundo o modo de abertura, que no caso referido é por omissão o modo para escrita no ficheiro. Assim sendo, para abrir ficheiros no modo binário, era necessário referir este modo na abertura do ficheiro.

Os diferentes modos de abertura dos ficheiros são essencialmente os mesmos que em C embora com uma sintaxe diferente que acrescenta ios:: antes da abreviatura do modo. Podem-se igualmente juntar vários modos utilizando o operador ‘ou’ ao nível do bit.

É importante referir ainda que estes mesmos parâmetros estão disponíveis quando se abre o ficheiro a partir da definição da variável associada. Assim, por exemplo, para abrir um ficheiro para leitura em modo binário poderia-se utilizar:

ifstream fich( "teste.dat", ios::in | ios::binary );

ou então,

ifstream fich;

fich.open("teste.dat", ios::in | ios::binary );

Os ficheiros de texto utilizam os operadores >> e << associados a variáveis dos tipos ifstream e ofstream para leitura e escrita de dados

��

Page 19: Escola Superior de Tecnologialtodi.est.ips.pt/jcordeiro/disciplinas/POO/Transição do C para C++.pdf · Notação Funcional do Operador de Coerção (cast) 16 ... de novas operações

1818

Os modos de abertura encontram-se resumidos na tabela 2.

Modos de abertura de ficheiModos de abertura de ficheirosros Modo Função

in Para leitura

out Para escrita

ate Posiciona-se no fim do ficheiro após a abertura (at end)

App Para adicionar dados (append)

Trunc Inicia o ficheiro a zero (limpa-o se existir)

nocreate Falha a abertura se o ficheiro existir

noreplace Falha a abertura se o ficheiro não existir

binary Abre em modo binário

TABELA 2 Lista dos modos de abertura dos ficheiros em C++

As operações de escrita ou leitura em modo binário utilizam habitualmente as novas funções read e write associadas também às variáveis dos ficheiros. Estas funções possuem dois argumentos, o primeiro o endereço da posição de memória onde se encontra a informação a ler ou a escrever, e o segundo o número de bytes a ler ou a escrever.

As funções get e put descritas anteriormente para os ficheiros de texto também estão disponíveis para utilização com ficheiros binários.

O fecho de ficheiros binários funciona da mesma forma da dos ficheiros de texto.

Uma outra funcionalidade na utilização de ficheiros em C era o controlo do posicionamento de um ponteiro de escrita ou leitura dentro dos ficheiros. Esta funcionalidade é disponibilizada em C++ através de ponteiros independentes para escrita e leitura, controlados pelas funções seekg, seekp, tellg e tellp.

A função seekg leva como argumento a posição de leitura (seekg significa seek get) contada a partir do início do ficheiro. Esta função possui uma segunda forma com dois argumentos em que o primeiro é a posição relativa e o segundo o local de inicio na determinação da posição efectiva. O local de inicio pode ser dado por ios::beg – princípio do ficheiro, ios::cur – posição corrente ou ios::end - fim do ficheiro). A função seekp possui igualmente as mesmas possibilidades em relação ao ponteiro de escrita (seekp significa seek put).

Por outro lado as funções tellg e tellp permitem obter respectivamente as posições actuais dos ponteiros de leitura e de escrita nos ficheiros.

Existem ainda um conjunto de funções de teste associadas à utilização de ficheiros, que são usadas em conjunto com as variáveis que representam os ficheiros e que se encontram descritas na tabela 3.

Os ficheiros binários são lidos utilizando as funções read ou get e escritos com as funções write ou put

��

Page 20: Escola Superior de Tecnologialtodi.est.ips.pt/jcordeiro/disciplinas/POO/Transição do C para C++.pdf · Notação Funcional do Operador de Coerção (cast) 16 ... de novas operações

1919

Funções de teste em ficheirosFunções de teste em ficheiros nome argumento descrição

eof --- Retorna True se o ponteiro estiver no fim do ficheiro

bad --- Retorna True se existiu erro na última operação com o ficheiro

fail --- Retorna True se falhou a última operação com o ficheiro

good --- Retorna True se todas as funções anteriores retornarem False

TABELA 3 Principais funções de teste em operações com ficheiros

LISTAGEM 9 Exemplo de escrita e leitura em ficheiros de texto

C C++

#include <stdio.h> #include <conio.h> void main() { FILE *fout, *fin; char str[129]; fout = fopen("\\AUTOEXEC.BAT","wt"); if( fout == NULL ) { printf("Erro a abrir o ficheiro"); return; } fprintf( fout, "Teste de escrita " ); fprintf( fout, "em ficheiro\n" ); fprintf( fout, "%lf\n", 10.4 ); fclose( fout ); fin = fopen("texto.dat","rt"); if( fin == NULL ) { printf("Erro a abrir o ficheiro"); return; } fscanf(fin,"%s",str); while( !feof(fin) ) { printf("%s ", str ); fscanf(fin,"%s",str); } fclose(fin); getch(); }

#include <fstream.h> #include <conio.h> void main() { ofstream fout("texto.dat"); // ou fout.open("texto.dat"); if( !fout ) { cout << "Erro a abrir o ficheiro"; return; } fout << "Teste de escrita " << "em ficheiro" << endl; fout << 10.4 << endl; fout.close(); ifstream fin("texto.dat"); char str[129]; if( !fin ) { cout << "Erro a abrir o ficheiro"; return; } fin >> str; while( !fin.eof() ) { cout << str << " "; fin >> str; } fin.close(); // Não é necessário getch(); }

Page 21: Escola Superior de Tecnologialtodi.est.ips.pt/jcordeiro/disciplinas/POO/Transição do C para C++.pdf · Notação Funcional do Operador de Coerção (cast) 16 ... de novas operações

2020

Modelos (templates) Em C++ é possível criar funções padrão (templates), que servem de modelo para a criação de funções. Nestas funções um ou mais dos tipos de dados dos argumentos e do valor de retorno não são fornecidos directamente no cabeçalho da função. Esta característica permite que se criem funções com o código idêntico, que possuem implementações diferentes motivadas pelos tipos de dados dos argumentos.

A título de exemplo admita-se uma função max que devolve o maior dos valores que eram passados como argumentos. Se esses valores se referissem a inteiros, a função poderia ser:

int max(int x, int y) { if( x > y ) return x; return y; };

Se, por outro lado estivéssemos a lidar com valores reais, então teríamos:

double max(double x, double y) { if( x > y ) return x; return y; }; Embora o tipo dos argumentos tenha sido alterado, o código da função permaneceu idêntico. As funções padrão permitem que os tipos envolvidos no protótipo da função funcionem como variáveis. Segundo este princípio a função max iria ter então a seguinte definição:

template <class T> T max(T x, T y) { if( x > y ) return x; return y; };

T é neste caso um nome escolhido pelo programador dado a um tipo arbitrário. Uma chamada à função max na seguinte forma:

double z = max( 2.0, 3.4);

levaria o compilador a criar um função max com o tipo T concretizado como um double. Se houvesse uma nova chamada à função max, em que agora o tipo envolvido fosse, por exemplo, o tipo char, então seria criado o código de uma outra nova função max onde T seria substituído por char.

Funções padrão permitem definir modelos para a criação de funções que possuem o mesmo código aplicado a argumentos de tipos diferentes

//

Page 22: Escola Superior de Tecnologialtodi.est.ips.pt/jcordeiro/disciplinas/POO/Transição do C para C++.pdf · Notação Funcional do Operador de Coerção (cast) 16 ... de novas operações

2121

Como regra sempre que o compilador encontra uma chamada a uma função segue os seguintes passos para resolver essa chamada:

1. Encontrar a função respectiva que deverá possuir o mesmo número de argumentos e do mesmo tipo dos utilizados na chamada à função. Utilizar a função encontrada.

2. Caso não encontre a função descrita em 1. Procura uma função padrão em que os tipos dos argumentos envolvidos se ajustem ao modelo. Caso isso aconteça cria essa função para os tipos envolvidos.

3. Em último caso se não resolveu a chamada à função em 1. ou 2. tenta a conversão dos valores dos argumentos de forma a se ajustarem às funções existentes. Esta situação ocorre apenas para funções realmente definidas e não para funções padrão.

Na definição de funções padrão utiliza-se uma linha inicial com a lista de tipos diferentes que poderão constar da lista de argumentos. Esta lista aparece a seguir à palavra template e entre os símbolos < e >. Os nomes dos tipos deverão ser precedidos da palavra reservada class. Sintaxe usada:

template <class nome1 [, class nome2, ...]>

Como regras na definição de funções padrão deve-se obedecer ao seguinte:

1. Os tipos declarados na lista de tipos devem aparecer obrigatoriamente pelo menos uma vez na lista de argumentos da função.

2. Os tipos declarados podem ser utilizados mais que uma vez na lista de argumentos e podem ser igualmente utilizados como tipo de retorno.

3. Podem coexistir tipos básicos ou tipos definidos anteriormente conjuntamente com os tipos declarados na lista de argumentos da função.

LISTAGEM 10 Utilização de funções padrão

ÄÄ

#include <iostream.h> #include <string.h> template <class T> T max(T x, T y) { return (x > y) ? x : y; }; char *max(char *str1, char *str2) { if(strcmp(str1,str2)>0) return str1; return str2; }

void main() { double x=1.0, y=2.0; cout << "valor double maximo: "<< max(x,y) << endl; // é criada a função double max(double, double) char z1 = 'a', z2 = 'b'; cout << "valor char maximo: "<< max(z1,z2) << endl; // é criada a função char max(char, char) char *str1="Texto um", *str2 = "Texto dois"; cout << "valor texto maximo: " << max(str1,str2) << endl; // é utilizada a função char *max(char*, char*) }

Page 23: Escola Superior de Tecnologialtodi.est.ips.pt/jcordeiro/disciplinas/POO/Transição do C para C++.pdf · Notação Funcional do Operador de Coerção (cast) 16 ... de novas operações

2222

Redefinição de operadores Regra geral todos os operadores do C++ estão preparados para trabalhar com os tipos de dados pré-definidos na linguagem. Por exemplo, o operador soma (+) funciona com os tipos inteiro, caracter ou mesmo ponteiro. Mas se o programador definir um tipo novo, por exemplo a partir de uma estrutura, o compilador não consegue realizar a operação e gera uma mensagem de erro.

Em C++ é possível fornecer uma função para a realização de uma determinada operação que envolva operadores. Esta função irá então ser chamada automaticamente e realizará a operação. Isto apenas será possível se pelo menos um dos operandos for de um tipo definido pelo utilizador.

Por exemplo se tivermos o seguinte tipo

struct COMPLEXO{ double real; double imag; }; podemos fazer com que as seguintes linhas de código funcionem:

COMPLEXO c1={1.2,-2.3}, c2={1.1,1.0}, c3; C3 = c2 + c1;

bastando para isso redefinir a operação soma para operandos do tipo COMPLEXO.

A redefinição da operação passa assim pela criação de uma função especial que irá ser chamada quando a operação e o tipo dos operandos corresponderem à função criada. Esta função especial é caracterizada por possuir como nome a palavra reservada operator seguida do símbolo do operador e como argumentos variáveis do mesmo tipo dos operandos. Retomando o exemplo anterior teríamos o seguinte código para a redefinição da operação de soma:

COMPLEXO operator + ( COMPLEXO c1, COMPLEXO c2 ) { COMPLEXO aux; aux.real = c1.real + c2.real; aux.imag = c1.imag + c2.imag; return aux; } Como regra geral todos os operadores podem ser redefinidos excepto os da tabela 4. Deve-se ter em atenção que os argumentos da função correspondem aos operandos, o que significa que os operadores unários irão possuir funções com um argumento apenas.

A redefinição das operações associadas aos operadores é efectuada fornecendo a função: operator <símbolo do operador> (. . .)

øø

Page 24: Escola Superior de Tecnologialtodi.est.ips.pt/jcordeiro/disciplinas/POO/Transição do C para C++.pdf · Notação Funcional do Operador de Coerção (cast) 16 ... de novas operações

2323

Operadores não redefiniveisOperadores não redefiniveis ?:

.

::

.*

TABELA 4 Operadores não redefiniveis

Uma redefinição de operadores muito útil é a redefinição do operador << para a operação de escrita através de cout e do operador >> para a operação de leitura através de cin.

Na realidade cout funciona como uma variável de um tipo pré-definido na linguagem: o tipo ostream. A operação de escrita no ecrã resulta então da redefinição que é feita do operador << para que ele funcione com este tipo da forma conhecida. É possível, no entanto, redefinir esta operação para o segundo operando de um novo tipo definido pelo utilizador. Por exemplo para a escrita de um COMPLEXO utilizando cout poderia-se redefinir a operação anterior da seguinte forma:

ostream & operator<<(ostream &os, COMPLEXO c1 ) { os << '(' << c1.real << ',' << c1.imag << ')'; return os; } Para a leitura de valores de tipos definidos pelo utilizador pode-se, de uma forma análoga, redefinir o operador >>. Note-se que neste caso cin funciona como uma variável do tipo istream. Teríamos então:

istream & operator>>(istream &is, COMPLEXO &c1 ) { cout << “Real: “; is >> c1.real; cout << “Imag: “; is >> c1.imag; return is; }

Os operadores >> e << redefinidos para istream e ostream permitem a leitura e escrita de tipos de dados definidos pelo utilizador nas operações de entrada e saída de dados

qq

Page 25: Escola Superior de Tecnologialtodi.est.ips.pt/jcordeiro/disciplinas/POO/Transição do C para C++.pdf · Notação Funcional do Operador de Coerção (cast) 16 ... de novas operações

2424

Na listagem 11 dá-se um exemplo completo de um programa envolvendo a redefinição dos operadores.

LISTAGEM 11 Redefinição de operadores

#include <iostream.h> struct COMPLEXO{ double real; double imag; }; COMPLEXO operator + (COMPLEXO c1, COMPLEXO c2) { c1.real = c1.real + c2.real; c1.imag = c1.imag + c2.imag; return c1; } COMPLEXO operator + (COMPLEXO c1, double val) { c1.real = c1.real + val; return c1; } ostream &operator<<(ostream &os, COMPLEXO c1) { os << '(' <<c1.real<< ',' <<c1.imag<< ')'; return os; } istream &operator>>(istream &is, COMPLEXO &c1) { cout << endl << "Real: "; is >> c1.real; cout << "Imag: "; is >> c1.imag; return is; }

void main() { COMPLEXO c1 = {2.0,3.0}, c2={3.2,-1.3}, c3; c3 = c1 + c2; cout << endl<< "c3:" << c3 <<endl; cout << c3 + 2.0; cin >> c1; cout << c3 + c1; } Resultado:

c3(5.2,1.7)

(7.2,1.7)

Real: -1

Imag: 4

(4.2,5.7)