1. classes 1.1. palavra chave this 1.2. palavra chave friend 1.3. palavra chave const 2. membros...

26
1. Classes 1.1. Palavra chave this 1.2. Palavra chave friend 1.3. Palavra chave const 2. Membros estáticos 2.1. Dados estáticos 2.2. Funções estáticas

Upload: internet

Post on 17-Apr-2015

105 views

Category:

Documents


1 download

TRANSCRIPT

Page 1: 1. Classes 1.1. Palavra chave this 1.2. Palavra chave friend 1.3. Palavra chave const 2. Membros estáticos 2.1. Dados estáticos 2.2. Funções estáticas

1. Classes1.1. Palavra chave this1.2. Palavra chave friend1.3. Palavra chave const

2. Membros estáticos2.1. Dados estáticos2.2. Funções estáticas

Page 2: 1. Classes 1.1. Palavra chave this 1.2. Palavra chave friend 1.3. Palavra chave const 2. Membros estáticos 2.1. Dados estáticos 2.2. Funções estáticas

A palavra this é definida dentro de um objecto como sendo umponteiro para o próprio objecto.

1.1. Palavra chave this

Objecto

this

Se uma função (por exemplo, set_string) for o método de uma classe (por exemplo, string) então podemos usar nesta função os nomes dos dados e das funções. Não é necessário usar o nome da

classe, i.e., podemos escrever só o nome dos seus dados. Consideremos um exemplo.

Page 3: 1. Classes 1.1. Palavra chave this 1.2. Palavra chave friend 1.3. Palavra chave const 2. Membros estáticos 2.1. Dados estáticos 2.2. Funções estáticas

Vamos examinar as seguintes declarações: string str1; string str2;

e invocamos as funções:str1.display_string();str2.display_string();

Suponhamos que as duas funções realizam a seguinte instrução:cout << str<<endl;

Como é que a primeira função sabe que deve usar o dado str pertencente ao objecto str1 e a segunda função sabe que

deve usar o atributo str pertencente ao objecto str2?

Cada objecto (no nosso exemplo eles são str1 e str2) tem um ponteiro escondido que o identifica. Outras possíveis

explicações são as seguintes:

Page 4: 1. Classes 1.1. Palavra chave this 1.2. Palavra chave friend 1.3. Palavra chave const 2. Membros estáticos 2.1. Dados estáticos 2.2. Funções estáticas

Quando declaramos um novo objecto o compilador reserva a memória necessária e chama o construtor para esta zona da memória.

Esta memória tem um campo especial que indica o início da área reservada para o objecto. O valor deste ponteiro pode ser obtido através da palavra chave this. Cada função (não estática) que pertence à classe recebe este ponteiro como um argumento adicional escondido. O ponteiro para as funções não constantes é do seguinte tipo:

my_class *const this;

str1

this

str2

this

Memória

é impossível mudar do valor do ponteiro this; é impossível utilizar o endereço do ponteiro this.

Page 5: 1. Classes 1.1. Palavra chave this 1.2. Palavra chave friend 1.3. Palavra chave const 2. Membros estáticos 2.1. Dados estáticos 2.2. Funções estáticas

Na maioria dos casos o ponteiro this é utilizado de maneira implícita.

void string::display_string(){

cout << str << endl; }

void string::display_string(){

cout << this->str << endl; }

void string::f(){

int a;this = &a;&this;

}

impossível

Page 6: 1. Classes 1.1. Palavra chave this 1.2. Palavra chave friend 1.3. Palavra chave const 2. Membros estáticos 2.1. Dados estáticos 2.2. Funções estáticas

class my_class{ int x,y;public:

void set (int X, int Y) { x=X; y=Y; }my_class f (my_class);my_class* ff (void) { x = y = 100; return this; }void display () { cout << x << ‘\t’ << y << endl; }

};my_class my_class::f(my_class M){ x += M.x; y += M.y;

return *this; }void main(void){ my_class A,B;

B.ff()->display(); // O resultado 100 100A.set(10,20);A.display(); // O resultado 10 20A.f(B).display(); // O resultado 110 120

}

Page 7: 1. Classes 1.1. Palavra chave this 1.2. Palavra chave friend 1.3. Palavra chave const 2. Membros estáticos 2.1. Dados estáticos 2.2. Funções estáticas

Vamos analisar a seguinte linha: my_class *const this;

1. this aponta para o início da memória do computador ondeo objecto está localizado.2. O ponteiro this é uma variável local no corpo da funçãopertencente à classe, por isso não pode ser acedido fora do corpoda função.3. Como this é declarado como *const não pode ser alterado,mas o objecto por ele apontado pode.4. O ponteiro this não necessita de ser declarado. 5. O ponteiro this é passado como um argumento escondido paratodas as funções pertencentes à classe dum determinado objecto,que não sejam do tipo static.

Page 8: 1. Classes 1.1. Palavra chave this 1.2. Palavra chave friend 1.3. Palavra chave const 2. Membros estáticos 2.1. Dados estáticos 2.2. Funções estáticas
Page 9: 1. Classes 1.1. Palavra chave this 1.2. Palavra chave friend 1.3. Palavra chave const 2. Membros estáticos 2.1. Dados estáticos 2.2. Funções estáticas

Este ponteiro é bastante útil quando se usam ponteiros e especialmente, no uso de listas ligadas duplas quando sequer referenciar um ponteiro para o objecto que se quer

introduzir na lista

class dlink { dlink* prev; // elemento anterior dlink* next; // elemento seguinte

public:void append(dlink*);// ...

};

next

list_head

this z

p

prevnext

prev

nextnext prevprev

Page 10: 1. Classes 1.1. Palavra chave this 1.2. Palavra chave friend 1.3. Palavra chave const 2. Membros estáticos 2.1. Dados estáticos 2.2. Funções estáticas

void dlink::append(dlink* p){ p->next=next; // equivalente a p->next=this->next

p->prev=this; // uso explícito de thisnext->prev=p; // equivalente a this->next->prev=pnext=p; // equivalente a this->next=p

}

this z

p

prevnext

prev

nextnext prevprev

next

p nextprev

next

prevthis z

p

prevnext

prev

nextnext prevprev

Page 11: 1. Classes 1.1. Palavra chave this 1.2. Palavra chave friend 1.3. Palavra chave const 2. Membros estáticos 2.1. Dados estáticos 2.2. Funções estáticas

void dlink::append(dlink* p){ p->next=next; // equivalente a p->next=this->next

p->prev=this; // uso explícito de thisnext->prev=p; // equivalente a this->next->prev=pnext=p; // equivalente a this->next=p

}

dlink* list_head; // Início da lista

void f(dlink* a, dlink* b){ // ...

list_head->append(a); // introdução do elemento a na listalist_head->append(b); // introdução do elemento b na lista

}

this z

p

prevnext

prev

nextnext prevprev

next

Page 12: 1. Classes 1.1. Palavra chave this 1.2. Palavra chave friend 1.3. Palavra chave const 2. Membros estáticos 2.1. Dados estáticos 2.2. Funções estáticas

1.2. Palavra chave friend

Todos os membros privados de uma classe são inacessíveis do exterior. Se quiser que uma função (não membro) tenha acesso aos membros privados de uma classe, terá que declarar esta função como amiga (friend).

A declaração de amizade deve ocorrer dentro da declaração da classe.

As amigas de uma classe podem ser funções globais, funções membros de uma outra classe ou uma outra classe inteira (i.e. todas as funções membros dela serão amigas).

A declaração de funções friend é feita dentro da classe e começa com a palavra chave friend. Esta declaração pode ser feita tanto na parte private coma na parte public da declaração de uma classe.

Uma função global do tipo friend obviamente não tem o ponteiro this.

Page 13: 1. Classes 1.1. Palavra chave this 1.2. Palavra chave friend 1.3. Palavra chave const 2. Membros estáticos 2.1. Dados estáticos 2.2. Funções estáticas

void Y::f1(X* x){

x->i = 22; }

class X {

int i; public:

X() { i = 0; }; friend void Y::f1(X*); // função f1 da Y é amiga friend class Z; // toda a classe é amiga friend void h(); // função global é amiga

};

class X;class Y { public:

void f1(X* x);void f2(X* x);

};

class Z {

int j;public:

Z() { X x; j = x.i; };void g(X* x) { x->i = j; };

};

void h() {

X x;x.i = 100; //acesso a membro privado

}

void Y::f2(X* x){

x->i = 33; }

erro

Page 14: 1. Classes 1.1. Palavra chave this 1.2. Palavra chave friend 1.3. Palavra chave const 2. Membros estáticos 2.1. Dados estáticos 2.2. Funções estáticas

class my_class2; // declaração forwardclass my_class1 {public:

friend void compare(my_class1&, my_class2&);my_class1(int A) : a(A) {}// .......................................

private: int a; };

class my_class2 {public:

friend void compare(my_class1&, my_class2&);my_class2(int A): a(A) {}// .......................................

private: int a; };

void compare(my_class1 &cl1, my_class2 &cl2){ if(cl1.a==cl2.a) cout << "equal\n";

else cout << " not equal\n"; }

Page 15: 1. Classes 1.1. Palavra chave this 1.2. Palavra chave friend 1.3. Palavra chave const 2. Membros estáticos 2.1. Dados estáticos 2.2. Funções estáticas

class englobante{ int a;public:

class aninhada; //declaração antecipada da classe aninhadafriend class aninhada; //declaração de amigaclass aninhada // definição da classe aninhada

{ ........................ };};

Uma classe que esteja definida dentro de outra (i.e. uma classe aninhada), não consegue ter acesso à informação que está na parte

private da classe englobante. Muito fácilmente se consegue este acesso através da declaração de friend da classe aninhada na

classe englobante.

Exemplo:

Page 16: 1. Classes 1.1. Palavra chave this 1.2. Palavra chave friend 1.3. Palavra chave const 2. Membros estáticos 2.1. Dados estáticos 2.2. Funções estáticas

As classe GoodArray e Pointer são fortemente relacionados => é razoável fazer com que Pointer seja uma classe aninhada dentro de GoodArray.

Dado que Pointer é uma classe separada é possível criar muitos ponteiros e utilizá-los para seleccionar elementos diferentes do array.

Dado que Pointer é uma classe (não apenas um ponteiro simples) é possível garantir que esta nunca ultrapasse os limites do array e vai sempre apontar para um elemento válido.

Ponteiros inteligentes

GoodArray Pointer

Page 17: 1. Classes 1.1. Palavra chave this 1.2. Palavra chave friend 1.3. Palavra chave const 2. Membros estáticos 2.1. Dados estáticos 2.2. Funções estáticas

const int sz = 5;class GoodArray {

int a[sz];public:

GoodArray ();class Pointer;friend class Pointer;class Pointer {

GoodArray* h;int* p;

public:Pointer(GoodArray* rv);

void next(); // passa para o elemento seguintevoid previous(); // passa para o elemento anteriorvoid top(); // passa para o primeiro elemento do arrayvoid end(); // passa para o último elemento do array

int read(); //aceder ao elemento corrente do arrayvoid set(int i); //modificar o elemento corrente do array

};};

class Pointer;friend class Pointer;class Pointer {

GoodArray* h;int* p;

public:Pointer(GoodArray* rv);

void next(); // passa para o elemento seguintevoid previous(); // passa para o elemento anteriorvoid top(); // passa para o primeiro elemento do arrayvoid end(); // passa para o último elemento do array

int read(); //aceder ao elemento corrente do arrayvoid set(int i); //modificar o elemento corrente do array

}

classeaninhada

Page 18: 1. Classes 1.1. Palavra chave this 1.2. Palavra chave friend 1.3. Palavra chave const 2. Membros estáticos 2.1. Dados estáticos 2.2. Funções estáticas

GoodArray::Pointer::Pointer(GoodArray* rv) {

h = rv;p = rv->a;

}

void GoodArray::Pointer::next() {

if(p < &(h->a[sz - 1])) p++;

}

void GoodArray::Pointer::previous() {

if(p > &(h->a[0])) p--;

}

void GoodArray::Pointer::top() {

p = &(h->a[0]);}

void GoodArray::Pointer::end() {

p = &(h->a[sz - 1]);}

int GoodArray::Pointer::read() {

return *p;}

void GoodArray::Pointer::set(int i) {

*p = i;}

GoodArray::GoodArray() {

memset(a, 0, sz * sizeof(int));}

Page 19: 1. Classes 1.1. Palavra chave this 1.2. Palavra chave friend 1.3. Palavra chave const 2. Membros estáticos 2.1. Dados estáticos 2.2. Funções estáticas

int main(int argc, char* argv[]){

GoodArray array;GoodArray::Pointer p1(&array), p2(&array);

for(int i = 0; i < sz; i++) {

p1.set(i); p1.next();}p1.top(); p2.end();

for(i = 0; i < sz; i++) {

cout << "pointer 1 = " << p1.read() << ", pointer 2 = " << p2.read() << endl;p1.next();p2.previous();

}

return 0;}

pointer 1 = 0, pointer 2 = 4pointer 1 = 1, pointer 2 = 3pointer 1 = 2, pointer 2 = 2pointer 1 = 3, pointer 2 = 1pointer 1 = 4, pointer 2 = 0

Page 20: 1. Classes 1.1. Palavra chave this 1.2. Palavra chave friend 1.3. Palavra chave const 2. Membros estáticos 2.1. Dados estáticos 2.2. Funções estáticas

Duas propriedades de funções e classes amigas, é a de amizade nãopoder ser herdada nem transitiva. Se uma classe é derivada de outra,

esta classe não mantém as propriedades de amizade para com asfunções que a classe da qual foi derivada mantinha, i.e.

não há herança de amizade.

class Z { int j;public: Z() { X x; j = x.i; };};

class X { int i; public: X() { i = 0; }; friend class Z; };

classe Z éamiga daclasse X

OK

class DZ : public Z{public: DZ ():Z () { X x; }; x.i; };};

erro

classe DZ não é amiga da classe X!

Page 21: 1. Classes 1.1. Palavra chave this 1.2. Palavra chave friend 1.3. Palavra chave const 2. Membros estáticos 2.1. Dados estáticos 2.2. Funções estáticas

class Z { int j;public: Z() { X x; j = x.i; }; friend class Y;};

class X { int i; public: X() { i = 0; }; friend class Z; };

classe Z éamiga daclasse X

OK class Y{public: Y () { X x; x.i; };};

erro

classe Y não é amiga da classe X!

classe Y éamiga daclasse Z

X Z Y

amiga amiga

não é amiga

A amizade não é transitiva.

Page 22: 1. Classes 1.1. Palavra chave this 1.2. Palavra chave friend 1.3. Palavra chave const 2. Membros estáticos 2.1. Dados estáticos 2.2. Funções estáticas

1.3. Palavra chave const

constantes (para eliminar #define)

objectos

ponteiros

argumentos de funções

tipos de retorno das funções

em classes

Page 23: 1. Classes 1.1. Palavra chave this 1.2. Palavra chave friend 1.3. Palavra chave const 2. Membros estáticos 2.1. Dados estáticos 2.2. Funções estáticas

Constantes (para eliminar #define)

#define NUM_ALUNOS 150

(pre-processador, não há informação sobre tipos, não há endereço)

const int num_alunos = 150;

(compilador, há informação sobre tipos, pode-se obter o endereço)

Page 24: 1. Classes 1.1. Palavra chave this 1.2. Palavra chave friend 1.3. Palavra chave const 2. Membros estáticos 2.1. Dados estáticos 2.2. Funções estáticas

Objectos

Se tiver um objecto cujo valor não se pretende alterar durante o tempo de vida deste objecto, é melhor declarar o objecto como constante.

int main(int argc, char* argv[]){

cout << "Introduza uma letra..." << endl;const int a = cin.get();cout << "O codigo ASCII da letra " << char(a) << " e "<< a << endl;return 0;

}

Introduza uma letra...AO codigo ASCII da letra A e 65

Page 25: 1. Classes 1.1. Palavra chave this 1.2. Palavra chave friend 1.3. Palavra chave const 2. Membros estáticos 2.1. Dados estáticos 2.2. Funções estáticas

Ponteiros

const pode ser aplicado ou a ponteiro (i.e. ao endereço que o ponteiro guarda) ou a objecto para o qual o ponteiro aponta.

char c1 = 'a', c2 = 'b';const char* letra = &c1;

letra = &c2;*letra = 'c'; //erro*letra = c2; //erro

char c1 = 'a', c2 = 'b';char const* letra = &c1;

letra = &c2;*letra = 'c'; //erro*letra = c2; //erro

=

char c1 = 'a', c2 = 'b';char* const letra = &c1;

letra = &c2; //erro*letra = 'c';*letra = c2;

objecto constante

ponteiro constante

Page 26: 1. Classes 1.1. Palavra chave this 1.2. Palavra chave friend 1.3. Palavra chave const 2. Membros estáticos 2.1. Dados estáticos 2.2. Funções estáticas

Ponteiros

É possível fazer com que ambas as partes sejam constantes, i.e. o ponteiro (o endereço que o ponteiro guarda) e o objecto para o qual o ponteiro aponta.

char c1 = 'a', c2 = 'b';const char* const letra = &c1;

letra = &c2; //erro

*letra = c2; //erro

É impossível atribuir a um ponteiro não constante o endereço de um objecto constante.

const char c1 = 'a';char* s = &c1; // erro

É possível atribuir a um ponteiro constante o endereço de um objecto não constante.

char c1 = 'a';const char* const s = &c1;