Ponteiros de método: conceito fundamental

Novo aqui no site? Talvez gostaria de assinar o
RSS feed do site?

Publicado em: 09/09/2007
Área: C / C++
Visualizações: 1.934
Comentário(s): 1

imprimir envie por e-mail compartilhe
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:

#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 member


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:

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

Preencha o formulário para comentar:
Nome:*

E-mail:* (não será exibido)

Site: (http://)

Comentário:*

Deseja receber os comentários no e-mail?

Anti-spam: (nova imagem)





Gabriel

   - Publicado em: 05/12/2008 - 13:04

Ola eu gostei desse postutorial!!! E em C++ e ta tudo bem explicado!!! Mas ta no estagio "avançadinho"!! pra quem ta começando em C tem que pegar umas coisa mais leve,tipo: Para obter ponteiros a métodos ou funções sobrecarregadas, como exemplo: class Foo { public: void bla(int a); int bla() const; }; Se tentarmos usar o nome da função diretamente, o compilador não saberá a qual dos métodos você se refere. Para sair da ambiguidade, necessitamos usar a “assinatura” (os tipos dos parâmetros e do valor retornado) da função indiretamente, possivelmente com o uso de variáveis temporárias: void (Foo::*ptr1)(int)= &Foo::bla; int (Foo::*ptr2)() const= &Foo::bla;

 

Autor da matéria
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 solicita.

Todas as matérias de Redação Oficina da Net

Publicidade
Seguir o Oficina da Net
RSS

RSS

RSS
Top matérias do mês
Matérias relacionadas
Tags

© 2005 - 2009 - Oficina da Net - v 4.0 - É proibida a reprodução parcial ou completa do conteúdo deste site sem autorização por escrito. Resolução adequada: 1024x768px.