Aula 13
Tipos Abstractos de Dados IV
Estrutura global do programa (I)
#include <iostream>
#include <cassert>
using namespace std;
/** Devolve o máximo divisor comum dos inteiros passados como argumento.
@pre m ≠ 0 ou n ≠ 0.
@post mdc = mdc(m, n). */
int mdc(int const m, int const n) {…}
class Racional {…};
Racional::Racional(int const n) {…}
Construtores
Racional::Racional(int const n, int const d) {…}
int Racional::numerador() {…}
Inspectores
int Racional::denominador() {…}
void Racional::escreve() {…}
(continua)
2
Introdução à Programação
2003/2004
Estrutura global do programa (II)
(continuação)
void Racional::lê() {…}
Racional& Racional::operator++() {…}
Racional& Racional::operator--() {…}
Modificadores
Racional& Racional::operator*=(Racional const& r2) {…}
Racional& Racional::operator/=(Racional const& r2) {…}
Racional& Racional::operator+=(Racional const& r2) {…}
Racional& Racional::operator-=(Racional const& r2) {…}
void Racional::reduz() {…}
Auxiliares
bool Racional::cumpreInvariante() {…}
(continua)
3
Introdução à Programação
2003/2004
Estrutura global do programa (III)
(continuação)
/** Produto de dois racionais.
@pre V.
@post operator* = r1 × r2. */
Racional const operator*(Racional r1, Racional const& r2) {…}
Operadores
aritméticos
não-membro
/** Divisão de dois racionais.
@pre r2 ≠ 0.
@post operator/ = r1 / r2. */
Racional const operator/(Racional r1, Racional const& r2) {…}
/** Soma de dois racionais.
@pre V.
@post operator+ = r1 + r2. */
Racional const operator+(Racional r1, Racional const& r2) {…}
/** Subtracção de dois racionais.
@pre V.
@post operator- = r1 - r2. */
Racional const operator-(Racional r1, Racional const& r2) {…}
(continua)
4
Introdução à Programação
2003/2004
Estrutura global do programa (IV)
(continuação)
Operadores de
igualdade e
diferença
não-membro
/** Indica se dois racionais são iguais.
@pre V.
@post operator== = (r1 = r2). */
bool operator==(Racional const& r1, Racional const& r2) {…}
/** Indica se dois racionais são diferentes.
@pre V.
@post operator!= = (r1 ≠ r2). */
bool operator!=(Racional const& r1, Racional const& r2) {…}
int main() {…}
5
Introdução à Programação
2003/2004
TAD Racional (construtores)
/** Representa números racionais.
@invariant 0 < denominador_  mdc(numerador_, denominador_) = 1. */
class Racional {
public:
/** Constrói racional com valor inteiro.
@pre V.
@post *this = valor. */
Racional(int const valor = 0);
/** Constrói racional correspondente a numerador/denominador.
@pre denominador ≠ 0.
@post *this = numerador/denominador. */
Racional(int const numerador, int const denominador);
(continua)
6
Introdução à Programação
2003/2004
TAD Racional (inspectores)
(continuação)
/** Devolve numerador da fracção mínima correspondente ao racional.
@pre V.
@post numerador/denominador() = *this. */
int numerador();
/** Devolve denominador da fracção mínima correspondente ao racional.
@pre V.
@post 0 < denominador  (E n : V : n/denominador = *this 
mdc(n, denominador) = 1). */
int denominador();
/** Escreve um racional no ecrã no formato de uma fracção.
@pre V.
@post cout.fail() ou cout contém n/d (ou simplesmente n, se d = 1) em
que n e d são os valores de numerador e denominador. */
void escreve();
(continua)
7
Introdução à Programação
2003/2004
TAD Racional (modificadores)
(continuação)
/** Lê do teclado um racional, na forma de dois inteiros sucessivos.
@pre *this = r.
@post Se cin.good()  cin tem dois inteiros n e d disponíveis para
leitura, com d <> 0, então *this = n/d  cin.fail(),
senão *this = r  cin.fail(). */
void lê();
/** Incrementa o racional.
@pre *this = r.
@post operator++ ≡ *this  *this = r + 1. */
Racional& operator++();
/** Decrementa o racional.
@pre *this = r.
@post operator-- ≡ *this  *this = r - 1. */
Racional& operator--();
(continua)
8
Introdução à Programação
2003/2004
TAD Racional (modificadores)
(continuação)
/** Multiplica por um racional.
@pre *this = r.
@post operator*= ≡ *this  *this = r × r2. */
Racional& operator*=(Racional const& r2);
/** Divide por um racional.
@pre *this = r  r2 ≠ 0.
@post operator/= ≡ *this  *this = r / r2. */
Racional& operator/=(Racional const& r2);
/** Adiciona de um racional.
@pre *this = r.
@post operator+= ≡ *this  *this = r + r2. */
Racional& operator+=(Racional const& r2);
/** Subtrai de um racional.
@pre *this = r.
@post operator-= ≡ *this  *this = r - r2. */
Racional& operator-=(Racional const& r2);
(continua)
9
Introdução à Programação
2003/2004
TAD Racional (implementação)
(continuação)
private:
/** Indica se a CIC se verifica.
@pre V.
@post cumpreInvariante =
0 < denominador_  mdc(numerador_, denominador_) = 1. */
bool cumpreInvariante();
/** Reduz a fracção que representa o racional.
@pre denominador_ ≠ 0  *this = r.
@post denominador_ ≠ 0 
mdc(numerador_, denominador_) = 1  *this = r. */
void reduz();
int numerador_;
int denominador_;
};
10
Introdução à Programação
2003/2004
Constantes de TAD
Porque não
Possível definir constantes de TAD:
Racional
 const um_terço(1 / 3);
?
Racional const um_terço(1, 3);

Mas é necessário ter alguns cuidados:
cout << um_terço.numerador() << endl;
Dá erro!
11
Introdução à Programação
2003/2004
Constantes de TAD

Compilador admite, por omissão, que as
operações alteram a instância implícita

Se a instância implícita for constante, não se
podem invocar operações??

Podem, mas apenas as operações que
declararem explicitamente que não alteram a
instância implícita, pois a tratam como
constante
12
Introdução à Programação
2003/2004
Operações que garantem
constância: Sintaxe
class Classe {
…
tipo operação(parâmetros) const;
…
};
tipo Classe::operação(parâmetros) const
{
…
}
13
Introdução à Programação
2003/2004
Operações que garantem
constância: Semântica

Podem ser invocadas usando constantes:
Classe const constante;
constante.operação(argumentos);
Proibido para
operações não
constantes.
14
Introdução à Programação
2003/2004
Operações que garantem
constância: Semântica

Compilador impede método de fazer
alterações aos atributos:
tipo Classe::operação(parâmetros) const
{
…
atributo = …;
…
}
15
Proibido!
Introdução à Programação
2003/2004
Operações que garantem
constância: Semântica

Métodos não-constantes


Métodos constantes

16
*this é Classe&
*this é Classe const&
Introdução à Programação
2003/2004
TAD Racional (construtores)
/** Representa números racionais.
@invariant 0 < denominador_  mdc(numerador_, denominador_) = 1. */
class Racional {
public:
/** Constrói racional com valor inteiro.
Construtores não podem ser
@pre V.
const, pois instância implícita é
@post *this = valor. */
por eles inicializada!
Racional(int const valor = 0);
/** Constrói racional correspondente a numerador/denominador.
@pre denominador ≠ 0.
@post *this = numerador/denominador. */
Racional(int const numerador, int const denominador);
(continua)
17
Introdução à Programação
2003/2004
TAD Racional (inspectores)
(continuação)
/** Devolve numerador da fracção mínima correspondente ao racional.
@pre V.
@post numerador/denominador() = *this. */
int numerador() const;
/** DevolveInspectores
denominador da
fracção
mínima
correspondente ao racional.
são
sempre
const!
@pre V.
@post 0 < denominadorAos
 (Einspectores
n : V : n/denominador
= *this 
também
mdc(n, denominador) = 1). */
se chama interrogações
int denominador() const;
(queries)
/** Escreve um racional no ecrã no formato de uma fracção.
@pre V.
@post cout.fail() ou cout contém n/d (ou simplesmente n, se d = 1) em
que n e d são os valores de numerador e denominador. */
void escreve() const;
(continua)
18
Introdução à Programação
2003/2004
TAD Racional (modificadores)
(continuação)
/** Lê do teclado um racional, na forma de dois inteiros sucessivos.
@pre *this = r.
@post Se cin.good()  cin tem dois inteiros n e d disponíveis para
leitura, com d <> 0, então *this = n/d  cin.fail(),
senão *this = r  cin.fail(). */
void lê();
/** Incrementa o racional.
@pre *this = r.
@post operator++ ≡ *this  *this = r + 1. */
Racional& operator++();
/** Decrementa o racional.
@pre *this = r.
@post operator-- ≡ *this  *this = r - 1. */
Racional& operator--();
(continua)
19
Introdução à Programação
2003/2004
TAD Racional (modificadores)
(continuação)
/** Multiplica por um racional.
@pre *this = r.
@post operator*= ≡ *this  *this = r × r2. */
Racional& operator*=(Racional const& r2);
/** Divide por um racional.
@pre *this = r  r2 ≠ 0.
Modificadores nunca são const!
@post operator/= ≡ *this  *this = r / r2. */
Racional& operator/=(Racional const& r2);
/** Adiciona de um racional.
@pre *this = r.
@post operator+= ≡ *this  *this = r + r2. */
Racional& operator+=(Racional const& r2);
/** Subtrai de um racional.
@pre *this = r.
@post operator-= ≡ *this  *this = r - r2. */
Racional& operator-=(Racional const& r2);
(continua)
20
Introdução à Programação
2003/2004
TAD Racional (implementação)
(continuação)
private:
/** Indica se a CIC se verifica.
@pre V.
@post cumpreInvariante =
0 < denominador_  mdc(numerador_, denominador_) = 1. */
bool cumpreInvariante() const;
/** Reduz a fracção que representa o racional.
@pre denominador_ ≠ 0  *this = r.
@post denominador_ ≠ 0 
mdc(numerador_, denominador_) = 1  *this = r. */
void reduz();
int numerador_;
int denominador_;
};
21
Introdução à Programação
2003/2004
Métodos afectados
…
int Racional::numerador() const {…}
int Racional::denominador() const {…}
void Racional::escreve() const {…}
…
bool Racional::cumpreInvariante() const {…}
…
22
Introdução à Programação
2003/2004
Métodos afectados
void Racional::escreve() const
{
assert(cumpreInvariante());
cout << numerador();
if(denominador() != 1)
cout << '/' << denominador();
assert(cumpreInvariante());
}
23
Desnecessário! Num método
constante, se o invariante se
verifica no início (para a
instância implícita), também
se verifica no fim.
Introdução à Programação
(Hmmm… Há excepções. )
2003/2004
Métodos afectados
void Racional::escreve() const
{
assert(cumpreInvariante());
cout << numerador();
if(denominador() != 1)
cout << '/' << denominador();
}
24
Introdução à Programação
2003/2004
Atenção!

Utilização sistemática de const tem grandes
vantagens:



25
Obriga programador a pensar
(menos erros)
Programador explicita informação acerca do
programa, que o compilador usa para detectar
incoerências
(erros detectados mais facilmente)
Erros ocorrem mais cedo, durante compilação
(erros detectados mais cedo)
Introdução à Programação
2003/2004
Dica:
Quando se constrói um racional à custa de outro, é invocado um
Desafio
construtor por cópia, fornecido automaticamente pelo
compilador, e que se limita a copiar os atributos um a um.

Quantas invocações de rotinas estão
envolvidas em
Racional r(1, 3);
Racional s = r + 2;
ignorando asserções?
26
Introdução à Programação
2003/2004
Construtor
Racional::Racional()
Racional::Racional(int const n)
: numerador(n), denominador(1)
{
assert(cumpreInvariante());
assert(numerador() == n * denominador());
}
27
Introdução à Programação
2003/2004
Construtor
Racional::Racional()
Racional::Racional(int const n, int const d)
{
assert(d != 0);
if(d < 0) {
numerador_ =
denominador_
} else {
numerador_ =
denominador_
}
-n;
= -d;
n;
= d;
reduz();
assert(cumpreInvariante());
assert(numerador() * d == n * denominador());
}
28
Introdução à Programação
2003/2004
Inspector
Racional::numerador()
int Racional::numerador() const
{
assert(cumpreInvariante());
return numerador_;
}
29
Introdução à Programação
2003/2004
Inspector
Racional::denominador()
int Racional::denominador() const
{
assert(cumpreInvariante());
return denominador_;
}
30
Introdução à Programação
2003/2004
Operador
Racional::operator+=()
Racional& Racional::operator+=(Racional const& r2)
{
assert(cumpreInvariante());
assert(r2.cumpreInvariante());
numerador_ = numerador() * r2.denominador() +
r2.numerador() * denominador();
denominador_ *= r2.denominador();
reduz();
assert(cumpreInvariante());
return *this;
}
31
Introdução à Programação
2003/2004
Método auxiliar
Racional::reduz()
void Racional::reduz()
{
assert(denominador_ != 0);
int const divisor = mdc(numerador_, denominador_);
numerador_ /= divisor;
denominador_ /= divisor;
assert(denominador_ != 0);
assert(mdc(numerador_, denominador_) == 1);
}
32
Introdução à Programação
2003/2004
Operador
Racional::operator+()
Racional const operator+(Racional r1, Racional const& r2)
{
r1 += r2;
return r1;
}
33
Introdução à Programação
2003/2004
Operador
Racional::operator==()
bool operator==(Racional const& r1, Racional const& r2)
{
return r1.numerador() == r2.numerador() and
r1.denominador() == r2.denominador();
}
34
Introdução à Programação
2003/2004
Número de invocações:
Traçado
0
Racional r(1, 3);
Racional s = r + 2;
35
Introdução à Programação
2003/2004
Número de invocações:
Traçado
1
Racional::Racional(int const n, int const d)
{
assert(d != 0);
if(d < 0) {
numerador_ =
denominador_
} else {
numerador_ =
denominador_
}
-n;
= -d;
n;
= d;
reduz();
assert(cumpreInvariante());
assert(numerador() * d == n * denominador());
}
36
Introdução à Programação
2003/2004
Número de invocações:
Traçado
1
Racional::Racional(int const n, int const d)
{
assert(d != 0);
if(d < 0) {
numerador_ =
denominador_
} else {
numerador_ =
denominador_
}
-n;
= -d;
n;
= d;
reduz();
assert(cumpreInvariante());
assert(numerador() * d == n * denominador());
}
37
Introdução à Programação
2003/2004
Número de invocações:
Traçado
1
Racional::Racional(int const n, int const d)
{
assert(d != 0);
if(d < 0) {
numerador_ =
denominador_
} else {
numerador_ =
denominador_
}
-n;
= -d;
n;
= d;
reduz();
assert(cumpreInvariante());
assert(numerador() * d == n * denominador());
}
38
Introdução à Programação
2003/2004
Número de invocações:
Traçado
1
Racional::Racional(int const n, int const d)
{
assert(d != 0);
if(d < 0) {
numerador_ =
denominador_
} else {
numerador_ =
denominador_
}
-n;
= -d;
n;
= d;
reduz();
assert(cumpreInvariante());
assert(numerador() * d == n * denominador());
}
39
Introdução à Programação
2003/2004
Número de invocações:
Traçado
1
Racional::Racional(int const n, int const d)
{
assert(d != 0);
if(d < 0) {
numerador_ =
denominador_
} else {
numerador_ =
denominador_
}
-n;
= -d;
n;
= d;
reduz();
assert(cumpreInvariante());
assert(numerador() * d == n * denominador());
}
40
Introdução à Programação
2003/2004
Número de invocações:
Traçado
1
Racional::Racional(int const n, int const d)
{
assert(d != 0);
if(d < 0) {
numerador_ =
denominador_
} else {
numerador_ =
denominador_
}
-n;
= -d;
n;
= d;
reduz();
assert(cumpreInvariante());
assert(numerador() * d == n * denominador());
}
41
Introdução à Programação
2003/2004
Número de invocações:
Traçado
2
void Racional::reduz()
{
assert(denominador_ != 0);
int const divisor = mdc(numerador_, denominador_);
numerador_ /= divisor;
denominador_ /= divisor;
assert(denominador_ != 0);
assert(mdc(numerador_, denominador_) == 1);
}
42
Introdução à Programação
2003/2004
Número de invocações:
Traçado
2
void Racional::reduz()
{
assert(denominador_ != 0);
int const divisor = mdc(numerador_, denominador_);
numerador_ /= divisor;
denominador_ /= divisor;
assert(denominador_ != 0);
assert(mdc(numerador_, denominador_) == 1);
}
43
Introdução à Programação
2003/2004
Número de invocações:
Traçado
3
int mdc(int const m, int const n)
{
…
}
44
Introdução à Programação
2003/2004
Número de invocações:
Traçado
3
int mdc(int const m, int const n)
{
…
}
45
Introdução à Programação
2003/2004
Número de invocações:
Traçado
3
void Racional::reduz()
{
assert(denominador_ != 0);
int const divisor = mdc(numerador_, denominador_);
numerador_ /= divisor;
denominador_ /= divisor;
assert(denominador_ != 0);
assert(mdc(numerador_, denominador_) == 1);
}
46
Introdução à Programação
2003/2004
Número de invocações:
Traçado
3
void Racional::reduz()
{
assert(denominador_ != 0);
int const divisor = mdc(numerador_, denominador_);
numerador_ /= divisor;
denominador_ /= divisor;
assert(denominador_ != 0);
assert(mdc(numerador_, denominador_) == 1);
}
47
Introdução à Programação
2003/2004
Número de invocações:
Traçado
3
void Racional::reduz()
{
assert(denominador_ != 0);
int const divisor = mdc(numerador_, denominador_);
numerador_ /= divisor;
denominador_ /= divisor;
assert(denominador_ != 0);
assert(mdc(numerador_, denominador_) == 1);
}
48
Introdução à Programação
2003/2004
Número de invocações:
Traçado
3
void Racional::reduz()
{
assert(denominador_ != 0);
int const divisor = mdc(numerador_, denominador_);
numerador_ /= divisor;
denominador_ /= divisor;
assert(denominador_ != 0);
assert(mdc(numerador_, denominador_) == 1);
}
49
Introdução à Programação
2003/2004
Número de invocações:
Traçado
3
Racional::Racional(int const n, int const d)
{
assert(d != 0);
if(d < 0) {
numerador_ =
denominador_
} else {
numerador_ =
denominador_
}
-n;
= -d;
n;
= d;
reduz();
assert(cumpreInvariante());
assert(numerador() * d == n * denominador());
}
50
Introdução à Programação
2003/2004
Número de invocações:
Traçado
3
Racional r(1, 3);
Racional s = r + 2;
51
Introdução à Programação
2003/2004
Número de invocações:
Traçado
4
Racional::Racional(int const n)
: numerador(n), denominador(1)
{
assert(cumpreInvariante());
assert(numerador() == n * denominador());
}
52
Introdução à Programação
2003/2004
Número de invocações:
Traçado
4
Racional::Racional(int const n)
: numerador(n), denominador(1)
{
assert(cumpreInvariante());
assert(numerador() == n * denominador());
}
53
Introdução à Programação
2003/2004
Número de invocações:
Traçado
4
Racional r(1, 3);
Racional s = r + 2;
54
Introdução à Programação
2003/2004
Número de invocações:
Traçado
5
Racional const operator+(Racional r1, Racional const& r2)
{
r1 += r2;
return r1;
}
55
Passagem por valor
implica cópia!
Introdução à Programação
2003/2004
Número de invocações:
Traçado
6
Racional::Racional(Racional const& original)
: numerador_(original.numerador_),
denominador_(original.denominador_)
{
}
Construtor por cópia fornecido
automaticamente pelo
compilador.
56
Introdução à Programação
2003/2004
Número de invocações:
Traçado
6
Racional::Racional(Racional const& original)
: numerador_(original.numerador_),
denominador_(original.denominador_)
{
}
57
Introdução à Programação
2003/2004
Número de invocações:
Traçado
6
Racional const operator+(Racional r1, Racional const& r2)
{
r1 += r2;
return r1;
}
58
Introdução à Programação
2003/2004
Número de invocações:
Traçado
7
Racional& Racional::operator+=(Racional const& r2)
{
assert(cumpreInvariante());
assert(r2.cumpreInvariante());
numerador_ = numerador() * r2.denominador() +
r2.numerador() * denominador();
denominador_ *= r2.denominador();
reduz();
assert(cumpreInvariante());
return *this;
}
59
Introdução à Programação
2003/2004
Número de invocações:
Traçado
7
Racional& Racional::operator+=(Racional const& r2)
{
assert(cumpreInvariante());
assert(r2.cumpreInvariante());
numerador_ = numerador() * r2.denominador() +
r2.numerador() * denominador();
denominador_ *= r2.denominador();
reduz();
assert(cumpreInvariante());
return *this;
}
60
Introdução à Programação
2003/2004
Número de invocações:
Traçado
8
int Racional::numerador() const
{
assert(cumpreInvariante());
return numerador_;
}
61
Introdução à Programação
2003/2004
Número de invocações:
Traçado
8
int Racional::numerador() const
{
assert(cumpreInvariante());
return numerador_;
}
62
Introdução à Programação
2003/2004
Número de invocações:
Traçado
8
Racional& Racional::operator+=(Racional const& r2)
{
assert(cumpreInvariante());
assert(r2.cumpreInvariante());
numerador_ = numerador() * r2.denominador() +
r2.numerador() * denominador();
denominador_ *= r2.denominador();
reduz();
assert(cumpreInvariante());
return *this;
}
63
Introdução à Programação
2003/2004
Número de invocações:
Traçado
9
int Racional::denominador() const
{
assert(cumpreInvariante());
return denominador_;
}
64
Introdução à Programação
2003/2004
Número de invocações:
Traçado
9
int Racional::denominador() const
{
assert(cumpreInvariante());
return denominador_;
}
65
Introdução à Programação
2003/2004
Número de invocações:
Traçado
9
Racional& Racional::operator+=(Racional const& r2)
{
assert(cumpreInvariante());
assert(r2.cumpreInvariante());
numerador_ = numerador() * r2.denominador() +
r2.numerador() * denominador();
denominador_ *= r2.denominador();
reduz();
assert(cumpreInvariante());
return *this;
}
66
Introdução à Programação
2003/2004
Número de invocações:
Traçado
10
int Racional::numerador() const
{
assert(cumpreInvariante());
return numerador_;
}
67
Introdução à Programação
2003/2004
Número de invocações:
Traçado
10
int Racional::numerador() const
{
assert(cumpreInvariante());
return numerador_;
}
68
Introdução à Programação
2003/2004
Número de invocações:
Traçado
10
Racional& Racional::operator+=(Racional const& r2)
{
assert(cumpreInvariante());
assert(r2.cumpreInvariante());
numerador_ = numerador() * r2.denominador() +
r2.numerador() * denominador();
denominador_ *= r2.denominador();
reduz();
assert(cumpreInvariante());
return *this;
}
69
Introdução à Programação
2003/2004
Número de invocações:
Traçado
11
int Racional::denominador() const
{
assert(cumpreInvariante());
return denominador_;
}
70
Introdução à Programação
2003/2004
Número de invocações:
Traçado
11
int Racional::denominador() const
{
assert(cumpreInvariante());
return denominador_;
}
71
Introdução à Programação
2003/2004
Número de invocações:
Traçado
11
Racional& Racional::operator+=(Racional const& r2)
{
assert(cumpreInvariante());
assert(r2.cumpreInvariante());
numerador_ = numerador() * r2.denominador() +
r2.numerador() * denominador();
denominador_ *= r2.denominador();
reduz();
assert(cumpreInvariante());
return *this;
}
72
Introdução à Programação
2003/2004
Número de invocações:
Traçado
11
Racional& Racional::operator+=(Racional const& r2)
{
assert(cumpreInvariante());
assert(r2.cumpreInvariante());
numerador_ = numerador() * r2.denominador() +
r2.numerador() * denominador();
denominador_ *= r2.denominador();
reduz();
assert(cumpreInvariante());
return *this;
}
73
Introdução à Programação
2003/2004
Número de invocações:
Traçado
12
int Racional::denominador() const
{
assert(cumpreInvariante());
return denominador_;
}
74
Introdução à Programação
2003/2004
Número de invocações:
Traçado
12
int Racional::denominador() const
{
assert(cumpreInvariante());
return denominador_;
}
75
Introdução à Programação
2003/2004
Número de invocações:
Traçado
12
Racional& Racional::operator+=(Racional const& r2)
{
assert(cumpreInvariante());
assert(r2.cumpreInvariante());
numerador_ = numerador() * r2.denominador() +
r2.numerador() * denominador();
denominador_ *= r2.denominador();
reduz();
assert(cumpreInvariante());
return *this;
}
76
Introdução à Programação
2003/2004
Número de invocações:
Traçado
12
Racional& Racional::operator+=(Racional const& r2)
{
assert(cumpreInvariante());
assert(r2.cumpreInvariante());
numerador_ = numerador() * r2.denominador() +
r2.numerador() * denominador();
denominador_ *= r2.denominador();
reduz();
assert(cumpreInvariante());
return *this;
}
77
Introdução à Programação
2003/2004
Número de invocações:
Traçado
13
void Racional::reduz()
{
assert(denominador_ != 0);
int const divisor = mdc(numerador_, denominador_);
numerador_ /= divisor;
denominador_ /= divisor;
assert(denominador_ != 0);
assert(mdc(numerador_, denominador_) == 1);
}
78
Introdução à Programação
2003/2004
Número de invocações:
Traçado
13
void Racional::reduz()
{
assert(denominador_ != 0);
int const divisor = mdc(numerador_, denominador_);
numerador_ /= divisor;
denominador_ /= divisor;
assert(denominador_ != 0);
assert(mdc(numerador_, denominador_) == 1);
}
79
Introdução à Programação
2003/2004
Número de invocações:
Traçado
14
int mdc(int const m, int const n)
{
…
}
80
Introdução à Programação
2003/2004
Número de invocações:
Traçado
14
int mdc(int const m, int const n)
{
…
}
81
Introdução à Programação
2003/2004
Número de invocações:
Traçado
14
void Racional::reduz()
{
assert(denominador_ != 0);
int const divisor = mdc(numerador_, denominador_);
numerador_ /= divisor;
denominador_ /= divisor;
assert(denominador_ != 0);
assert(mdc(numerador_, denominador_) == 1);
}
82
Introdução à Programação
2003/2004
Número de invocações:
Traçado
14
void Racional::reduz()
{
assert(denominador_ != 0);
int const divisor = mdc(numerador_, denominador_);
numerador_ /= divisor;
denominador_ /= divisor;
assert(denominador_ != 0);
assert(mdc(numerador_, denominador_) == 1);
}
83
Introdução à Programação
2003/2004
Número de invocações:
Traçado
14
void Racional::reduz()
{
assert(denominador_ != 0);
int const divisor = mdc(numerador_, denominador_);
numerador_ /= divisor;
denominador_ /= divisor;
assert(denominador_ != 0);
assert(mdc(numerador_, denominador_) == 1);
}
84
Introdução à Programação
2003/2004
Número de invocações:
Traçado
14
void Racional::reduz()
{
assert(denominador_ != 0);
int const divisor = mdc(numerador_, denominador_);
numerador_ /= divisor;
denominador_ /= divisor;
assert(denominador_ != 0);
assert(mdc(numerador_, denominador_) == 1);
}
85
Introdução à Programação
2003/2004
Número de invocações:
Traçado
14
Racional& Racional::operator+=(Racional const& r2)
{
assert(cumpreInvariante());
assert(r2.cumpreInvariante());
numerador_ = numerador() * r2.denominador() +
r2.numerador() * denominador();
denominador_ *= r2.denominador();
reduz();
assert(cumpreInvariante());
return *this;
}
86
Introdução à Programação
2003/2004
Número de invocações:
Traçado
14
Racional const operator+(Racional r1, Racional const& r2)
{
r1 += r2;
return r1;
Devolução por valor
implica cópia!
}
87
Introdução à Programação
2003/2004
Número de invocações:
Traçado
15
Racional::Racional(Racional const& original)
: numerador_(original.numerador_),
denominador_(original.denominador_)
{
}
88
Introdução à Programação
2003/2004
Número de invocações:
Traçado
15
Racional::Racional(Racional const& original)
: numerador_(original.numerador_),
denominador_(original.denominador_)
{
}
89
Introdução à Programação
2003/2004
Número de invocações:
Traçado
15
Racional r(1, 3);
Racional s = r + 2;
90
Introdução à Programação
2003/2004
Número de invocações:
Traçado
16
Racional::Racional(Racional const& original)
: numerador_(original.numerador_),
denominador_(original.denominador_)
{
}
91
Introdução à Programação
2003/2004
Número de invocações:
Traçado
16
Racional::Racional(Racional const& original)
: numerador_(original.numerador_),
denominador_(original.denominador_)
{
}
92
Introdução à Programação
2003/2004
Número de invocações:
Traçado
16
Racional r(1, 3);
Racional s = r + 2;
// Fim!
93
Introdução à Programação
2003/2004
Conclusão


Há muito mais invocações do que
suspeitávamos: 16!
Cada invocação implica:






94
Ok, ok… Uma das
cópias provavelmente
não seria feita…
Colocar endereço de retorno na pilha
Construir parâmetros na pilha
Executar corpo
Destruir parâmetros da pilha
Construir instância de devolução (se for o caso)
Retornar ao local de invocação
Introdução à Programação
2003/2004
Eficiência

Dados



Conclusões

95
Programa passa 80% do tempo em 20% do
código
20% críticos desconhecidos a priori
Esforços de optimização antecipados são perda
de tempo
Introdução à Programação
2003/2004
Mas…

Há hábitos que contribuem para eficiência do
programa e não têm qualquer desvantagem:
1.
Usar passagem de argumentos por referência
constante onde apropriado
2.
Usar a palavra chave inline onde apropriado
Já se lá irá, já se lá irá…
96
Introdução à Programação
2003/2004
Rotinas em-linha (inline)

Corpo não existe num único local, sendo
executado sempre que desejado

Corpo é substituído pelo compilador em todos
ou três linhas, digamos,
os locais onde a rotinaDuas
é invocada
excluindo asserções.

97
Rotinas curtas e sem ciclos devem ser emlinha!
Introdução à Programação
2003/2004
Exemplo
Geram mesmo
código máquina!
inline int soma(int const a,
int const b)
{
return a + b;
}
int
int
int
int
x1 = 10;
x2 = 30;
x3 = 50;
r = 0;
int
int
int
int
int main()
{
r = x1 + x2;
r = r + x3;
} é
globais
int main()
Usar variáveis
{
má ideia! Isto é
r = soma(x1, x2);
exemplo!
r = soma(r, x3);
}
98
x1 = 10;
x2 = 30;
x3 = 50;
r = 0;
só um
Introdução à Programação
2003/2004
Sem inline (nem
optimização).
Exemplo em MAC-1
int soma(int const a,
int const b)
{
return a + b;
}
int
int
int
int
x1 = 10;
x2 = 30;
x3 = 50;
r = 0;
int main()
{
r = soma(x1, x2);
r = soma(r, x3);
}
99
main:
compilação
soma:
Introdução à Programação
jump main
# Variáveis:
x1 = 10
x2 = 30
x3 = 50
r = 0
# Aqui faz-se a soma:
lodd x1
# Carrega variável x1 no acumulador.
push
# Coloca acumulador no topo da pilha.
lodd x2
# Carrega variável x2 no acumulador.
push
# Coloca acumulador no topo da pilha.
# Aqui a pilha tem os dois argumentos x1 e x2:
call soma # Invoca a função soma.
insp 2
# Repõe a pilha (limpeza da casa).
# Aqui o acumulador tem o valor devolvido.
stod r
# Guarda o acumulador na variável r.
lodd r
# Carrega variável r no acumulador.
push
# Coloca acumulador no topo da pilha.
lodd x3
# Carrega variável x3 no acumulador.
push
# Coloca acumulador no topo da pilha.
# Aqui a pilha tem os dois argumentos r e x3:
call soma # Invoca a função soma.
insp 2
# Repõe a pilha (limpeza da casa).
# Aqui o acumulador tem o valor devolvido.
stod r
# Guarda o acumulador na variável r.
halt
lodl 2
addl 1
retn
2003/2004
0
x1: 1
x2: 2
x3: 3
r: 4
main: 5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
soma: 20
21
22
jump main
10
30
50
0
lodd x1
push
lodd x2
push
call soma
insp 2
stod r
lodd r
push
lodd x3
push
call soma
insp2
stod r
halt
lodl 2
addl 1
retn
pc
0
ac
?
sp
100
…
pilha
Instruções executadas:
93
94
95
96
97
98
99
100
?
?
?
?
?
?
?
?
0
100
Introdução à Programação
2003/2004
0
x1: 1
x2: 2
x3: 3
r: 4
main: 5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
soma: 20
21
22
jump main
10
30
50
0
lodd x1
push
lodd x2
push
call soma
insp 2
stod r
lodd r
push
lodd x3
push
call soma
insp2
stod r
halt
lodl 2
addl 1
retn
pc
5
ac
?
sp
100
…
Instruções executadas:
93
94
95
96
97
98
99
100
?
?
?
?
?
?
?
?
1
101
Introdução à Programação
2003/2004
0
x1: 1
x2: 2
x3: 3
r: 4
main: 5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
soma: 20
21
22
jump main
10
30
50
0
lodd x1
push
lodd x2
push
call soma
insp 2
stod r
lodd r
push
lodd x3
push
call soma
insp2
stod r
halt
lodl 2
addl 1
retn
pc
6
ac
10
sp
100
…
Instruções executadas:
93
94
95
96
97
98
99
100
?
?
?
?
?
?
?
?
2
102
Introdução à Programação
2003/2004
0
x1: 1
x2: 2
x3: 3
r: 4
main: 5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
soma: 20
21
22
jump main
10
30
50
0
lodd x1
push
lodd x2
push
call soma
insp 2
stod r
lodd r
push
lodd x3
push
call soma
insp2
stod r
halt
lodl 2
addl 1
retn
pc
7
ac
10
sp
99
…
Instruções executadas:
93
94
95
96
97
98
99
100
?
?
?
?
?
?
10
?
3
103
Introdução à Programação
2003/2004
0
x1: 1
x2: 2
x3: 3
r: 4
main: 5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
soma: 20
21
22
jump main
10
30
50
0
lodd x1
push
lodd x2
push
call soma
insp 2
stod r
lodd r
push
lodd x3
push
call soma
insp2
stod r
halt
lodl 2
addl 1
retn
pc
8
ac
30
sp
99
…
Instruções executadas:
93
94
95
96
97
98
99
100
?
?
?
?
?
?
10
?
4
104
Introdução à Programação
2003/2004
0
x1: 1
x2: 2
x3: 3
r: 4
main: 5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
soma: 20
21
22
jump main
10
30
50
0
lodd x1
push
lodd x2
push
call soma
insp 2
stod r
lodd r
push
lodd x3
push
call soma
insp2
stod r
halt
lodl 1
addl 2
retn
pc
9
ac
30
sp
98
…
Instruções executadas:
93
94
95
96
97
98
99
100
?
?
?
?
?
30
10
?
5
105
Introdução à Programação
2003/2004
0
x1: 1
x2: 2
x3: 3
r: 4
main: 5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
soma: 20
21
22
jump main
10
30
50
0
lodd x1
push
lodd x2
push
call soma
insp 2
stod r
lodd r
push
lodd x3
push
call soma
insp2
stod r
halt
lodl 2
addl 1
retn
pc
20
ac
30
sp
97
…
Instruções executadas:
93
94
95
96
97
98
99
100
?
?
?
?
10
30
10
?
6
106
Introdução à Programação
2003/2004
0
x1: 1
x2: 2
x3: 3
r: 4
main: 5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
soma: 20
21
22
jump main
10
30
50
0
lodd x1
push
lodd x2
push
call soma
insp 2
stod r
lodd r
push
lodd x3
push
call soma
insp2
stod r
halt
lodl 2
addl 1
retn
pc
21
ac
10
sp
97
…
Instruções executadas:
93
94
95
96
97
98
99
100
?
?
?
?
10
30
10
?
7
107
Introdução à Programação
2003/2004
0
x1: 1
x2: 2
x3: 3
r: 4
main: 5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
soma: 20
21
22
jump main
10
30
50
0
lodd x1
push
lodd x2
push
call soma
insp 2
stod r
lodd r
push
lodd x3
push
call soma
insp2
stod r
halt
lodl 2
addl 1
retn
pc
22
ac
40
sp
97
…
Instruções executadas:
93
94
95
96
97
98
99
100
?
?
?
?
10
30
10
?
8
108
Introdução à Programação
2003/2004
0
x1: 1
x2: 2
x3: 3
r: 4
main: 5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
soma: 20
21
22
jump main
10
30
50
0
lodd x1
push
lodd x2
push
call soma
insp 2
stod r
lodd r
push
lodd x3
push
call soma
insp2
stod r
halt
lodl 2
addl 1
retn
pc
10
ac
40
sp
98
…
Instruções executadas:
93
94
95
96
97
98
99
100
?
?
?
?
10
30
10
?
9
109
Introdução à Programação
2003/2004
0
x1: 1
x2: 2
x3: 3
r: 4
main: 5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
soma: 20
21
22
jump main
10
30
50
0
lodd x1
push
lodd x2
push
call soma
insp 2
stod r
lodd r
push
lodd x3
push
call soma
insp2
stod r
halt
lodl 2
addl 1
retn
pc
11
ac
40
sp
100
…
Instruções executadas:
93
94
95
96
97
98
99
100
?
?
?
?
10
30
10
?
10
110
Introdução à Programação
2003/2004
0
x1: 1
x2: 2
x3: 3
r: 4
main: 5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
soma: 20
21
22
jump main
10
30
50
40
lodd x1
push
lodd x2
push
call soma
insp 2
stod r
lodd r
push
lodd x3
push
call soma
insp2
stod r
halt
lodl 2
addl 1
retn
pc
12
ac
40
sp
100
…
Instruções executadas:
93
94
95
96
97
98
99
100
?
?
?
?
10
30
10
?
11
111
Introdução à Programação
2003/2004
0
x1: 1
x2: 2
x3: 3
r: 4
main: 5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
soma: 20
21
22
jump main
10
30
50
40
lodd x1
push
lodd x2
push
call soma
insp 2
stod r
lodd r
push
lodd x3
push
call soma
insp2
stod r
halt
lodl 2
addl 1
retn
pc
13
ac
40
sp
100
…
Instruções executadas:
93
94
95
96
97
98
99
100
?
?
?
?
10
30
10
?
12
112
Introdução à Programação
2003/2004
0
x1: 1
x2: 2
x3: 3
r: 4
main: 5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
soma: 20
21
22
jump main
10
30
50
40
lodd x1
push
lodd x2
push
call soma
insp 2
stod r
lodd r
push
lodd x3
push
call soma
insp2
stod r
halt
lodl 2
addl 1
retn
pc
14
ac
40
sp
99
…
Instruções executadas:
93
94
95
96
97
98
99
100
?
?
?
?
10
30
40
?
13
113
Introdução à Programação
2003/2004
0
x1: 1
x2: 2
x3: 3
r: 4
main: 5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
soma: 20
21
22
jump main
10
30
50
40
lodd x1
push
lodd x2
push
call soma
insp 2
stod r
lodd r
push
lodd x3
push
call soma
insp2
stod r
halt
lodl 2
addl 1
retn
pc
15
ac
50
sp
99
…
Instruções executadas:
93
94
95
96
97
98
99
100
?
?
?
?
10
30
40
?
14
114
Introdução à Programação
2003/2004
0
x1: 1
x2: 2
x3: 3
r: 4
main: 5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
soma: 20
21
22
jump main
10
30
50
40
lodd x1
push
lodd x2
push
call soma
insp 2
stod r
lodd r
push
lodd x3
push
call soma
insp2
stod r
halt
lodl 2
addl 1
retn
pc
16
ac
50
sp
98
…
Instruções executadas:
93
94
95
96
97
98
99
100
?
?
?
?
10
50
40
?
15
115
Introdução à Programação
2003/2004
0
x1: 1
x2: 2
x3: 3
r: 4
main: 5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
soma: 20
21
22
jump main
10
30
50
40
lodd x1
push
lodd x2
push
call soma
insp 2
stod r
lodd r
push
lodd x3
push
call soma
insp2
stod r
halt
lodl 2
addl 1
retn
pc
20
ac
50
sp
97
…
Instruções executadas:
93
94
95
96
97
98
99
100
?
?
?
?
17
50
40
?
16
116
Introdução à Programação
2003/2004
0
x1: 1
x2: 2
x3: 3
r: 4
main: 5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
soma: 20
21
22
jump main
10
30
50
40
lodd x1
push
lodd x2
push
call soma
insp 2
stod r
lodd r
push
lodd x3
push
call soma
insp2
stod r
halt
lodl 2
addl 1
retn
pc
21
ac
40
sp
97
…
Instruções executadas:
93
94
95
96
97
98
99
100
?
?
?
?
17
50
40
?
17
117
Introdução à Programação
2003/2004
0
x1: 1
x2: 2
x3: 3
r: 4
main: 5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
soma: 20
21
22
jump main
10
30
50
40
lodd x1
push
lodd x2
push
call soma
insp 2
stod r
lodd r
push
lodd x3
push
call soma
insp2
stod r
halt
lodl 2
addl 1
retn
pc
22
ac
90
sp
97
…
Instruções executadas:
93
94
95
96
97
98
99
100
?
?
?
?
17
50
40
?
18
118
Introdução à Programação
2003/2004
0
x1: 1
x2: 2
x3: 3
r: 4
main: 5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
soma: 20
21
22
jump main
10
30
50
40
lodd x1
push
lodd x2
push
call soma
insp 2
stod r
lodd r
push
lodd x3
push
call soma
insp2
stod r
halt
lodl 2
addl 1
retn
pc
17
ac
90
sp
98
…
Instruções executadas:
93
94
95
96
97
98
99
100
?
?
?
?
17
50
40
?
19
119
Introdução à Programação
2003/2004
0
x1: 1
x2: 2
x3: 3
r: 4
main: 5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
soma: 20
21
22
jump main
10
30
50
40
lodd x1
push
lodd x2
push
call soma
insp 2
stod r
lodd r
push
lodd x3
push
call soma
insp2
stod r
halt
lodl 2
addl 1
retn
pc
18
ac
90
sp
100
…
Instruções executadas:
93
94
95
96
97
98
99
100
?
?
?
?
17
50
40
?
20
120
Introdução à Programação
2003/2004
0
x1: 1
x2: 2
x3: 3
r: 4
main: 5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
soma: 20
21
22
jump main
10
30
50
90
lodd x1
push
lodd x2
push
call soma
insp 2
stod r
lodd r
push
lodd x3
push
call soma
insp2
stod r
halt
lodl 2
addl 1
retn
pc
19
ac
90
sp
100
…
Instruções executadas:
93
94
95
96
97
98
99
100
?
?
?
?
17
50
40
?
21
121
Introdução à Programação
2003/2004
Exemplo em MAC-1
Com inline.
inline int soma(int const a,
int const b)
{
return a + b;
}
int
int
int
int
x1 = 10;
x2 = 30;
x3 = 50;
r = 0;
main:
compilação
jump main
# Variáveis:
x1 = 10
x2 = 20
x3 = 30
r = 0
# Aqui faz-se a soma:
lodd x1
# Carrega variável x1 no acumulador.
addd x2
# Adiciona variável x2 ao acumulador.
stod r
# Guarda o acumulador na variável r.
lodd r
# Carrega variável r no acumulador.
addd x3
# Adiciona variável x3 ao acumulador.
stod r
# Guarda o acumulador na variável r.
halt
int main()
{
r = soma(x1, x2);
r = soma(r, x3);
}
122
Introdução à Programação
2003/2004
0
x1: 1
x2: 2
x3: 3
r: 4
main: 5
6
7
8
9
10
11
jump main
10
30
50
0
lodd x1
addd x2
stod r
lodd r
addd x3
stod r
halt
pc
0
ac
?
sp
100
…
pilha
Instruções executadas:
93
94
95
96
97
98
99
100
?
?
?
?
?
?
?
?
0
123
Introdução à Programação
2003/2004
0
x1: 1
x2: 2
x3: 3
r: 4
main: 5
6
7
8
9
10
11
jump main
10
30
50
0
lodd x1
addd x2
stod r
lodd r
addd x3
stod r
halt
pc
5
ac
?
sp
100
…
Instruções executadas:
93
94
95
96
97
98
99
100
?
?
?
?
?
?
?
?
1
124
Introdução à Programação
2003/2004
0
x1: 1
x2: 2
x3: 3
r: 4
main: 5
6
7
8
9
10
11
jump main
10
30
50
0
lodd x1
addd x2
stod r
lodd r
addd x3
stod r
halt
pc
6
ac
10
sp
100
…
Instruções executadas:
93
94
95
96
97
98
99
100
?
?
?
?
?
?
?
?
2
125
Introdução à Programação
2003/2004
0
x1: 1
x2: 2
x3: 3
r: 4
main: 5
6
7
8
9
10
11
jump main
10
30
50
0
lodd x1
addd x2
stod r
lodd r
addd x3
stod r
halt
pc
7
ac
40
sp
100
…
Instruções executadas:
93
94
95
96
97
98
99
100
?
?
?
?
?
?
?
?
3
126
Introdução à Programação
2003/2004
0
x1: 1
x2: 2
x3: 3
r: 4
main: 5
6
7
8
9
10
11
jump main
10
30
50
40
lodd x1
addd x2
stod r
lodd r
addd x3
stod r
halt
pc
8
ac
40
sp
100
…
Instruções executadas:
93
94
95
96
97
98
99
100
?
?
?
?
?
?
?
?
4
127
Introdução à Programação
2003/2004
0
x1: 1
x2: 2
x3: 3
r: 4
main: 5
6
7
8
9
10
11
jump main
10
30
50
40
lodd x1
addd x2
stod r
lodd r
addd x3
stod r
halt
pc
9
ac
40
sp
100
…
Instruções executadas:
93
94
95
96
97
98
99
100
?
?
?
?
?
?
?
?
5
128
Introdução à Programação
2003/2004
0
x1: 1
x2: 2
x3: 3
r: 4
main: 5
6
7
8
9
10
11
jump main
10
30
50
40
lodd x1
addd x2
stod r
lodd r
addd x3
stod r
halt
pc
10
ac
90
sp
100
…
Instruções executadas:
93
94
95
96
97
98
99
100
?
?
?
?
?
?
?
?
6
129
Introdução à Programação
2003/2004
0
x1: 1
x2: 2
x3: 3
r: 4
main: 5
6
7
8
9
10
11
jump main
10
30
50
90
lodd x1
addd x2
stod r
lodd r
addd x3
stod r
halt
pc
11
ac
90
sp
100
…
Instruções executadas:
7
130
93
94
95
96
97
98
99
100
?
?
?
?
?
?
?
?
Sem inline
eram 21…
Introdução à Programação
2003/2004
Comparação
Sem inline:
Sempre mais
rápido!
jump main
# Variáveis:
x1 = 10
x2 = 30
x3 = 50
r = 0
# Aqui faz-se a soma:
lodd x1
# Carrega variável x1 no acumulador.
push
# Coloca acumulador no topo da pilha.
lodd x2
# Carrega variável x2 no acumulador.
push
# Coloca acumulador no topo da pilha.
# Aqui a pilha tem os dois argumentos x1 e x2:
call soma # Invoca a função soma.
insp 2
# Repõe a pilha (limpeza da casa).
# Aqui o acumulador tem o valor devolvido.
stod r
# Guarda o acumulador na variável r.
lodd r
# Carrega variável r no acumulador.
push
# Coloca acumulador no topo da pilha.
lodd x3
# Carrega variável x3 no acumulador.
push
# Coloca acumulador no topo da pilha.
# Aqui a pilha tem os dois argumentos r e x3:
call soma # Invoca a função soma.
insp 2
# Repõe a pilha (limpeza da casa).
# Aqui o acumulador tem o valor devolvido.
stod r
# Guarda o acumulador na variável r.
halt
lodl 2
addl 1
retn
Com inline:
Sempre mais
curto?
main:
main:
Código demasiado longo
pode tornar a execução
mais lenta, pois obriga a
soma:
recorrer à memória
virtual.
131
Introdução à Programação
jump main
# Variáveis:
x1 = 10
x2 = 20
x3 = 30
r = 0
# Aqui faz-se a soma:
lodd x1
# Carrega variável x1 no acumulador.
addd x2
# Adiciona variável x2 ao acumulador.
stod r
# Guarda o acumulador na variável r.
lodd r
# Carrega variável r no acumulador.
addd x3
# Adiciona variável x3 ao acumulador.
stod r
# Guarda o acumulador na variável r.
halt
Não! Por vezes é mais
longo. Depende da
dimensão do código das
rotinas, do número de
invocações, etc.
2003/2004
Sintaxe

Colocar a palavra chave inline antes do cabeçalho
na definição da rotina:
inline tipo nome(parâmetros) …
{
…
}
ou
inline tipo Classe::nome(parâmetros) …
{
…
}
132
Introdução à Programação
2003/2004
Estrutura global do programa (I)
#include <iostream>
#include <cassert>
using namespace std;
/** Devolve o máximo divisor comum dos inteiros passados como argumento.
@pre m ≠ 0 ou n ≠ 0.
@post mdc = mdc(m, n). */
int mdc(int const m, int const n) {…}
class Racional {…};
inline Racional::Racional(int const n) {…}
Construtores
inline Racional::Racional(int const n, int const d) {…}
inline int Racional::numerador() const {…}
Inspectores
inline int Racional::denominador() const {…}
inline Racional::escreve() const {…}
(continua)
133
Introdução à Programação
2003/2004
Estrutura global do programa (II)
(continuação)
void Racional::lê() {…}
inline Racional& Racional::operator++() {…}
inline Racional& Racional::operator--() {…}
Modificadores
inline Racional& Racional::operator*=(Racional const& r2) {…}
inline Racional& Racional::operator/=(Racional const& r2) {…}
inline Racional& Racional::operator+=(Racional const& r2) {…}
inline Racional& Racional::operator-=(Racional const& r2) {…}
inline void Racional::reduz() {…}
Auxiliares
inline bool Racional::cumpreInvariante() const {…}
(continua)
134
Introdução à Programação
2003/2004
Estrutura global do programa (III)
(continuação)
/** Produto de dois racionais.
@pre V.
@post operator* = r1 × r2. */
inline Racional const operator*(Racional r1, Racional const& r2) {…}
Operadores
aritméticos
não-membro
/** Divisão de dois racionais.
@pre r2 ≠ 0.
@post operator/ = r1 / r2. */
inline Racional const operator/(Racional r1, Racional const& r2) {…}
/** Soma de dois racionais.
@pre V.
@post operator+ = r1 + r2. */
inline Racional const operator+(Racional r1, Racional const& r2) {…}
/** Subtracção de dois racionais.
@pre V.
@post operator- = r1 - r2. */
inline Racional const operator-(Racional r1, Racional const& r2) {…}
(continua)
135
Introdução à Programação
2003/2004
Estrutura global do programa (IV)
(continuação)
Operadores de
igualdade e
diferença
/** Indica se dois racionais são iguais.
@pre V.
@post operator== = (r1 = r2). */
inline bool operator==(Racional const& r1, Racional const& r2) {…}
/** Indica se dois racionais são diferentes.
@pre V.
@post operator!= = (r1 ≠ r2). */
inline bool operator!=(Racional const& r1, Racional const& r2) {…}
int main() {…}
136
Introdução à Programação
2003/2004
Operadores em falta

Aritméticos:


Relacionais:


<, <=, > e >=
Incrementação:


Unários: + e -
Sufixo: ++ e --
Começamos aqui.
Inserção e extracção de canais:

<< e >>
Fica por fazer...
137
Introdução à Programação
2003/2004
Incrementação prefixa
class Racional {
public:
…
/** Incrementa o racional.
@pre *this = r.
@post operator++ ≡ *this  *this = r + 1. */
Racional& operator++();
…
};
Racional& Racional::operator++()
{
assert(cumpreInvariante());
numerador_ += denominador();
assert(cumpreInvariante());
}
138
return *this;
Introdução à Programação
2003/2004
Incrementação sufixa
139
Introdução à Programação
2003/2004
Incrementação sufixa: a solução
/** Incrementa o racional, devolvendo o seu valor antes de incrementado.
@pre r = r.
@post operator++ = r  r = r + 1. */
inline Racional const operator++(Racional& r, int)
{
Racional const cópia = r;
++r;
return cópia; Devolve-se por valor um
Aha!} Cá está a diferença!
racional
Trata-se o operador como
se com o valor antes de
incrementado,
i.e., devolve-se
fosse binário, recebendo
como
a cópia
argumento um inteiro com
valordo racional r.
uma cópia de r antes de
não especificado Faz-se
e irrelevante.
se incrementar, recorrendo à
incrementação prefixa, já
definida.
140
Introdução à Programação
2003/2004
Decrementação sufixa: a solução
/** Decrementa o racional, devolvendo o seu valor antes de decrementado.
@pre r = r.
@post operator-- = r  r = r - 1. */
inline Racional const operator--(Racional& r, int)
{
Racional const cópia = r;
--r;
return cópia;
}
141
Introdução à Programação
2003/2004
Operador - unário: operação
/** … */
class Racional {
public:
…
/** Devolve simétrico do racional.
@pre V.
@post operator- = -*this. */
Racional const operator-() const;
…
private:
…
};
142
Introdução à Programação
2003/2004
Operador - unário: método
inline Racional const Racional::operator-() const
{
assert(cumpreInvariante());
Racional r;
r.numerador_ = -numerador();
r.denominador_ = denominador();
assert(r.cumpreInvariante());
return r;
}
143
Não é fundamental usar uma
rotina membro, mas permite
código mais eficiente, pois
pode-se mudar o sinal do
numerador directamente,
evitando-se invocações
espúrias do redutor de
fracções.
Introdução à Programação
2003/2004
Operador + unário
/** Devolve o racional.
@pre V.
@post operator+ ≡ r. */
inline Racional const& operator+(Racional const& r)
{
return r;
}
144
Introdução à Programação
2003/2004
Operador <
/** Devolve verdadeiro se o primeiro racional for menor que o segundo.
@pre V.
@post operator< = r1 < r2. */
inline bool operator<(Racional const& r1, Racional const& r2)
{
return r1.numerador() * r2.denominador() <
r2.numerador() * r1.denominador();
}
Como 0 < r1.d  0 < r2.d,
r1.n / r1.d < r2.n / r2.d 
r1.n x r2.d < r2.n * r1.d
145
Introdução à Programação
2003/2004
Operadores <=, > e >=

Podem-se definir à custa do operador <

Como?
146
Introdução à Programação
2003/2004
Operador >
/** Devolve verdadeiro se o primeiro racional for maior que o segundo.
@pre V.
@post operator> = r1 > r2. */
inline bool operator>(Racional const& r1, Racional const& r2)
{
return r2 < r1;
}
147
Introdução à Programação
2003/2004
Operador <=
/** Devolve verdadeiro se o primeiro racional for menor ou igual ao segundo.
@pre V.
@post operator<= = r1 <= r2. */
inline bool operator<=(Racional const& r1, Racional const& r2)
{
return not (r1 > r2);
}
148
Introdução à Programação
2003/2004
Operador >=
/** Devolve verdadeiro se o primeiro racional for menor ou igual ao segundo.
@pre V.
@post operator>= = r1 >= r2. */
inline bool operator>=(Racional const& r1, Racional const& r2)
{
return not (r1 < r2);
}
149
Introdução à Programação
2003/2004
Outro desafio (fácil)

150
Definir o operador == à custa do operador <
Introdução à Programação
2003/2004
Último problema

Operador /= usa o operador !=, definido mais
tarde

Melhor solução:


151
concentrar declarações de rotinas não-membro
após definição da classe
Definir rotinas não-membro mais tarde
Introdução à Programação
2003/2004
Preâmbulo e definição da classe
C++
#include <iostream>
#include <cassert>
using namespace std;
/** Devolve o máximo divisor comum dos inteiros passados como argumento.
@pre m ≠ 0 ou n ≠ 0.
@post mdc = mdc(m, n). */
int mdc(int const m, int const n) {…}
class Racional {…};
152
Introdução à Programação
2003/2004
Declaração de rotinas
não-membro (I)
Incrementação e
decrementação
sufixas
/** Incrementa o racional, devolvendo o seu valor antes de incrementado.
@pre r = r.
@post operator++ = r  r = r + 1. */
Racional const operator++(Racional& r, int);
/** Decrementa o racional, devolvendo o seu valor antes de decrementado.
@pre r = r.
@post operator-- = r  r = r - 1. */
Racional const operator--(Racional& r, int);
153
Introdução à Programação
2003/2004
Declaração de rotinas
não-membro (II)
/** Produto de dois racionais.
@pre V.
@post operator* = r1 × r2. */
Racional const operator*(Racional r1, Racional const& r2);
Operadores
aritméticos
binários
/** Divisão de dois racionais.
@pre r2 ≠ 0.
@post operator/ = r1 / r2. */
Racional const operator/(Racional r1, Racional const& r2);
/** Soma de dois racionais.
@pre V.
@post operator+ = r1 + r2. */
Racional const operator+(Racional r1, Racional const& r2);
/** Subtracção de dois racionais.
@pre V.
@post operator- = r1 - r2. */
Racional const operator-(Racional r1, Racional const& r2);
154
Introdução à Programação
2003/2004
Declaração de rotinas
não-membro (III)
Operador
identidade
Operadores de
igualdade e
diferença
/** Devolve o racional.
@pre V.
@post operator+ ≡ r. */
Racional const& operator+(Racional const& r);
/** Indica se dois racionais são iguais.
@pre V.
@post operator== = (r1 = r2). */
bool operator==(Racional const& r1, Racional const& r2);
/** Indica se dois racionais são diferentes.
@pre V.
@post operator!= = (r1 ≠ r2). */
bool operator!=(Racional const& r1, Racional const& r2);
155
Introdução à Programação
2003/2004
Declaração de rotinas
não-membro (IV)
/** Devolve verdadeiro se o primeiro racional for menor que o segundo.
@pre V.
@post operator< = r1 < r2. */
bool operator<(Racional const& r1, Racional const& r2);
Operadores
relacionais
/** Devolve verdadeiro se o primeiro racional for maior que o segundo.
@pre V.
@post operator> = r1 > r2. */
bool operator>(Racional const& r1, Racional const& r2);
/** Devolve verdadeiro se o primeiro racional for menor ou igual ao segundo.
@pre V.
@post operator<= = r1 <= r2. */
bool operator<=(Racional const& r1, Racional const& r2);
/** Devolve verdadeiro se o primeiro racional for maior ou igual ao segundo.
@pre V.
@post operator>= = r1 >= r2. */
bool operator>=(Racional const& r1, Racional const& r2);
156
Introdução à Programação
2003/2004
Definição de métodos (I)
Construtores
Inspectores
Modificadores
Auxiliares
inline Racional::Racional(int const n) {…}
inline Racional::Racional(int const n, int const d) {…}
inline int Racional::numerador() const {…}
inline int Racional::denominador() const {…}
inline void Racional::escreve() const {…}
inline Racional const Racional::operator-() const {…}
void Racional::lê() {…}
inline Racional& Racional::operator++() {…}
inline Racional& Racional::operator--() {…}
inline Racional& Racional::operator*=(Racional const& r2)
inline Racional& Racional::operator/=(Racional const& r2)
inline Racional& Racional::operator+=(Racional const& r2)
inline Racional& Racional::operator-=(Racional const& r2)
inline void Racional::reduz() {…}
inline bool Racional::cumpreInvariante() const {…}
{…}
{…}
{…}
{…}
(continua)
157
Introdução à Programação
2003/2004
Definição de rotinas não-membro
Incrementação e
decrementação
sufixas
inline Racional const operator++(Racional& r, int) {…}
inline Racional const operator--(Racional& r, int) {…}
inline Racional const operator*(Racional r1, Racional const& r2) {…}
Operadores
aritméticos
binários
inline Racional const operator/(Racional r1, Racional const& r2) {…}
inline Racional const operator+(Racional r1, Racional const& r2) {…}
inline Racional const operator-(Racional r1, Racional const& r2) {…}
Operador
identidade
Operadores de
igualdade e
diferença
inline Racional const& operator+(Racional const& r) {…}
inline bool operator==(Racional const& r1, Racional const& r2) {…}
inline bool operator!=(Racional const& r1, Racional const& r2) {…}
inline bool operator<(Racional const& r1, Racional const& r2) {…}
Operadores
relacionais
inline bool operator>(Racional const& r1, Racional const& r2) {…}
inline bool operator<=(Racional const& r1, Racional const& r2) {…}
inline bool operator>=(Racional const& r1, Racional const& r2) {…}
int main() {…}
158
Introdução à Programação
2003/2004
TAD Racional (construtores)
/** Representa números racionais.
@invariant 0 < denominador_  mdc(numerador_, denominador_) = 1. */
class Racional {
public:
/** Constrói racional com valor inteiro.
@pre V.
@post *this = valor. */
Racional(int const valor = 0);
/** Constrói racional correspondente a numerador/denominador.
@pre denominador ≠ 0.
@post *this = numerador/denominador. */
Racional(int const numerador, int const denominador);
(continua)
159
Introdução à Programação
2003/2004
TAD Racional (inspectores)
(continuação)
/** Devolve numerador da fracção mínima correspondente ao racional.
@pre V.
@post numerador/denominador() = *this. */
int numerador() const;
/** Devolve denominador da fracção mínima correspondente ao racional.
@pre V.
@post 0 < denominador  (E n : V : n/denominador = *this 
mdc(n, denominador) = 1). */
int denominador() const;
(continua)
160
Introdução à Programação
2003/2004
TAD Racional (inspectores)
(continuação)
/** Escreve um racional no ecrã no formato de uma fracção.
@pre V.
@post cout.fail() ou cout contém n/d (ou simplesmente n, se d = 1) em
que n e d são os valores de numerador e denominador. */
void escreve() const;
/** Devolve simétrico do racional.
@pre V.
@post operator- = -*this. */
Racional const operator-() const;
(continua)
161
Introdução à Programação
2003/2004
TAD Racional (modificadores)
(continuação)
/** Lê do teclado um racional, na forma de dois inteiros sucessivos.
@pre *this = r.
@post Se cin.good()  cin tem dois inteiros n e d disponíveis para
leitura, com d <> 0, então *this = n/d  cin.fail(),
senão *this = r  cin.fail(). */
void lê();
/** Incrementa o racional.
@pre *this = r.
@post operator++ ≡ *this  *this = r + 1. */
Racional& operator++();
/** Decrementa o racional.
@pre *this = r.
@post operator-- ≡ *this  *this = r - 1. */
Racional& operator--();
(continua)
162
Introdução à Programação
2003/2004
TAD Racional (modificadores)
(continuação)
/** Multiplica por um racional.
@pre *this = r.
@post operator*= ≡ *this  *this = r × r2. */
Racional& operator*=(Racional const& r2);
/** Divide por um racional.
@pre *this = r  r2 ≠ 0.
@post operator/= ≡ *this  *this = r / r2. */
Racional& operator/=(Racional const& r2);
/** Adiciona de um racional.
@pre *this = r.
@post operator+= ≡ *this  *this = r + r2. */
Racional& operator+=(Racional const& r2);
/** Subtrai de um racional.
@pre *this = r.
@post operator-= ≡ *this  *this = r - r2. */
Racional& operator-=(Racional const& r2);
(continua)
163
Introdução à Programação
2003/2004
TAD Racional (implementação)
(continuação)
private:
/** Indica se a CIC se verifica.
@pre V.
@post cumpreInvariante =
0 < denominador_  mdc(numerador_, denominador_) = 1. */
bool cumpreInvariante() const;
/** Reduz a fracção que representa o racional.
@pre denominador_ ≠ 0  *this = r.
@post denominador_ ≠ 0 
mdc(numerador_, denominador_) = 1  *this = r. */
void reduz();
int numerador_;
int denominador_;
};
164
Introdução à Programação
2003/2004
Aula 13: Sumário

Definindo constantes de uma classe:





Evitando o mecanismo de invocação de rotinas no código máquina produzido
pelo compilador:








165
Necessidade de declarar operações como constantes (que não alteram a instância
implícita).
Sintaxe.
Devolução por valor constante.
Vantagens da utilização de const.
Rotinas inline.
Sintaxe.
Regras de utilização.
Explicação do efeito de inline sobre o código máquina produzido.
Exemplo com programa em C++ e respectiva tradução para MAC-1 (ver
Arquitectura de Computadores).
Quando optimizar.
Incrementação e decrementação sufixa: sobrecarga.
Ordem de declaração/definição de operações/métodos e rotinas não-membro
associados a um TAD.
Introdução à Programação
2003/2004
Download

Aula teórica - iscte-iul