Departamento de Eng.
Eltrica da UFMG
renato@cpdee.ufmg.br
3- Classes em C++
.
Exemplo:
class Ponto {
private:
int x,y;
public:
void init(int,int);
void draw();
void moveto(int,int);
};
Ponto A,B;
B.init(10,20);
A.init(300,300);
A.moveto(100,100);
B.draw();
A.x; B.y; // ERRO!!!!!!!!!
OBS:
Tipos de acesso: private, public e protected
Default: private
Poltica a ser seguida: confinar as informaes de uma classe prpria
classe, acessando-as atravs de suas funes membros
encapsulamento!
Declarao de objetos da classe (A, B);
Classes membro de classes (Estrutura Todo-Parte).
Exemplo:
class Circulo{
private:
int raio;
Ponto centro;
public:
}
void Circulo :: moveto(int x1, int y1){
centro.moveto(x1,y1);
// No conseguiria acessar diretamente x e y
// de centro, pois estes so membros privados de
// Ponto
}
// Inicializa
// Adiciona n anos
// Adiciona n meses
// Adiciona n dias
// Outros mtodos
Comentrios:
Parte pblica de uma classe define a sua interface com o mundo, isto
, como ela pode ser utilizada, como seu estado pode ser modificado,
etc
Vantagens de se restringir o acesso aos membros privados: evitam-se
inicializaes e modificaes ilegais (exemplo, inicializar com
30/02/98, mudar o nmero do ms para 14) e se garante que as
operaes sejam feitas corretamente (exemplo, ao se somar n dias ao
dia atual, verifica-se se d ultrapassa o nmero mximo de dias do ms
m, fazendo-se a atualizao em d e m, simultaneamente).
Todo e qualquer mudana no estado de um objeto Date pode e deve
ser efetuada por suas funes membro
// ERRO!
// Definio
Ponto A(3,4), B;
Ponto C=A;
void f(Ponto pt);
Ponto D;
f(D);
// Adiciona n anos
// Adiciona n meses
// Adiciona n dias
// Outros mtodos
};
cada funo usaria o contedo do ponteiro this para fazer o retorno
Date& Date :: add_year(int n)
{
if (d==29 && m==2 && !leapyear (y+n)
{
// Cuida do 29/02
d = 1;
m = 3;
}
y +=n;
return *this;
}
3.1.5. Classes de armazenamento.
Objetos estticos: Um objeto pode ser declarado como esttico em
uma funo. Assim, sua durao em memria se prolonga at o
encerramento do escopo da funo em que ele uma varivel local
exatamente como variveis estticas!
Atributos estticos: servem para implementar o conceito de Atributo
de Classe. (pg 3, cap. 2), isto , deseja-se que todos os objetos de
uma determinada classe compartilhem de um certo dado. Faz-se isto
declarando um atributo de uma classe como esttico:
class Ponto{
int x, y;
static int cont;
// ....
};
Ponto Ponto_1, Ponto_2;
Ponto_1
Ponto_2
x
y
cont
x
y
cont
#include <iostream.h>
class Ponto{
int x, y;
static int cont;
public:
Ponto( ){ cont ++;}
~Ponto();
static void mostra () { cout << cont << " ";}
};
int Ponto::cont =0;
int main() {
Ponto :: mostra();
Ponto p1;
p1.mostra();
{ Ponto p2;
p2.mostra();
}
Ponto p2;
p2.mostra();
return 0;
}
Ponto :: ~Ponto () {
cout << "Destruindo Ponto numero" << cont << " ";
cont --;
}
Resultados:
0 1 2 Destruindo Ponto numero2 2 Destruindo Ponto
numero2 Destruindo Ponto numero1
Resolvendo o problema do construtor da classe Date .(pgs 6 e 7):
eliminando a varivel global:
#include <iostream>
class Date {
int d, m, y;
static Date default_date;
public:
Date( int dd=0, int mm=0, int yy=0); // default = default_date
// ....
static void set_default (int, int, int);
void show();
};
Date :: Date(int dd, int mm, int yy)
{
d = dd ? dd : default_date.d;
m = mm ? mm : default_date.m;
y = yy ? yy : default_date.y;
// OK
// erro: cd no pode ser alterado
}
Fsicamente e lgicamente constantes: atributos mutable.
Ocasionalmente, uma funo membro logicamente constante, mas
ela ainda necessita modificar o valor de um membro de um objeto.
Para o cliente a funo parece no modificar o estado do objeto,
porm algum detalhe que o cliente do objeto no observa diretamente
modificado. Isto chamado de "funo logicamente constante".
Por exemplo, a classe Date poderia possuir uma funo retornando
uma string representando a data. Construir esta representao pode ser
uma operao cara. Portanto, pode fazer sentido manter uma cpia de
forma que requisies repetidas simplesmente retornariam esta cpia,
a no ser que os valores de Date tenham sido modificados. Valores
colocados num "cache" como estes so mais comuns em estruturas de
dados mais complexas, mas pode ser adicionado em Date da forma
seguinte:
class Date{
bool cache_valid;
string cache; // string definida na biblioteca padro do C++
void compute_cache_value( );
// ...
3.3. Friends
Friends: so classes ou funes que podem acessar os membros privados
de uma outra classe!
3.3.1. Funes friends
Quando se declara uma funo como membro de uma classe, estamos
dizendo trs coisas distintas:
1. Que a funo pode acessar a parte privada da classe (a parte
pblica ela j poderia acessar sem problemas);
2. Que a funo est no escopo da classe;
3. Que a funo deve ser chamada em um objeto (tem um ponteiro
this).
Ao declarar uma funo como friend, damos a ela a primeira
propriedade apenas, isto , uma classe permite que uma funo
friend acesse seus membros privados, quando a declara dentro de
sua definio.
Sintaxe:
class Nome_da_Classe {
...
tipo_acesso :
...
friend prottipo_da_funo_friend;
};
A funo friend no pertence classe e, portanto, no tem qualquer
declarao de acesso.
a prpria classe quem indica suas funes friends.
As funes friends podem ser membros de uma outra classe ou nomembros de classes.
Funes friend no-membros de classe:
Funes genricas de manipulao de dados s quais queremos enviar
os atributos privados de uma determinada classe.
Exemplo: Uma funo que precisa acessar os atributos privados de
duas classes diferentes, precisa ser friend de ambas:
class Linha;
Caixa
Funcionario
salario
fechament
o
1
1,m
~
*=
>>
&&
[]
*
!
/=
>>=
||
()
/
=
%=
<<=
++
new
%
<
^=
==
-new[]
^
>
&=
!=
->*
delete
&
+=
|=
<=
,
delete[]
}
3.4.2. Sintaxes para a sobrecarga de operadores:
// pr-fixado
// pr-fixado
// c = a.operator+(b)
// c = operator-(a,b);
// c.operator++()
// operator--(c);
// - Unrio, pr-fixado
// - Binrio
// Erro! Ternrio
// Erro! Sem operando!
// Unrio, ps-fixado
// Unrio, pr-fixado
// Erro! % Unrio?
Uma funo definindo um operador tem que ser uma funo membro ou
receber ao menos um argumento de um tipo definido pelo programador.
Uma operador recebendo um tipo bsico como primeiro argumento no
pode ser uma funo membro.
Exemplo:
// Complexo + int
-=, *= e /=
};
Complex operator+(const Complex& a, const Complex& b)
{
Complex r = a;
return r +=b; // Acessa a representacao por +=
}
Complex operator+(double a, const Complex& b)
{
Complex r = b;
return r +=a; // Chama Complex::operator+=(double)
}
Complex operator+(const Complex& a, double b)
{
Complex r = a;
return r +=b; // Chama Complex::operator+=(double)
}
OBS: os dois operadores anteriores no so necessrios, pois atravs
do construtor de Complex pode haver converso implcita de double
para Complex!
// -, * e /
inline bool operator== (const Complex& a, const Complex& b)
{
return ( a.real( ) == b.real( ) && a.imag( ) == b.imag( ));
}
// !=
Ento:
Complex x(1,2), y(3,4), z(2,1);
Complex r1 = x+y+z; // r1=Complex+(Complex+(x,y),z)
Complex r2 = x;
r2 +=y;
// r2.operator+=(y)
r2 +=z;
// r2.operator+=(z)
double b = 3.;
r1 = b;
// r1 = Complex(b)
pf
class Cruzeiro {
double dinheiro;
public :
Cruzeiro (double valor) { dinheiro = valor; } // Float em Cruzeiro
friend Dolar :: Dolar (Cruzeiro &); // Construtor de Dolar e' friend
friend ostream& operator << (ostream&, Cruzeiro&);
};
Dolar :: Dolar (Cruzeiro & qtde) {
money = (float) qtde.dinheiro/PARALELO;
}
ostream& operator << (ostream& op, Dolar& coin) {
op << "U$ ";
op.width(10); op.precision(2);
op << coin.money << '\n';
return op;
}
ostream& operator << (ostream& op, Cruzeiro& moeda) {
op <<"R$ ";
op.width(10); op.precision(2);
op << moeda.dinheiro << '\n';
return op;
}
int main () {
Cruzeiro salario(110.00), paralelo (1.13);
Dolar usa (10.50);
cout.setf(ios::showpoint); cout.setf(ios::fixed);
cout << "1. Objeto Dolar sem Conversao : " << usa;
cout << "2. Objeto Cruzeiro sem Conversao: " << salario;
Dolar salario_dolar = salario;
cout <<"3. Conversao por Construtor: " << salario_dolar;
usa = Dolar (paralelo);
class String {
char *msg;
// ....
public:
String(int n) { msg = new char[n]; }
};
String s(10);
String r = 10;