Apontando uma variável para uma função de membro em C ++
É surpreendente descobrir que a maioria dos programadores C ++ têm idéia de que um ponteiro chamado esta existe. assim esta é um grande segredo! Deleite-se com ele! Qual é o segredo? O segredo é que você pode pegar o endereço da função de membro do objeto para que você possa acessar os dados da instância de função de membro diretamente. Ooh-wee!
Agora, lembre-se que cada instância de uma classe obtém sua própria cópia das variáveis de membro, a menos que as variáveis são estáticos. Mas as funções são compartilhados por toda a classe. Sim, você pode distinguir funções estáticas de funções nonstatic.
Mas isso só se refere ao que tipos de variáveis que acessam: funções estáticas podem acessar variáveis de membro única estáticos, e você não precisa se referir a eles com uma instância. Nonstatic (isto é, normal, normal) funções de membro de trabalhar com uma instância particular. No entanto, dentro da memória, realmente apenas uma cópia da função existe.
Então como é que a função de membro sabe qual instância de trabalhar? Um parâmetro segredo é passado para a função de membro: o esta ponteiro. Suponha que você tenha uma classe chamada Gobstopper que tem uma função de membro chamada Mastigar(). Em seguida, você tem uma instância chamada MyGum, e você chamar o Mastigar() função da seguinte forma:
MyGum.Chew () -
Quando o compilador gera código de montagem para isso, ele realmente passa um parâmetro para a função - o endereço do MyGum exemplo, também conhecido como o thispointer. Portanto, apenas um Mastigar() função é no código, mas chamá-lo você deve usar uma instância específica da classe.
Porque apenas uma cópia do Mastigar() função é na memória, você pode tomar seu endereço. Mas, para isso requer algum tipo de código críptico de aparência. Aqui está ele, rápido e direto ao ponto. Suponha que sua classe se parece com isso:
classe Gobstopper {public: int WhichGobstopper-int Chew (string name) {cout lt; lt; WhichGobstopper lt; lt; endl-cout lt; lt; nome lt; lt; endl-retorno WhichGobstopper -}} -
o Mastigar() função recebe uma string e retorna um inteiro. Aqui está uma typedef para um apontador para o Mastigar() função:
typedef int (Gobstopper :: * GobMember) (string) -
E aqui está uma variável do tipo GobMember:
GobMember func = Gobstopper :: Chew-
Se você olhar atentamente para a typedef, parece semelhante a um ponteiro de função regular. A única diferença é que o nome da classe e dois dois pontos precedem o asterisco. Fora isso, é um ponteiro normal função antiga.
Mas, enquanto um ponteiro de função regular é limitado a apontar para funções de um determinado conjunto de tipos de parâmetro e um tipo de retorno, esta função de ponteiro ações essas restrições, mas tem uma limitação adicional: Ele só pode apontar para funções de membro dentro da classe Gobstopper.
Para chamar a função armazenado no ponteiro, você precisa ter uma instância particular. Observe que, na atribuição de func no código anterior não havia exemplo, apenas o nome da classe e função, Gobstopper :: Chew. Assim, para chamar a função, pegar um exemplo, adicionar func, e ir!
o FunctionPointer02 exemplo mostrado contém um exemplo completo com a classe, o endereço função de membro, e duas instâncias separadas.
#incluir#incluir usando Gobstopper namespace std-classe {public: int WhichGobstopper-int Chew (string name) {cout lt; lt; WhichGobstopper lt; lt; endl-cout lt; lt; nome lt; lt; WhichGobstopper endl-retorno -}} - int main () {typedef int (Gobstopper :: * GobMember) (string) -GobMember func = Gobstopper :: Mastigue-Gobstopper inst-inst.WhichGobstopper = 10 Gobstopper outra-another.WhichGobstopper = 20- (inst * func.) ( "Greg W".) - (. * Outro func) ( "Jennifer W.") -Retornar 0-}
Você pode ver no a Principal que primeiro você criar o tipo para a função, a que chamam GobMember, em seguida, criar uma variável, func, desse tipo. Em seguida, você cria duas instâncias do Gobstopper classe, e dar-lhes cada um diferente WhichGobstopper valor.
Finalmente, você chamar a função de membro, em primeiro lugar para a primeira instância e, em seguida, para a segunda instância. Só para mostrar que você pode levar os endereços de funções com parâmetros, você passar uma cadeia com alguns nomes.
Quando você executar o código, você pode ver a partir da saída que é realmente chamando a função de membro correto para cada situação:
10Greg W.20Jennifer W.
Agora, quando você diz # 147-a função de membro correto para cada caso, # 148- o que você realmente quer dizer é que o código está chamando a mesma função de membro de cada vez, mas usando uma instância diferente. Se você está pensando em termos de orientação a objetos, considere cada instância como tendo a sua própria cópia da função de membro. Portanto, não há problema em dizer # 147-a função de membro correto para cada instância # 148.;