Escolar Documentos
Profissional Documentos
Cultura Documentos
Desenvolvimento OO em C++
para quem já sabe C e Java
Departamento de Informática
Centro Tecnológico
Universidade Federal do Espírito Santo
Este obra foi licenciada sob uma Licença Creative Commons Atribuição 3.0 Não Adaptada.
Sobre o Curso Rápido de C++
• Pré-requisito:
– Desenvolver bem em C;
– Saber outra linguagem OO (de preferência Java);
– Conceitos OO não serão apresentados, apenas como
aplicar tais conceitos em C++.
• Bibliografia básica:
– Apostila Programação Orientada a Objetos em C++
(Berilhes B. Garcia, Flávio M. Varejão);
– P. Deitel, H. Deitel. C++ Como Programar, 5ª Edição.
Pearson Education, 2010.
C++
Eiffel Miranda
CLOS
1990
main () {
int a = 193;
int b = 456;
int c;
c = a + b + 47;
printf("%d\n",c);
}
main() {
BigInt a = "25123654789456";
BigInt b = "456023398798362";
BigInt c;
c = a + b + 47;
c.print();
printf("\n");
}
Junho 2016 Curso Rápido de C++ 7
E na especificação de BigInt...
• A especificação de BigInt deve dizer como:
1. Criar objetos da classe BigInt (de strings!);
2. Somar BigInt x BigInt e BigInt x int/long;
3. Imprimir um BigInt.
#include "BigInt.h"
main() {
BigInt a = "25123654789456"; 1
BigInt b = "456023398798362";
BigInt c;
c = a + b + 47; 2
c.print();
printf("\n"); 3
}
Compilador
BigInt.cpp C++ BigInt.o
Linker
BigInt.h
Compilador
Client.cpp C++ Client.o
Client.exe
digitos
1 2 3 4 5 6
6
ndigitos
BigInt(const char*)
(construir)
BigInt a = “218”
BigInt c = a + b +47;
char* digitos
BigInt(const BigInt&) c.print();
print() (inicializar)
int ndigitos
operador+(const BigInt&)
(somar)
BigInt(const char*);
BigInt(unsigned n = 0);
BigInt(const BigInt&);
/* ... */
BigInt(unsigned n = 0);
BigInt(unsigned n = 0);
/* ... */
/* ... */
BigInt* p;
p = &a;
p->print();
// No cliente:
BigInt a = "25123654789456";
BigInt b = "456023398798362";
BigInt c;
c = a + b + 47;
Compilador
BigInt.cpp C++ BigInt.o
Linker
BigInt.h
Compilador
Client.cpp C++ Client.o
Client.exe
DEFININDO CLASSES
(IMPLEMENTAÇÃO)
// C++:
BigInt* p;
p = new BigInt; // Sem cast ou sizeof!
int y = 1;
inc(y);
printf("%d\n", y); // 2
• Note que:
– A variável x não precisou ser derreferenciada em
inc();
– A variável y foi passada como argumento
normalmente, e não seu endereço &y.
int main () {
Objeto c(10);
c.print(); // 10
c.setAttr(20);
c.print(); // 20
}
Junho 2016 Curso Rápido de C++ 38
A classe SeqDigitos
• Para implementar a soma de BigInts, precisaremos de
uma classe auxiliar: sequência de dígitos:
class SeqDigitos {
char* dp; // Ponteiro para o digito corrente.
unsigned nd; // Número de dígitos restantes.
public:
SeqDigitos (const BigInt& n) {
dp = n.digitos;
nd = n.ndigitos;
}
unsigned operator++(int) {
if (nd == 0) return 0;
else {
nd--;
return *dp++; Sobrescreve apenas o x++,
} não o ++x!
}
};
Junho 2016 Curso Rápido de C++ 39
Somando dois objetos BigInt
BigInt BigInt::operator+(const BigInt& n) const {
unsigned maxdigitos = (ndigitos > n.ndigitos ?
ndigitos : n.ndigitos) + 1;
char* sumPtr = new char[maxdigitos];
BigInt sum(sumPtr, maxdigitos);
this, como em
SeqDigitos a(*this);
SeqDigitos b(n); Java (BigInt *)
unsigned i = maxdigitos - 1;
unsigned carry = 0;
while (i--) {
*sumPtr = (a++) + (b++) + carry;
if (*sumPtr >=10) {
carry = 1;
*sumPtr −= 10;
}
else carry = 0;
sumPtr++;
} // Continua...
Junho 2016 Curso Rápido de C++ 40
Somando dois objetos BigInt
if (carry) {
*sumPtr = 1;
return sum;
}
else {
i = maxdigitos - 1;
char* p = new char[i];
BigInt s(p, maxdigitos - 1);
char* q = sum.digitos;
while (i--) *p++ = *q++;
return s;
}
}
class BigInt {
// ...
// ...
};
// No cliente:
BigInt c = 243;
BigInt a, b;
a = b = c; // Erro! (b = c) retorna void!
Ponto& f() {
Ponto a;
// ...
return a; // Objeto referido será desalocado!
} Junho 2016 Curso Rápido de C++ 46
O Operador delete
• Como já visto, delete é o contrário de new e libera a
memória alocada para um objeto (como free em C);
• delete aciona o destrutor da classe:
BigInt* a = new BigInt("9834567843");
// [...] Chama a->~BigInt();
delete a;
MELHORIAS EM RELAÇÃO A C
if (s2.empty()) {
s2 = s1 + " mais Um";
char c = s2.at(0);
const char *cStr = s1.c_str();
}
}
} Junho 2016 Curso Rápido de C++ 50
Booleanos
• C++ adiciona o tipo booleano: bool.
int main () { Conversão de int
string resposta;
bool resultado = true;
para bool automática
while (resultado) {
cout << "Deseja sair (S/N)? ";
getline(cin, resposta);
int cmp = resposta.compare("S");
resultado = cmp;
// Altenativamente:
// resultado = (resposta == "N");
}
}
int main () {
cout << "Hello, world!\n";
cout << "Um inteiro: ";
cout << 10;
cout << " e um float: " << 10.5 << '\n';
int valor;
cout << "Digite um valor: ";
cin >> valor;
cout << "O dobro é: " << valor * 2 << '\n';
}
int main () {
cout << "Hello, world!\n";
cout << "Um inteiro: ";
cout << 10;
cout << " e um float: " << 10.5 << endl;
int valor;
cout << "Digite um valor: ";
cin >> valor;
cout << "O dobro é: " << valor * 2 << endl;
}
int main () {
char nome[50];
cout << "Qual é o seu nome?\n";
cin >> nome;
cout << "Olá, " << nome << "!\n";
}
// Problema:
// Vítor -> "Olá, Vítor!"
// Vítor Souza -> "Olá, Vítor!"
int main () {
string nome;
cout << "Qual é o seu nome?\n";
getline(cin, nome);
cout << "Olá, " << nome << "!\n";
}
// OK!
// Vítor -> "Olá, Vítor!"
// Vítor Souza -> "Olá, Vítor Souza!"
int main () {
std::string nome;
std::cout << "Qual é o seu nome?\n";
std::getline(std::cin, nome);
std::cout << "Olá, " << nome << "!\n";
}
CONCEITOS OO
public:
Pessoa (string n, int a) {nome = n; idade = a;}
string& getNome() const { return nome; };
void mudarIdade(int a) { idade = a; }
virtual void print( );
};
public:
Empregado(string n, int a, float s) :
Pessoa (n, a) { salario = s; }
// Herança privativa:
class EmpregadoB: Pessoa { /* ... */ };
int main () {
Pessoa* p = new Pessoa("Fulano", 32);
EmpregadoA* a = new EmpregadoA("Ana", 32, 2000.00);
EmpregadoB* b = new EmpregadoB("Bruno", 32, 2000.00);
imprimir(p); // OK!
imprimir(a); // OK!
imprimir(b); // ‘Pessoa’ is an inaccessible base
}
public:
void insereInicio(Info valor);
Info removeInicio();
int estaVazia();
};
class Pai {
public:
void um() { cout << "1" << endl; };
void dois() { cout << "2" << endl; };
void tres() { cout << "3" << endl; };
};
public:
/* ... */
};
Junho 2016 Curso Rápido de C++ 71
Herança múltipla
• C++, ao contrário de Java, permite a herança múltipla:
class Surf {
time_t data;
float notas[10];
public:
void registrarNota(float nota);
};
class Vela {
Subclasse herda
time_t data; ambos os métodos
float tempos[10];
public:
void registrarTempo(float tempo);
};
• Ou:
void WindSurf::ordena() {
// N = competição por nota; T = por tempo.
if (competicao == 'N' )
Surf::ordena();
else
Vela::ordena();
}
int main() {
WindSurf ws;
cout << ws.getPremio(); // request is ambiguous
}
Junho 2016 Curso Rápido de C++ 75
Ambiguidades da herança múltipla
• Resolve-se usando a palavra-chave virtual:
class Competicao {
float premio;
public:
virtual float getPremio() { return premio; };
};
int main() {
WindSurf ws;
cout << ws.getPremio(); // OK!
} Obs.: herança virtual NÃO
resolve colisão de nomes!
Junho 2016 Curso Rápido de C++ 76
[ Curso Rápido de C++ ]
CONCEITOS AVANÇADOS
class GeradorId {
// Declara a variável na interface:
static int proxId;
public:
static int getId() { return proxId++; }
};
int main () {
for (int i = 0; i < 10; i++)
std::cout << GeradorId::getId() << endl;
} Junho 2016 Curso Rápido de C++ 79
Inicialização
• Atenção, pois funciona de forma diferente de Java:
class Classe {
// ISO C++ forbids initialization of member ‘atributo’
int atributo = 100;
};
private:
class No {
No* prox;
Info info;
};
No* prim;
// Continua...
Junho 2016 Curso Rápido de C++ 81
Classes internas
public:
Lista() { prim = nullptr; }
void insereInicio(Info valor);
void insereFim(Info valor);
Info removeInicio();
int estaVazia();
};
#ifndef CASULO_H_
#define CASULO_H_
void test() {
Casulo<string> cs("Hello, world!");
Casulo<int> ci(10);
Casulo<double> cd(3.14);
Casulo<Casulo<int>*> cp(&ci);
cs.imprimir(); ci.imprimir();
cd.imprimir(); cp.imprimir();
}
int main () {
VitorSouzaLibrary::hello();
vsl::hello();
}
#endif
Junho 2016 Curso Rápido de C++ 88
Modularização com namespaces
#include <string> Não podemos aqui incluir
using namespace std;
#ifndef FUNCIONARIO_H_
“Departamento.h” pois gera
#define FUNCIONARIO_H_ inclusão circular. Portanto,
namespace exercicio02 { fazemos uma declaração
class Departamento; antecipada (forward
declaration).
class Funcionario {
string nome;
double salario;
string dataAdmissao;
Departamento* departamento;
friend class Departamento;
public:
/* ... */
};
}
#endif
Junho 2016 Curso Rápido de C++ 89
Modularização com namespaces
#include <iostream>
#include "Departamento.h”
namespace exercicio02 {
Departamento::Departamento(const char* nome) {
/* ... */
}
/* ... */
}
int main () {
ofstream out("arq.txt");
for (int i = 0; i < MAX; i++) out << i << endl;
out.close();
ifstream in("arq.txt");
string linha;
while (getline(in, linha)) cout << linha << endl;
in.close();
}
Junho 2016 Curso Rápido de C++ 91
[ Curso Rápido de C++ ]
TRATAMENTO DE EXCEÇÕES
class Excecao {
string motivo;
public:
Excecao(const string& motivo) { this->motivo=motivo; }
void lancarA() {
throw ExcecaoA("lancarA() foi chamado");
}
void lancarB() {
throw ExcecaoB("lancarB() foi chamado");
}
• Note que:
– Qualquer objeto pode ser lançado (inclusive de
classes que já existam);
– São lançadas instâncias diretas. O programa
automaticamente desaloca a memória delas.
Junho 2016 Curso Rápido de C++ 95
A biblioteca <exception>
• A biblioteca <exception> define tipos (incluindo a
classe base exception) e utilitários para exceções.
#include <iostream>
#include <typeinfo>
#include <exception>
using namespace std;
UTILITÁRIOS
int main() {
vector<int> vec;
int i;
vector<int>::iterator v = vec.begin();
while (v != vec.end()) {
cout << "v = " << *v << endl;
v++;
}
} Junho 2016 Curso Rápido de C++ 105
Outras bibliotecas interessantes
• <chronos>: manipulação de valores temporais (a
partir de C++11, gcc >= 4.5);
• <complex>: para lidar com números complexos;
• <locale>: localização (internacionalização);
• <numeric>: operações em sequências de valores
numéricos;
• <random>: geração de números pseudoaleatórios;
• <regex>: expressões regulares;
• Dentre outras...
Novamente,
http://www.cplusplus.com/reference/
é seu amigo...
Junho 2016 Curso Rápido de C++ 106
[ Curso Rápido de C++ ]
string& trim(string& s) {
return ltrim(rtrim(s));
}
Junho 2016 Curso Rápido de C++ 111
Collator
• Como faço comparação de strings com Collator (para
considerar letras com acentos)?
// Já implementado no StringUtils:
bool stringCompare(string s1, string s2) {
const collate<char>& col =
use_facet<collate<char> >(locale());
transform(s1.begin(), s1.end(), s1.begin(),
::tolower);
transform(s2.begin(), s2.end(), s2.begin(),
::tolower);
const char* pb1 = s1.data();
const char* pb2 = s2.data();
return (col.compare(pb1, pb1 + s1.size(), pb2, pb2 +
s2.size()) < 0);
}
class PessoaComparator {
public:
bool operator()(const Pessoa*, const Pessoa*) const;
};
int main() {
// Parses a date (string -> time_t) using
// the pt-BR locale.
string data = "15/07/2014";
cout << validDate(data, DATE_FORMAT_PT_BR_SHORT) <<
endl;
time_t hoje = parseDate(data, DATE_FORMAT_PT_BR_SHORT);
cout << hoje << endl << endl;