Este material trata de *alguns* aspectos da linguagem C++ que não estão presentes nas versões mais antigas da linguagem C.
A entrada e saída “usual” de C é feita via funções printf e scanf que utiliza os fluxos stdout e stdin, em C++ o mecanismo “usual” de entrada e saída (teclado/tela) é a utilização dos fluxos cout e cin (character output e character input) e as funções “implícitas” (operator<<() e operator>>() existem dezenas, centenas destas funções, este aspecto da linguagem C++ é tratado em material mais à frente). Além destas funções implícitas podem ser usados “manipuladores” (C++ manipulators).
Alguns dos manipuladores de C++ #include <iomanip>
endl
atua na hora escreve "nova linha"(new line)
setw(int) o mesmo que width(int)
atua no próximo elemento a ser impresso, largura do campo
setfill(char)
é útil no contexto de um setw(), se um valor não esgota a largura o caractere
preenche ao invés do default "branco".
right ou left
é útil no contexto de um setw(), default right, onde posicionar os caracteres
do elemento a ser impresso
ex: cout<<setfill('*')<<setw(20)<<34<<"@@@"<<endl;
a saida deve ser
******************34@@@
ex: cout<<setfill('*')<<setw(20)<<left<<34<<"@@@"<<endl;
a saida deve ser
34******************@@@
setprecision(int)
numero de dígitos à direita do ponto de elementos do tipo ponto flutuante.
fixed
exibir a parte inteira do ponto flutuante
scientific
notação científica.
ex: cout<<123456.7890123<<endl;
cout<<fixed<<123456.7890123<<endl;
cout<<scientific<<123456.7890123<<endl;
saida:
123457
123456.789012
1.234568e+005
boolalpha noboolalpha
imprimir os strings true ou false
outros
skipws noskipws showpoint, noshowpoint, uppercase, nouppercase, dec, oct, hex,
setbase(8|10|16), showbase, noshowbase, ends, showpos, noshowpos, internal,
flush, unitbuf, nounitbuf, setiosflags(), resetiosflags()
-------
variáveis & tipos
A linguagem C++ define vários tipos. Assim como na linguagem C alguns tipos são básicos ou primitivos (p.ex. int, double, char) e outros tipos são definidos a partir dos tipos primitivos e algumas vezes são denominados tipos complexos. A linguagem C também permite a definição de tipos complexos, por exemplo através do mecanismo de definição de estruturas (struct), mas a linguagem C++ estende o mecanismo de definição de estruturas e define vários outros mecanismos. Vários tipos da linguagem C++ são definidos utilizando bibliotecas, que são conjuntos de unidades précompiladas de dados e códigos.
Tipos aritméticos
|
Tipo |
Significado |
|
bool |
domínio de dois valores que podem ser
representados por dois literais: |
|
char |
dominio dos caracteres usualmente codificados via ASCII 8 bits |
|
wchar_t |
domínio de caracteres com codificação em 16 bits |
|
short |
(short int) inteiros com pelo menos 16 bits |
|
int |
inteiros com pelo menos 16 bits |
|
long |
(long int) inteiros com pelo menos 32 bits |
|
float |
ponto flutuante com pelo menos 6 digitos de precisão na base 10 |
|
double |
ponto flutuante com pelo menos 10 dígitos de precisão na base 10 |
|
long double |
ponto flutuante com extensão (pelo menos 10 dígitos) |
A linguagem C++ permite um trecho de programa como este:
bool b;
b=true;
if(b) cout<<”b e’ verdadeiro”<<endl;
ou ainda
bool aceitar(){
cout<<"Voce deseja
prosseguir?(s/n)\n";
char resposta=0;
cin>>resposta;
return resposta=='s';
}
A linguagem C++ define tipos apropriados para as variáveis prédefinidas cout e cin (cout e cin de certo modo equivalem ao stdout e stdin da linguagem C; deve ser observado que a “ênfase” em C é nas funções printf() e scanf() e os objetos destino e origem stdin/stdout ficam implícitos a estas funções, a ênfase em C++ desloca-se para os objetos cout e cin e as dezenas/centenas de funções operator<<() ficam obnubiladas como simples operadores). Os tipos de cout e cin redefinem os operadores << e >> como (“inserir no fluxo” e “extrair do fluxo”) ou (“enviar” e “obter”) ou (“stream insertion” and “stream extraction”) respectivamente. As variáveis (os objetos) cin e cout correspondem aos fluxos padrão de entrada e saída respectivamente e serão vistos mais à frente na disciplina.
A linguagem C++ introduz o tipo bool como sendo “aritmético” (existe o tipo “booleano”, mas o falso corresponde ao int 0 e true corresponde ao int 1) e utiliza as operações lógicas e aritméticas que já eram definidas em C (além de vários novos aspectos).
Operadores aritméticos:
+(unário), +(binário), -(unário), -(binário), *, /, %
Operadores de comparação
==, !=, <, >, <=, >=
Nas atribuições e operações aritméticas, C++ faz conversões entre os tipos básicos e portanto eles podem ser misturados de forma livre.
-------
O espaço de nomes em C se reduz “grosso modo” ao escopo global (fora das funções) e escopo local (dentro das funções) [se desconsiderarmos que o espaço de nomes de cada arquivo pode ser explorado via definições globais com o modificador “static”]. A linguagem C++ possui diretivas de definição (namespace <nome>) e uso (p.ex. using namespace <nome>) de escopos de nomes. Não vamos discutir todas as características destas diretivas, mas vamos ver como funciona o conceito. Em um programa C++ podemos definir variáveis em um escopo similar ao escopo global e local de C. Mas podemos definir novos escopos. Uma vez definido um certo escopo podemos identificá-lo usando o operador de resolução de escopo “dois pontos dois pontos”.
#include <cstdlib>
#include <iostream>
using namespace std;
namespace A{ int i=10;}
namespace B{ int i=20;}
int main(int argc, char *argv[]){
cout<<A::i<<endl;
cout<<B::i<<endl;
system("PAUSE");
return EXIT_SUCCESS;
}
No programa acima é definido um espaço de nomes identificado por A e um
espaço de nomes identificado por B. Os espaços A e B definem duas variáveis
distintas mas com mesmo nome. Na função main() distinguimos as duas variáveis
usando o operador de resolução de escopo. A linguagem C++ permite ainda um
espaço de nomes “unnamed” definido via omissão do nome do espaço! A diretiva
“using namespace <nome>” instrui o compilador a tentar resolver a
identificação de nomes através de escopos. Compare o programa acima com este
programa:
#include <cstdlib>
#include <iostream>
using namespace std;
namespace A{ int i=10;}
namespace B{ int i=20;}
int main(int argc, char *argv[]){
using namespace B;
cout<<A::i<<endl;
cout<<i<<endl;
system("PAUSE");
return EXIT_SUCCESS;
}
O uso da diretiva “using namespace” também obedece questões de escopo,
seu uso no escopo global ou no escopo de definição de um espaço de nomes é
diferente do uso no escopo local. A definição de escopo de nomes pode ser
aninhada, conforme programa abaixo.
#include <cstdlib>
#include <iostream>
using namespace std;
namespace A{
int i=10;
namespace X{ int i=30;} //aninhamento
}
namespace B{ int i=20;}
int main(int argc, char *argv[]){
using namespace B;
cout<<A::i<<endl;
cout<<i<<endl;
cout<<A::X::i<<endl;
system("PAUSE");
return EXIT_SUCCESS;
}
Em função de todos estes aspectos os identificadores em programas C++ são mais estruturados do que em programas C. Boa parte da biblioteca padrão do C++ (p.ex. iostream) é definida com base no espaço de nomes std.
-----
Cadeias de caracteres: arranjos/ponteiros, strings etc.
A linguagem C++ define uma classe padrão “string”, além disso os projetistas não removeram de C++ nenhuma das caracteristicas da linguagem C relacionadas ao tratamento de arranjos de caracteres. A linguagem C++ não definiu novos literais para strings e, portanto, o único literal para string em C++ continua correspondendo a uma cadeia de caracteres terminada com zero/nulo apesar de ter havido uma certa “briga” relacionada a um literal string corresponder ao tipo “const char *” ou ao tipo “char *”. O uso de strings no estilo da linguagem C corresponde a inclusão do cabecalho <cstring>(strlen, strcpy, strcmp, etc).
A linguagem C++ define um tipo (class) string baseada em uma classe definida via “templates”(“template” é visto no material mais à frente da disciplina). Este uso corresponde a inclusão do cabeçalho <string>. A classe string é baseada no uso de caracteres do tipo char e a classe wstring é baseada no uso de caracteres do tipo wchar_t.
As instâncias de string em C++ são objetos “dinâmicos” no seguinte sentido: uma vez instanciado este objeto pode conter uma cadeia que pode ser modificada. Podemos inserir, trocar, remover caracteres da cadeia de caracteres correspondente à instância.
A classe string “sobrecarrega”os seguintes operadores: = + += == != < <= > >= [] << >> e podemos usá-los de forma razoavelmente intuitiva. A sobrecarga permite o uso de == != < <= > >= ao invés de usar uma função que corresponderia à strcmp das cadeias no estilo da linguagem C.
---
Ponteiros, referências, etc
Além dos ponteiros a linguagem C++ define “referências” (será visto mais a frente). A recomendação é não usar alocação dinâmica via malloc() & free(), C++ define os operadores new e delete (e também new[] e delete[]). O operador new é polimórfico e devolve um ponteiro do mesmo tipo do argumento. Veja estes exemplos:
int *pini=new int; //não inicializado
int *pii=new int(10); //int inicializado com valor 10
double *pd=new double(3.14);
delete pini; // torna disponivel a area que estava sendo apontada por pini
int *pai=new int[10];
delete [] pai; // operador delete[] considera o arranjo
endereços mais ao final da memória
|
Sistema; código e dados diversos |
|
Registros de ativação (PILHA) vvvvvvvvvvvvvvvvv |
|
Espaço da PILHA vvvvvvvvvvvvvvvvvvvvvvvvvv |
|
|
|
Código das funções de código ligado dinâmicamente |
|
|
|
Espaço do HEAP ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
|
Dados HEAP [malloc calloc new etc ]^^^^^^^^ |
|
Dados não inicializados |
|
Dados inicializados |
|
Código da função main() e outras funções estáticas |
|
Sistema; código e dados diversos |
Endereços no início da memória
Uma figura melhor definida pode ser conseguida na Internet, p.ex. www.linuxjournal.com
A linguagem C++ permite na hora de *definir* uma função que os parâmetros tenham valores default. Na invocação das funções o programador pode omitir a expressão correspondente ao parâmetro e será então usado o valor default. Observe que a ordem dos parâmetros é importante porque não há como expressar, na invocação, que deseja-se utilizar apenas o valor default de um parâmetro específico, além disso se um parâmetro tem valor default na definição então todos os parâmetros que o seguem devem ter valor default.
Observe a seguinte definição de função:
void f(int p1=10,
int p2=20, int p3=30){
cout<<p1<<"
"<<p2<<endl;
}
podemos invocar esta função sem especificar expressões para os parâmetros:
....f();//equivale a
f(10,20,30)
f(40); // f(40, 20, 30)
f(50,100); //f(50,100, 30)
A linguagem C++ permite um estilo de inicialização idiomaticamente diferente da linguagem C:
Uma definição e inicialização em C como esta
int var=10;
pode ser escrita em C++ desta forma:
int var(10);
Exercícios
reescrever alguns dos programas em C já discutidos em aula para utilizar recursos da linguagem C++ (por exemplo bool).