Ponteiros de método: conceito fundamental
Diferente de ponteiros de função (funções globais ou estáticas) - que são a grosso modo ponteiros como qualquer um - os ponteiros de método possuem uma semântica toda especial que costuma intimidar at...
Publicado em: 9 de setembro de 2007 | Leituras: 4.639 |
Canal: C / C++ |
Autor: Redação Oficina da Net
Diferente de ponteiros de função (funções globais ou estáticas) - que são a grosso modo ponteiros como qualquer um - os ponteiros de método possuem uma semântica toda especial que costuma intimidar até quem está acostumado com a aritmética de ponteiros avançada. Não é pra menos. É praticamente uma definição à parte, com algumas limitações e que deixa a desejar os quase sempre criativos programadores da linguagem, que vira e mexe estão pedindo mudanças no C++0x.
Três regras iniciais que devem ser consideradas para usarmos ponteiros para métodos são:
* A semântica para lidar com ponteiros de método é totalmente diferente de ponteiros de função.
* Ponteiros de método de classes distintas nunca se misturam.
* Para chamarmos um ponteiro de método precisamos sempre de um objeto da classe para a qual ele aponta.
Visto isso, passemos a um exemplo simples, um chamador de métodos aleatórios, que ilustra o princípio básico de utilização:
Como podemos ver, para o typedef de ponteiros de método é necessário especificar o escopo da classe. Com isso, o compilador já sabe que só poderá aceitar endereços de métodos pertencentes à mesma classe com o mesmo protótipo.
Na hora de atribuir, usamos o operador de endereço e o nome do método (com escopo, se estivermos fora da classe). É importante notar que, diferente de ponteiros de função, o operador de endereço é obrigatório. Do contrário:
E, por fim, a chamada. Como é a chamada de um método, é quase intuitiva a necessidade de um objeto para chamá-la. Do contrário não teríamos um this para alterar o objeto em qualquer método não estático, certo? Daí a necessidade do padrão C++ especificar dois operadores especialistas para esse fim, construídos a partir da combinação de operadores já existentes em C:
Esses operadores obrigam o programador a sempre ter um objeto e um ponteiro. Daí não tem como errar. Infelizmente, devido à ordem de precedência, temos que colocar os parênteses em torno da expressão para chamar o método. Pelo menos fica equivalente ao que precisávamos fazer antes da padronização da linguagem C.
Fonte: http://www.cbrasil.org
Três regras iniciais que devem ser consideradas para usarmos ponteiros para métodos são:
* A semântica para lidar com ponteiros de método é totalmente diferente de ponteiros de função.
* Ponteiros de método de classes distintas nunca se misturam.
* Para chamarmos um ponteiro de método precisamos sempre de um objeto da classe para a qual ele aponta.
Visto isso, passemos a um exemplo simples, um chamador de métodos aleatórios, que ilustra o princípio básico de utilização:
#include <windows.h>
#include <iostream>
#include <time.h>
using namespace std;
// declaramos que existe uma classe com esse nome
class FuzzyCall;
// ponteiro para métodos da classe acima
typedef void (FuzzyCall::*FP_Fuzzy)();
/** Classe que faz chama um método aleatório. */
class FuzzyCall
{
public:
FuzzyCall()
{
srand(GetTickCount()); // chacoalha o saco de bingo
}
FP_Fuzzy GiveMeAMethod() { return m_methods[rand() % 3]; }
private:
void MethodOne() { cout << "One!n"; }
void MethodTwo() { cout << "Two!n"; }
void MethodThree() { cout << "Three!n"; }
static FP_Fuzzy m_methods[3];
};
/** Array com os métodos que podem ser chamados aleatoriamente. */
FP_Fuzzy FuzzyCall::m_methods[3] = { &MethodOne, &MethodTwo, &MethodThree };
/** Recebe um ponteiro para um método de FuzzyCall e chama com um objeto local. */
void passThrough(FP_Fuzzy pMethod)
{
FuzzyCall fuzzyObject; // esse é o objeto local
( fuzzyObject.*pMethod )(); // essa é a chamada
}
/** No princípio Deus disse: 'int main!'
*/
int main()
{
FuzzyCall fuzzyObject1;
FP_Fuzzy pMethod;
// pegamos um método da classe qualquer
pMethod = fuzzyObject1.GiveMeAMethod();
// e passamos para uma outra função
passThrough(pMethod);
}Como podemos ver, para o typedef de ponteiros de método é necessário especificar o escopo da classe. Com isso, o compilador já sabe que só poderá aceitar endereços de métodos pertencentes à mesma classe com o mesmo protótipo.
Na hora de atribuir, usamos o operador de endereço e o nome do método (com escopo, se estivermos fora da classe). É importante notar que, diferente de ponteiros de função, o operador de endereço é obrigatório. Do contrário:
error C4867: 'FuzzyCall::MethodOne': function call missing argument list;
use '&FuzzyCall::MethodOne' to create a pointer to memberE, por fim, a chamada. Como é a chamada de um método, é quase intuitiva a necessidade de um objeto para chamá-la. Do contrário não teríamos um this para alterar o objeto em qualquer método não estático, certo? Daí a necessidade do padrão C++ especificar dois operadores especialistas para esse fim, construídos a partir da combinação de operadores já existentes em C:
FuzzyCall fuzzyObject; // esse é o objeto local
FuzzyCall* pFuzzy = &fuzzyObject; // ponteiro para esse mesmo objeto
( fuzzyObject.*pMethod )(); // [objeto] .* [ponteiro de método]
( fuzzyObject->*pMethod )(); // [ponteiro para objeto] ->* [ponteiro de método]Esses operadores obrigam o programador a sempre ter um objeto e um ponteiro. Daí não tem como errar. Infelizmente, devido à ordem de precedência, temos que colocar os parênteses em torno da expressão para chamar o método. Pelo menos fica equivalente ao que precisávamos fazer antes da padronização da linguagem C.
Fonte: http://www.cbrasil.org
Resposta em até 24 horas! (grátis)Dúvidas?
Autor da matéria
Últimas matérias escritas pelo autor:
|
Redação Oficina da Net A Redação do Oficina da Net é composta por todos os integrantes da equipe do portal. Estamos abertos a indicações de matérias, entre em contato conosco solicitando sua dúvida, ou acesse nosso fórum. |
Últimas matérias escritas pelo autor:
30/08 - Dicas de segurança para smartphones co...
27/08 - Eleições: redes sociais dão mostras de...
23/08 - 5 dicas para aumentar a proteção no e-...
12/08 - Web Analytics - Só números não bastam
09/08 - Google Android OS
09/08 - Business Intelligence: é estratégia ou...
06/08 - Os desafios de recursos humanos nas em...
05/08 - Neutralidade da rede o que é?
02/08 - Nota Fiscal Eletrônica: cumpra a lei e...
29/07 - Saiba como ter segurança na internet d...
26/07 - Cloud Computing redesenha modelo de ne...
26/07 - O sucesso depende de manter foco?
07/07 - Usabilidade de interfaces para EAD
07/07 - Dicas para deixar o Firefox mais rápid...
27/08 - Eleições: redes sociais dão mostras de...
23/08 - 5 dicas para aumentar a proteção no e-...
12/08 - Web Analytics - Só números não bastam
09/08 - Google Android OS
09/08 - Business Intelligence: é estratégia ou...
06/08 - Os desafios de recursos humanos nas em...
05/08 - Neutralidade da rede o que é?
02/08 - Nota Fiscal Eletrônica: cumpra a lei e...
29/07 - Saiba como ter segurança na internet d...
26/07 - Cloud Computing redesenha modelo de ne...
26/07 - O sucesso depende de manter foco?
07/07 - Usabilidade de interfaces para EAD
07/07 - Dicas para deixar o Firefox mais rápid...
Últimas matérias







O que você procura para sua vida profissional?
O planejamento agrega valor
E-mail marketing em 140 caracteres
Novos iPods, novo iOS, novo iTunes e nova Apple TV
Conheça as 100 primeiras cidades atendidas pelo Banda Larga ...
Linus Torvalds diz que mercado já se rendeu ao Linux