inline
.
Sintaxe. Regras de utilização.inline
sobre o código
máquina produzido. Exemplo com programa em C++ e respectiva tradução
para MAC-1 (ver Arquitectura de Computadores).Escrever logo no quadro o programa da soma e as suas versões MAC-1!
Na última aula introduzimos mais alguns operadores nossa classe C++ Racional
.
O resultado é o que podem ver no quadro.
Ficaram por definir alguns operadores, mas antes de os pensar em definir há que pensar noutros assuntos...
#include <iostream>
#include <cassert>
using namespace std;
/**
Devolve o máximo divisor comum dos inteiros passados como argumento.
@pre
m
<> 0 oun
<> 0.
@post
mdc
= mdc(m
,n
).*/
int mdc(int const m, int const n)
{
assert(m != 0 or n != 0);
...
}
/**
Representa números racionais.@invariant 0 <
denominador_
e 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 an
/d
.@pre
d
<> 0.@post
*this
=numerador
/denominador
.*/
Racional(int const numerador, int const denominador);
/**
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 (E n : : n/
denominador
=*this
e 0 <denominador
e
mdc(n,
denominador
) = 1).*/
int denominador();
/**
Escreve um racional no ecrã no formato de uma fracção.
@pre V.
@post ¬
cout
.good
() oucout
contémn/d
(ou simplesmente
n
, sed
= 1) em quen
ed
são os valores denumerador
() edenominador
().*/
void escreve();
/**
Lê do teclado o racional, na forma de dois inteiros sucessivos.
@pre
*this
= r.
@post Se
cin
.good
() ecin
tem dois inteiros n' e d' disponíveis para
leitura, com d' <> 0,
então
*this
= n'/d',
senão
*this
= r e¬cin
.good
().*/
void lê();
/**
Incrementa o racional.@pre
*this
= r.
@post
operator++
idêntico a*this
e*this
= r + 1. */
Racional& operator++();
/**
Decrementa o racional.@pre
*this
= r.
@post
operator--
idêntico a*this
e*this
= r - 1. */
Racional& operator--();
/**
Multiplica por um racional.@pre
*this
= r.
@post
operator*=
idêntico a*this
e*this
= r ×r2
. */
Racional& operator*=(Racional const& r2);
/**
Divide por um racional.@pre
*this
= r er2
<> 0.
@post
operator/=
idêntico a*this
e*this
= r /r2
. */
Racional& operator/=(Racional const& r2);
/**
Adiciona de um racional.@pre
*this
= r.
@post
operator+=
idêntico a*this
e*this
= r +r2
. */
Racional& operator +=(Racional const& r2);
/**
Subtrai de um racional.@pre
*this
= r.
@post
operator-=
idêntico a*this
e*this
= r -r2
. */
Racional& operator-=(Racional const& r2);
private:
int numerador_;
int denominador_;
/**
Reduz a fracção que representa o racional.
@pre
denominador_
<> 0 e*this
= r.
@post
denominador_
<> 0 e mdc(numerador_
,denominador_
) = 1 e
*this
= r.*/
void reduz();
/**
Indica se a CIC se verifica.@pre V.
@post
cumpreInvariante
= 0 <denominador_
e mdc(numerador_
,denominador_
) = 1.*/
bool cumpreInvariante();
};
Racional::Racional(int const valor)
: numerador_(valor), denominador_(1)
{
assert(cumpreInvariante());
assert(numerador() == valor * denominador());
}
Racional::Racional(int const numerador, int const denominador)
{
assert(denominador != 0);
if(denominador < 0) {
numerador_ = -numerador;
denominador_ = -denominador;
} else {
numerador_ = numerador;
denominador_ = denominador;
}
reduz();
assert(cumpreInvariante());
assert(numerador_() * denominador == numerador * denominador());
}
int Racional::numerador()
{
assert(cumpreInvariante());
assert(cumpreInvariante());
return numerador_;
}
int Racional::denominador()
{
...
}
void Racional::escreve()
{
...
}
void Racional::lê()
{
...
}
Racional& Racional::operator++()
{
...
}
Racional& Racional::operator--()
{
...
}
Racional& Racional::operator*=(Racional const& r2)
{
...
}
Racional& Racional::operator/=(Racional const& r2)
{
...
}
Racional& Racional::operator+=(Racional const& r2)
{
assert(cumpreInvariante() and r2.cumpreInvariante());
numerador_ = numerador_ * r2.denominador_ +
r2.numerador_ * denominador_;denominador_ *= r2.denominador_;
reduz();
assert(cumpreInvariante());
return *this;
}
Racional& Racional::operator-=(Racional const& r2)
{
...
}
void Racional::reduz()
{
assert(denominador_ != 0);
int divisor = mdc(numerador_, denominador_);
numerador_ /= divisor;
denominador_ /= divisor;
assert(denominador_ != 0 and mdc(numerador_, denominador_) == 1);
}
bool Racional::cumpreInvariante()
{
...
}
/**
Produto de dois racionais.@pre V.
@post
operator*
=r1
×r2
. */
Racional const operator*(Racional r1, Racional const& r2){
...
}
/**
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){
return r1 += r2;
}
/**
Subtracção de dois racionais.@pre V.
@post
operator-
=r1
-r2
. */
Racional const operator-(Racional r1, Racional const& r2){
...
}
/**
Devolve verdadeiro se dois racionais forem iguais.@pre V.
@post
operator==
= (r1
=r2
).*/
bool operator==(Racional const& r1, Racional const& r2){
return r1.numerador() == r2.numerador() and
r1.denominador() == r2.denominador();
}
/**
Devolve verdadeiro se dois racionais forem iguais.@pre V.
@post
operator
!=
= (r1
<>r2
).*/
bool operator!=(Racional const& r1, Racional const& r2){
...
}
int main()
{
...
}
Será que se podem definir constantes racionais? Sim!
Mas o que acontece quando se faz:
Racional const um_terço(1, 3);
Dá erro! O compilador assume que as operações alteram a instância implícita! E a instância implícita é... constante!
cout << "O denominador é " << um_terço.denominador() << endl;
Note-se que o mesmo problema já existia neste código. Repare-se no
operador ==
, por exemplo. Explicar.
Logo, é necessário indicar explicitamente ao compilador quais as operações cujos métodos não alteram a instância implícita, ou seja, que esta funciona como uma constante implícita.
Explicar sintaxe e espalhar const
pelo código.
Discutir cuidadosamente a constância da variável implícita: variáveis membro
inalteráveis e operações não constantes proibidas!
...
/**
Representa números racionais.@invariant 0 <
denominador_
e mdc(numerador_
,denominador_
) = 1.*/
class Racional {
public:
...
/**
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 (E n : : n/
denominador
=*this
e 0 <denominador
e
mdc(n,
denominador
) = 1).*/
int denominador() const;
/**
Escreve um racional no ecrã no formato de uma fracção.
@pre V.
@post ¬
cout
.good
() oucout
contémn/d
(ou simplesmente
n
, sed
= 1) em quen
ed
são os valores denumerador
() edenominador
().*/
void escreve() const;
...
private:
...
/**
Indica se a CIC se verifica.@pre V.
@post
cumpreInvariante
= 0 <denominador_
e mdc(numerador_
,denominador_
) = 1.*/
bool cumpreInvariante() const;
};...
int Racional::numerador() const
{
assert(cumpreInvariante());
assert(cumpreInvariante());
return numerador_;
}
int Racional::denominador() const
{
...
}
void Racional::escreve() const
{
...
}
...
bool Racional::cumpreInvariante() const
{
...
}
...
Note-se que nas operações que garantem a constância da instância implícita não é necessário verificar a veracidade da condição invariante no seu final!
As operações podem assim ser divididas em operações que modificam e operações que não modificam a instância implícita. As segundas dizem-se modificadoras, enquanto as primeiras, pelo menos no caso das funções, dizem-se inspectoras. Também é típico chamar às funções membro inspectoras interrogações (queries).
Atenção! É muito importante pensar logo nas operações de uma classe como sendo ou não constantes, ou melhor, como garantindo ou não a constância da instância implícita.
As invocações de rotinas (membro ou não) implicam tarefas de arrumação da casa algo morosas: é necessário colocar na pilha o endereço de retorno e os respectivo argumentos, executar as instruções do corpo da rotina, depois retirar os argumentos da pilha, e retornar, eventualmente devolvendo o resultado no seu topo. Referir Arquitectura de Computadores e aulas sobre rotinas recursivas (aquela com os pesos). Suponha-se a invocação:
Quantas invocações de rotinas são feitas neste código?
Racional r(1, 3);
Racional s = r + 2;
Dar dica acerca de construtores por cópia!
reduz()
.mdc()
.r
para
o parâmetro r1
do operador +
.+
. +=
.reduz()
.mdc()
.r1
no operador
+
.s
à custa do
valor devolvido pelo operador +
.Não será lento? Como evitá-lo? Duma forma simples: rotinas muito simples, tipicamente não fazendo uso de ciclos e consistindo em apenas duas ou três linhas (excluindo instruções de asserção), podem ser em-linha ou inline. Que significa? Que o compilador, em vez de traduzir o código da rotina uma vez e chamá-lo quando necessário, coloca o código da rotina directamente nos locais de chamada! Por exemplo:
fica com o mesmo código máquina que
inline int soma(int const a, int const b)
{return a + b;
}
int main()
{int x1 = 10;
int x2 = 20;
int x3 = 30;
int r = 0;
r = soma(x1, x2);
r = soma(r, x3);
}
É interessante ver-se a tradução para assembly do MAC-1 (citar Arquitectura de Computadores) dos dois programas.
int main()
{int x1 = 10;
int x2 = 20;
int x3 = 30;
int r = 0;
r = x1 + x2;
r = r + x3;
}
Sem inline
:
jump main
#
Variáveis:
x1 = 10
x2 = 20
x3 = 30
r = 0
#
Aqui faz-se a soma:
main: lodd x1 #
Carrega variávelx1
no acumulador.Coloca acumulador no topo da pilha.
push #Carrega variável
lodd x2 #x2
no acumulador.Coloca acumulador no topo da pilha.
push #
#
Aqui a pilha tem os dois argumentosx1
ex2
:Invoca a função
call soma #soma
.Repõe a pilha (limpeza da casa).
insp 2 #
#
Aqui o acumulador tem o valor devolvido.Guarda o acumulador na variável
stod r #r
.
lodd r #
Carrega variávelr
no acumulador.Coloca acumulador no topo da pilha.
push #Carrega variável
lodd x3 #x3
no acumulador.Coloca acumulador no topo da pilha.
push #
#
Aqui a pilha tem os dois argumentosr
ex3
:Invoca a função
call soma #soma
.Repõe a pilha (limpeza da casa).
insp 2 #
#
Aqui o acumulador tem o valor devolvido.Guarda o acumulador na variável
stod r #r
.
halt
soma: lodl 1
addl 2
retn
Com
inline
:
jump main
#
Variáveis:
x1 = 10
x2 = 20
x3 = 30
r = 0
#
Aqui faz-se a soma:
main: lodd x1 #
Carrega variávelx1
no acumulador.Adiciona variável
addd x2 #x2
ao acumulador.Guarda o acumulador na variável
stod r #r
.
lodd r #
Carrega variávelr
no acumulador.Adiciona variável
addd x3 #x3
ao acumulador.Guarda o acumulador na variável
stod r #r
.
halt
Explicar que programa consome memória!
Explicar que a dimensão do código pode aumentar! Se as rotinas forem simples, a dimensão do código pode diminuir, que é o que acontece neste caso!
Espalhar inline
pelos métodos (tudo
excepto lê()
e mdc()
). Explicar que basta indicar que são
em linha (inline
) na
definição!
...
inline Racional::Racional(int const valor)
: numerador_(valor), denominador_(1)
{
assert(cumpreInvariante());
assert(numerador() == valor * denominador());
}
inline Racional::Racional(int const numerador, int const denominador)
...
{
}
inline int Racional::numerador()
{
assert(cumpreInvariante());
assert(cumpreInvariante());
return numerador_;
}
inline int Racional::denominador()
{
...
}
inline void Racional::escreve()
{
...
}
inline 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)
{
assert(cumpreInvariante() and r2.cumpreInvariante());
numerador_ = numerador_ * r2.denominador_ +
r2.numerador_ * denominador_;denominador_ *= r2.denominador_;
reduz();
assert(cumpreInvariante());
return *this;
}
inline Racional& Racional::operator-=(Racional const& r2)
{
...
}
inline void Racional::reduz()
{
assert(denominador_ != 0);
int divisor = mdc(numerador_, denominador_);
numerador_ /= divisor;
denominador_ /= divisor;
assert(denominador_ != 0 and mdc(numerador_, denominador_) == 1);
}
inline bool Racional::cumpreInvariante()
{
...
}
/**
Produto de dois racionais.@pre V.
@post
operator*
=r1
×r2
. */
inline Racional const operator*(Racional r1, Racional const& r2){
...
}
/**
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){
return r1 += r2;
}
/**
Subtracção de dois racionais.@pre V.
@post
operator-
=r1
-r2
. */
inline Racional const operator-(Racional r1, Racional const& r2){
...
}
/**
Devolve verdadeiro se dois racionais forem iguais.@pre V.
@post
operator==
= (r1
=r2
).*/
inline bool operator==(Racional const& r1, Racional const& r2){
return r1.numerador() == r2.numerador() and
r1.denominador() == r2.denominador();
}
/**
Devolve verdadeiro se dois racionais forem iguais.@pre V.
@post
operator
!=
= (r1
<>r2
).*/
inline bool operator!=(Racional const& r1, Racional const& r2){
...
}
int main()
{
...
}
Se houver tempo:
Ficaram a faltar...
++
,--
sufixo
+
,-
unários
<
,<=
,>
,>=
e ainda
<<
e>>
para inserção e extracção em e de canais
Vamos definir primeiro os operadores de incrementação e decrementação sufixo.
Discutir com eles que têm o mesmo número de operandos que os prefixo. Como os distinguir?
Distinguem-se de uma forma simples e eficiente, embora muito, muito
feia... Basta dizer que têm um parâmetro adicional do tipo int
!
Assim, se forem definidos fora da classe C++ terão o aspecto:
Racional const operator++(Racional& r, int);
e se forem definidos dentro da classe C++, como membros,
Racional const Racional::operator++(int);
Vamos defini-los como não-membros da classe C++:
/**
Incrementa o racional, devolvendo o seu valor antes de incrementado.@pre
r
= r.@post
operator++
= r er
= r + 1.*/
inline Racional const operator++(Racional& r, int)
{
Racional copia = r;
++r;
return copia;
}
/**
Decrementa o racional, devolvendo o seu valor antes de decrementado.@pre
r
= r.@post
operator--
= r er
= r - 1.*/
inline Racional const operator--(Racional& r, int)
{
Racional copia = r;
--r;
return copia;
}
Chamo a atenção para o facto de os operadores fazerem logicamente parte do TAD, mesmo não pertencendo à classe C++ que o implementa!
E os operadores +
e -
unários? São simples:
/**
Representa números racionais.@invariant 0 <
denominador_
e mdc(numerador_
,denominador_
) = 1.*/
class Racional {
public:
...
/**
Devolve simétrico do racional.@pre V.
@post
operator-
= -*this
.*/
Racional const operator-() const;
...
};
...
inline Racional const Racional::operator-() const
{
assert(cumpreInvariante());
Racional r;
r.numerador_ = -numerador_;
r.denominador_ = denominador_;
assert(r.cumpreInvariante());
return r;
}
/**
Devolve o racional.@pre V.
@post
operator+
idêntico ar
.*/
inline Racional const& operator+(Racional const& r)
{
return r;
}...
Explicar porque se definiu o operador simétrico como membro! (Por razões de eficiência, pois evitam-se tentativas de redução do racional.)
Finalmente falta definir os operadores relacionais. Comecemos pelo
operador <
. Fá-lo-emos não-membro pela mesma razão que
o operador ==
também o é.
/**
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();
}
Os restantes são fáceis de definir à custa deste!
Discutir!
/**
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;
}
/**
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);
}
/**
Devolve verdadeiro se o primeiro racional for maior ou igual ao segundo.@pre V.
@post
operator<
=r1
>=r2
.*/
inline bool operator>=(Racional const& r1, Racional const& r2)
{
return not (r1 < r2);
}
Curiosamente também é possível definir os operadores igual e diferente à custa do operador menor! Fica como exercício!
Os operadores de inserção e extracção de um canal ficam também como exercício.
O código como está não funciona. Por exemplo, o operador /=
usa o operador !=
declarado e definido mais tarde. O ideal
neste caso será agrupar as declarações das rotinas do TAD que são externas
à classe C++ junto a essa mesma classe:
#include <iostream>
#include <cassert>
using namespace std;
/**
Devolve o máximo divisor comum dos inteiros passados como argumento.
@pre
m
<> 0 oun
<> 0.
@post
mdc
= mdc(m
,n
).*/
int mdc(int const m, int const n)
{
assert(m != 0 or n != 0);
...
}
/**
Representa números racionais.@invariant 0 <
denominador_
e 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 an
/d
.@pre
d
<> 0.@post
*this
=numerador
/denominador
.*/
Racional(int const numerador, int const denominador);
/**
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 (E n : : n/
denominador
=*this
e 0 <denominador
e
mdc(n,
denominador
) = 1).*/
int denominador();
/**
Escreve um racional no ecrã no formato de uma fracção.
@pre V.
@post ¬
cout
.good
() oucout
contémn/d
(ou simplesmente
n
, sed
= 1) em quen
ed
são os valores denumerador
() edenominador
().*/
void escreve();
/**
Devolve simétrico do racional.@pre V.
@post
operator-
= -*this
.*/
Racional const operator-() const;
/**
Lê do teclado o racional, na forma de dois inteiros sucessivos.
@pre
*this
= r.
@post Se
cin
.good
() ecin
tem dois inteiros n' e d' disponíveis para
leitura, com d' <> 0,
então
*this
= n'/d',
senão
*this
= r e¬cin
.good
().*/
void lê();
/**
Incrementa o racional.@pre
*this
= r.
@post
operator++
idêntico a*this
e*this
= r + 1. */
Racional& operator++();
/**
Decrementa o racional.@pre
*this
= r.
@post
operator--
idêntico a*this
e*this
= r - 1. */
Racional& operator--();
/**
Multiplica por um racional.@pre
*this
= r.
@post
operator*=
idêntico a*this
e*this
= r ×r2
. */
Racional& operator*=(Racional const& r2);
/**
Divide por um racional.@pre
*this
= r er2
<> 0.
@post
operator/=
idêntico a*this
e*this
= r /r2
. */
Racional& operator/=(Racional const& r2);
/**
Adiciona de um racional.@pre
*this
= r.
@post
operator+=
idêntico a*this
e*this
= r +r2
. */
Racional& operator +=(Racional const& r2);
/**
Subtrai de um racional.@pre
*this
= r.
@post
operator-=
idêntico a*this
e*this
= r -r2
. */
Racional& operator-=(Racional const& r2);
private:
int numerador_;
int denominador_;
/**
Reduz a fracção que representa o racional.
@pre
denominador_
<> 0 e*this
= r.
@post
denominador_
<> 0 e mdc(numerador_
,denominador_
) = 1 e
*this
= r.*/
void reduz();
/**
Indica se a CIC se verifica.@pre V.
@post
cumpreInvariante
= 0 <denominador_
e mdc(numerador_
,denominador_
) = 1.*/
bool cumpreInvariante() const;
};
/**
Incrementa o racional, devolvendo o seu valor antes de incrementado.@pre
r
= r.@post
operator++
= r er
= r + 1.*/
inline Racional const operator++(Racional& r, int);
/**
Decrementa o racional, devolvendo o seu valor antes de decrementado.@pre
r
= r.@post
operator--
= r er
= r - 1.*/
inline Racional const operator--(Racional& r, int);
/**
Produto de dois racionais.@pre V.
@post
operator*
=r1
×r2
. */
Racional const operator*(Racional r1, Racional const& r2);
/**
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)
/**
Devolve o racional.@pre V.
@post
operator+
idêntico ar
.*/
inline Racional const& operator+(Racional const& r);
/**
Devolve verdadeiro se dois racionais forem iguais.@pre V.
@post
operator==
= (r1
=r2
).*/
bool operator==(Racional const& r1, Racional const& r2);
/**
Devolve verdadeiro se dois racionais forem iguais.@pre V.
@post
operator
!=
= (r1
<>r2
).*/
;
bool operator!=(Racional const& r1, Racional const& r2)
/**
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);
/**
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);
/**
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);
/**
Devolve verdadeiro se o primeiro racional for maior ou igual ao segundo.@pre V.
@post
operator<
=r1
>=r2
.*/
inline bool operator>=(Racional const& r1, Racional const& r2);
inline Racional::Racional(int const valor)
: numerador_(valor), denominador_(1)
...
{
}
inline Racional::Racional(int const numerador, int const denominador)
...
{
}
inline int Racional::numerador()
{
...
}
inline int Racional::denominador()
{
...
}
inline void Racional::escreve()
{
...
}
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 inline void Racional::reduz()
{
...
}
inline bool Racional::cumpreInvariante()
{
...
}
inline Racional const operator++(Racional& r, int)
...
{
}
inline Racional const operator--(Racional& r, int)
...
{
}
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)
{
...
}
inline Racional const operator-(Racional r1, Racional const& r2)
{
...
}
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)
...
{
}
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()
{
...
}
#ifdef TESTE
int main()
{
assert(mdc(10, 0) == 10);
assert(mdc(0, 10) == 10);
assert(mdc(10, 10) == 10);
assert(mdc(3, 7) == 1);
assert(mdc(8, 6) == 2);
assert(mdc(-8, 6) == 2);
assert(mdc(8, -6) == 2);
assert(mdc(-8, -6) == 2);
Racional r1(2, -6);
assert(r1.numerador() == -1 and r1.denominador() == 3);
Racional r2(3);
assert(r2.numerador() == 3 and r2.denominador() == 1);
Racional r3;
assert(r2 == 3);
assert(3 == r2);
assert(r3 == 0);
assert(0 == r3);
assert(r1 < r2);
assert(r2 > r1);
assert(r1 <= r2);
assert(r2 >= r1);
assert(r1 <= r1);
assert(r2 >= r2);
assert(r2 == +r2);
assert(-r1 == Racional(1, 3));
assert(++r1 == Racional(2, 3));
assert(r1 == Racional(2, 3));
assert(r1++ == Racional(2, 3));
assert(r1 == Racional(5, 3));
assert((r1 *= Racional(7, 20)) == Racional(7, 12));
assert((r1 /= Racional(3, 4)) == Racional(7, 9));
assert((r1 += Racional(11, 6)) == Racional(47, 18));
assert((r1 -= Racional(2, 18)) == Racional(5, 2));
assert(r1 + r2 == Racional(11, 2));
assert(r1 - Racional(5, 7) == Racional(25, 14));
assert(r1 * 40 == 100);
assert(30 / r1 == 12);
}
#endif // TESTE
Este código já tem o respectivo teste de unidade. Faltam apenas os operadores de inserção e extracção de canais. Ver código no directório de código!