Introdução C++
A linguagem de programa a ser usada se chama C++. Como indica o nome, essa linguagem é uma extensão à linguagem C, de forma a aderir ao paradigma de orientação a objetos. Como esse assunto será visto em profundidade na 4a fase, na disciplina de POO (Programação Orientada a Objetos), faremos um uso mais superficial dessa linguagem. Quer dizer, usaremos algumas de suas construções, mas não nos deteremos em seus aspectos teóricos. O objetivo de usar C++ é introduzir essa linguagem, que será usada em próximas disciplinas.
Para iniciar o uso da linguagem, vamos começar com um exemplo clássico do tipo hello world:
#include <iostream>
using namespace std;
int main() {
cout << "Hello world !" << endl;
return 0;
}
Para compilar este exemplo, grave-o em um arquivo com extensão .cc.Supondo que o nome do arquivo seja hello.cc, pode-se compilá-lo assim:
g++ -o hello hello.cc
O comando acima deve gerar um arquivo executável chamado hello. Para executá-lo, faça o seguinte:
./hello
O exemplo acima pode ser estendido para mostrar como ler dados do teclado:
#include <iostream>
#include <stdio.h>
using namespace std;
int main() {
int x;
cout << "Hello world !" << endl;
cout << "x: ";
cin >> x;
cout << "Voce digitou " << x << endl;
return 0;
}
Mas o que tem de especial a linguagem C++ ? Muita coisa, se comparada à linguagem C. Veja este exemplo sobre horários em ambas linguagens:
#include <stdio.h>
struct Horario {
unsigned int hora, minuto, segundo;
};
struct Horario criaHorario(unsigned int h, unsigned int m, unsigned int s) {
struct Horario horario;
if (h < 24) horario.hora = h;
else horario.hora = 0;
if (m < 60) horario.minuto = m;
else horario.minuto = 0;
if (s < 60) horario.segundo = s;
else horario.segundo = 0;
return horario;
}
char * mostraHorario(struct Horario horario) {
static char buffer[32];
snprintf(buffer, 32, "%u:%u:%u", horario.hora, horario.minuto, horario.segundo);
return buffer;
}
void acrescenta(struct Horario * horario, struct Horario * outro) {
horario->segundo = horario->segundo + outro->segundo;
if (horario->segundo > 59) {
horario->minuto++;
horario->segundo = horario->segundo - 60;
}
horario->minuto = horario->minuto + outro->minuto;
if (horario->minuto > 59) {
horario->hora++;
horario->minuto = horario->minuto - 60;
}
horario->hora = horario->hora + outro->hora;
if (horario->hora > 23) horario->hora = horario->hora - 24;
}
int main() {
struct Horario h1 = criaHorario(9, 45, 0);
struct Horario h2 = criaHorario(15,20,30);
printf("horario 1: %s\n", mostraHorario(h1));
printf("horario 2: %s\n", mostraHorario(h2));
acrescenta(&h1, &h2);
printf("horario 1 + horario 2: %s\n", mostraHorario(h1));
}
Um exemplo em linguagem C
#include <iostream>
using namespace std;
class Horario {
private:
unsigned int hora, minuto, segundo;
public:
Horario() {
hora = minuto = segundo = 0;
}
Horario(unsigned int h, unsigned int m, unsigned int s) {
if (h < 24) hora = h;
else hora = 0;
if (m < 60) minuto = m;
else minuto = 0;
if (s < 60) segundo = s;
else segundo = 0;
}
~Horario() {}
void mostreSe(ostream & out) {
out << hora << ":" << minuto << ":" << segundo;
}
void acrescenta(Horario outro) {
segundo = segundo + outro.segundo;
if (segundo > 59) {
minuto++;
segundo = segundo - 60;
}
minuto = minuto + outro.minuto;
if (minuto > 59) {
hora++;
minuto = minuto - 60;
}
hora = hora + outro.hora;
if (hora > 23) hora = hora - 24;
}
};
int main() {
Horario h1(9,45,0);
Horario h2(15,20,30);
cout << "horario 1: ";
h1.mostreSe(cout);
cout << endl;
cout << "horario 2: ";
h2.mostreSe(cout);
cout << endl;
cout << "horario 1 + horario 2: ";
h1.acrescenta(h2);
h1.mostreSe(cout);
cout << endl;
}
O mesmo exemplo em linguagem C++
As diferenças não são superficiais, apesar de existirem muitas semelhanças e analogias poderem ser feitas entre os programas. Para entender algumas das novidades de C++, é necessária uma pequena introdução a alguns conceitos essenciais da linguagem.
1 Classes e objetos
A linguagem C foi projetada segundo um paradigma de programação chamado de programação estruturada. Essa forma de expressar programas se baseia em subrotinas (funções no caso da linguagem C), blocos de instruções e laços de repetição, os quais atuam sobre variáveis que contêm os dados a serem acessados e transformados. O que se deve notar é a forma com que se costuma modelar um programa nesse caso, dando-se ênfase aos algoritmos que modificam os dados. Não é à toa que uma ferramenta de modelagem tradicional e ainda muito usada seja o fluxograma. Porém existem outras formas de pensar os problemas a serem resolvidos e expressar programas, dentre elas o paradigma de orientação a objetos seguido por diversas linguagens tais como C++, Java e Python.
Um programa orientado a objetos é composto por objetos que interagem. Um objeto é uma abstração que representa uma coisa que faz parte do problema a ser resolvido. Um objeto contém dados que representam seu estado (chamados de atributos), e procedimentos que representam seu comportamento (chamados de métodos). No caso do exemplo dos horários, um horário pode ser representado por um objeto. O estado desse objeto Horario é definido pelos valores de hora, minuto e segundo, e seu comportamento é dado pelos métodos mostreSe e acrescenta. Isso deve ser entendido da seguinte forma: um objeto 'Horario pode ser mostrado, ao se chamar seu método 'mostreSe, e pode ser somado a outro objeto Horario, ao se chamar seu método acrescenta. Essas são as únicas operações definidas para esse objeto, e assim nada mais se consegue fazer com ele ... a não ser que se definam novas operações.
Muitos objetos similares podem existir. Por exemplo, pode haver muitos diferentes objetos Horario, que se diferenciam por seus estados (valores de hora, minuto e segundo). Todos os objetos cujos estados são definidos pelo mesmo conjunto de atributos, e que possuem o mesmo comportamento (conjunto de métodos), pertencem à mesma classe. O conceito de classe é semelhante ao de tipo de dados, porém tem uma implicação mais profunda. Um tipo de dados define como o conteúdo de uma variável deve ser interpretado (ex: um número inteiro, ponto flutuante, uma string, ...), porém não define os procedimentos que podem manipular essas variáveis. Desta forma, uma classe vincula a seus objetos os algoritmos que atuam sobre eles. Isso tem uma importante implicação no acoplamento e coesão de um programa, que são métricas fundamentais de qualidade de um projeto de software modular.
Mas isso está um tanto abstrato ... o exemplo abaixo pode esclarecer melhor os conceitos de classe e objeto. Ele declara uma classe Vetor, que representa vetores bidimensionais. As operações sobre tais objetos são: módulo, produto escalar, subtração e escrita em um arquivo. Veja como pode ser escrita essa classe.
// a classe Vetor define objetos que representam vetores bidimensionais
class Vetor {
private: // as declarações abaixo são privativas (podem ser acessadas somente dentro da classe)
double x, y;
public: // as declarações abaixo são públicas, podendo ser acessadas de fora da classe
// construtor da classe: um método especial que cria objetos desta classe
Vetor(double px, double py) {
// inicia o estado de um objeto
x = px;
y = py;
}
// destrutor da classe: um método especial que destrói objetos desta classe
~Vetor() {} // nada demais precisa ser feito
// este método retorna o módulo do vetor
double modulo() {
return sqrt(x*x + y*y);
}
// este método retorna o produto escalar deste vetor com outro vetor
double produto_escalar(const Vetor & outro) {
return x*outro.x + y*outro.y;
}
// este método calcula a soma entre este e outro vetor (este + outro),
// retornando um novo vetor como resultado
Vetor adicione(const Vetor & outro) {
Vetor novo(x+outro.x, y+outro.y);
return novo;
}
// este método calcula a diferença entre este e outro vetor (este - outro),
// retornando um novo vetor como resultado
Vetor subtraia(const Vetor & outro) {
Vetor novo(x-outro.x, y-outro.y);
return novo;
}
// este método escreve uma representação do objeto no arquivo "out"
// (que é um objeto da classe ostream)
void mostreSe(ostream & out) {
out << "(";
out << x;
out << ", ";
out << y;
out << ")";
}
};
Uma vez existindo a classe Vetor, pode-se escrever um programa que use objetos dessa classe. No exemplo abaixo, calcula-se o vetor resultante de dois outros vetores:
int main() {
int x, y;
cout << "Coordenada X do vetor 1: ";
cin >> x;
cout << "Coordenada Y do vetor 1: ";
cin >> y;
cout << endl;
// Aqui se cria o primeiro objeto Vetor
Vetor v1(x, y);
cout << "Coordenada X do vetor 2: ";
// Aqui se lê pela entrada padrão a coordenada X
cin >> x;
cout << "Coordenada Y do vetor 2: ";
// Aqui se lê pela entrada padrão a coordenada Y
cin >> y;
cout << endl;
// Aqui se cria o segundo objeto Vetor
Vetor v2(x, y);
// Aqui se obtém a resultante dos vetores v1 e v2. Note como a operação "adicione"
// do objeto "v1" é chamada.
Vetor v3 = v1.adicione(v2);
cout << "Vetor resultante: ";
// Aqui se escreve uma representação de "v3" na tela. "cout" é um objeto da biblioteca C++ padrão
// que representa a saída padrão de um processo. A saída padrão funciona como um arquivo. O objeto
// "cout" é similar ao "stdout" da linguagem C.
v3.mostreSe(cout);
cout << endl;
}
O programa em si se apresenta como um pequeno algoritmo que lê pela entrada padrão valores de coordenadas e cria os respectivos vetores (v1 e v2), calculando sua resultante a apresentando na saída padrão o novo vetor (v3).
Além das regras de escrita da linguagem, o que se denomina sintaxe, ressalta-se o uso dos objetos feito no programa. O pequeno programa criado trata de calcular a resultante de dois vetores bidimensionais. As coisas a serem diretamente manipuladas pelo programa são os vetores, sendo estes representado por objetos. Outros objetos usados são os arquivos que representam a entrada e saída padrão do programa (respectivamente cin e cout). O programa usa os objetos da classe Vetor, explorando as operações que eles oferecem. Assim, a declaração da classe Vetor se preocupa em definir o que é um objeto Vetor (seus atributos) e o que ele é capaz de fazer (seu comportamento). Já o programa apenas utiliza esses objetos.