A apresentação está carregando. Por favor, espere

A apresentação está carregando. Por favor, espere

1. Classes 2. Membros estáticos 1.1. Palavra chave this

Apresentações semelhantes


Apresentação em tema: "1. Classes 2. Membros estáticos 1.1. Palavra chave this"— Transcrição da apresentação:

1 1. Classes 2. Membros estáticos 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

2 1.1. Palavra chave this A palavra this é definida dentro de um objecto como sendo um ponteiro para o próprio objecto. 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.

3 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:

4 str1 str2 Memória this é impossível mudar do valor do ponteiro this;
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 Memória é impossível mudar do valor do ponteiro this; é impossível utilizar o endereço do ponteiro this.

5 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

6 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 A.set(10,20); A.display(); // O resultado 10 20 A.f(B).display(); // O resultado }

7 Vamos analisar a seguinte linha:
my_class *const this; 1. this aponta para o início da memória do computador onde o objecto está localizado. 2. O ponteiro this é uma variável local no corpo da função pertencente à classe, por isso não pode ser acedido fora do corpo da 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 para todas as funções pertencentes à classe dum determinado objecto, que não sejam do tipo static.

8 Utilização do ponteiro "this" para
criar uma lista ligada

9 Este ponteiro é bastante útil quando se usam ponteiros e especialmente, no uso de listas ligadas duplas quando se quer 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*); // ... }; list_head this z p prev next next

10 void dlink::append(dlink* p)
{ p->next=next; // equivalente a p->next=this->next p->prev=this; // uso explícito de this next->prev=p; // equivalente a this->next->prev=p next=p; // equivalente a this->next=p } next prev p prev next this z p prev next this z p prev next next

11 void dlink::append(dlink* p)
{ p->next=next; // equivalente a p->next=this->next p->prev=this; // uso explícito de this next->prev=p; // equivalente a this->next->prev=p next=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 lista list_head->append(b); // introdução do elemento b na lista this z p prev next next

12 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.

13 erro class X; class Y { public: void f1(X* x); void f2(X* 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 Z { int j; public: Z() { X x; j = x.i; }; void g(X* x) { x->i = j; }; }; void Y::f2(X* x) { x->i = 33; } erro void h() { X x; x.i = 100; //acesso a membro privado } void Y::f1(X* x) { x->i = 22; }

14 class my_class2; // declaração forward
{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"; }

15 Uma classe que esteja definida dentro de outra (i. e
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. class englobante { int a; public: class aninhada; //declaração antecipada da classe aninhada friend class aninhada; //declaração de amiga class aninhada // definição da classe aninhada { }; }; Exemplo:

16 Ponteiros inteligentes
Pointer GoodArray 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.

17 classe aninhada int read(); //aceder ao elemento corrente do array
const int sz = 5; class GoodArray { int a[sz]; public: GoodArray (); class Pointer; friend class Pointer; class Pointer GoodArray* h; int* p; Pointer(GoodArray* rv); void next(); // passa para o elemento seguinte void previous(); // passa para o elemento anterior void top(); // passa para o primeiro elemento do array void end(); // passa para o último elemento do array int read(); //aceder ao elemento corrente do array void 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 seguinte void previous(); // passa para o elemento anterior void top(); // passa para o primeiro elemento do array void end(); // passa para o último elemento do array int read(); //aceder ao elemento corrente do array void set(int i); //modificar o elemento corrente do array } classe aninhada

18 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)); } 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--;

19 pointer 1 = 0, pointer 2 = 4 pointer 1 = 1, pointer 2 = 3
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 = 4 pointer 1 = 1, pointer 2 = 3 pointer 1 = 2, pointer 2 = 2 pointer 1 = 3, pointer 2 = 1 pointer 1 = 4, pointer 2 = 0

20 Duas propriedades de funções e classes amigas, é a de amizade não
poder ser herdada nem transitiva. Se uma classe é derivada de outra, esta classe não mantém as propriedades de amizade para com as funçõ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; X() { i = 0; }; friend class Z; classe Z é amiga da classe X OK class DZ : public Z { public: DZ ():Z () { X x; }; x.i; }; }; erro classe DZ não é amiga da classe X!

21 A amizade não é transitiva. X Z Y
amiga amiga A amizade não é transitiva. X Z Y não é amiga classe Y é amiga da classe Z class Z { int j; public: Z() { X x; j = x.i; }; friend class Y; }; OK class Y { public: Y () { X x; x.i; }; }; erro classe Y não é amiga da classe X! class X { int i; public: X() { i = 0; }; friend class Z; }; classe Z é amiga da classe X

22 1.3. Palavra chave const constantes (para eliminar #define) objectos
ponteiros argumentos de funções tipos de retorno das funções em classes

23 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)

24 Objectos int main(int argc, char* argv[]) {
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... A O codigo ASCII da letra A e 65

25 Ponteiros objecto constante ponteiro
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 = objecto constante ponteiro char c1 = 'a', c2 = 'b'; char* const letra = &c1; letra = &c2; //erro *letra = 'c'; *letra = c2;

26 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 É possível atribuir a um ponteiro constante o endereço de um objecto não constante. char c1 = 'a'; const char* const s = &c1; É impossível atribuir a um ponteiro não constante o endereço de um objecto constante. const char c1 = 'a'; char* s = &c1; // erro


Carregar ppt "1. Classes 2. Membros estáticos 1.1. Palavra chave this"

Apresentações semelhantes


Anúncios Google