2010-09-15 6 views
2

Dire que j'ai une classe:la liste des fonctions pointeur membres

class A 
{ 
public: 
    void doSomething(); 
} 

Où doSomething fait quelque chose qui repose explicitement sur l'état interne de l'instance de A.

Maintenant, j'ai une situation où je J'ai un tas de choses de type A qui traînent, mais je ne veux appeler que quelque chose d'un sous-ensemble strict, alors je veux les coller sur la liste. En particulier, ce que je veux vraiment faire, c'est coller des pointeurs sur doSomethings() individuels dans la liste.

Puis-je le faire? Est-ce que je le déclare comme:

std::list<(A::*)()> aDoSomethings; 

je lis this entry, il est logique et je vais aller dans cette voie si je dois.

+0

Je ne comprends pas ce que vous demandez. Ou plutôt, je pense que je comprends, je ne sais pas pourquoi vous pensez que les pointeurs vers les fonctions des membres ont quelque chose à voir avec cela? D'après ce que vous décrivez, votre liste se retrouverait avec un tas de valeurs identiques. Vous devez stocker une référence à vos objets A réels d'une manière ou d'une autre, sinon votre liste ne vaudra rien. –

+0

Si je vous comprends bien, il semble que vous vouliez avoir une liste de pointeurs de fonction plutôt que des pointeurs vers des instances d'objets spécifiques. Est-ce ce que vous demandez? – linuxuser27

+1

Pouvez-vous le faire? Oui. Mais c'est sans valeur compte tenu de la situation que vous avez décrite. Toutes les instances de 'A :: doSomething' ont la même adresse. –

Répondre

2

Il semble que vous soyez confus sur le fonctionnement des pointeurs de fonction membres. Pour une classe donnée, il n'y a qu'une seule instance d'une fonction donnée. Ils sont différenciés par l'utilisation du paramètre implicite this. Fondamentalement, vous pouvez prétendre que vous avez le mappage suivant.

struct Struct { void Function(); } 
Struct a; 
a.Function(); 

se transforme en

struct Struct { } 
void Function(Struct* this); 
Struct a; 
Function(&a); 

Donc, si vous avez un tas d'objets Struct et que vous voulez appeler Function sur un petit nombre d'entre eux, vous ne stockez Function, vous stockez Struct.

Les pointeurs vers les fonctions membres sont utilisés lorsque vous avez plusieurs fonctions que vous souhaitez appeler de manière sélective. Donc, si vous avez deux fonctions dans votre classe, toutes deux ne prenant aucun paramètre et renvoyant un void, void (Struct::*)() peut pointer vers l'une ou l'autre. Mais il pointe toujours vers une fonction spécifique, dont il n'y en a qu'une seule. Vous devez toujours fournir le paramètre this.

struct Struct { 
    Struct(int v) : value(v) { } 
    void One() { cout << "one: " << value << endl; } 
    void Two() { cout << "two: " << value << endl; } 
    int value; 
}; 

int main() 
{ 
    std::vector<Struct> v; 
    v.push_back(1); 
    v.push_back(2); 
    v.push_back(3); 

    std::vector<void (Struct::*)()> f; 
    f.push_back(&Struct::One); 
    f.push_back(&Struct::Two); 
    f.push_back(&Struct::One); 

    for(int i = 0; i < 3; ++i) 
    (v[i].*f[i])(); 
} 

Ce n'est pas le meilleur exemple, mais cela fait passer le message. Vous pouvez mélanger et assortir des objets, avec des fonctions membres.

* edit: Un exemple sans conteneurs obtenir de la manière

Struct a(5), b(10); 
void (Struct::*one)() = &Struct::One; 
void (Struct::*two)() = &Struct::Two; 

(a.*one)(); 
(b.*one)(); 
(a.*two)(); 
(b.*two)(); 

Notez la parenthèse supplémentaire. a.*one() est insuffisant.

+0

C'était une excellente explication. Je suis reconnaissant pour cela. Je comprends que, de même, je pourrais appeler v [1]. * F [2]() et j'obtiendrais «deux: 1». – David

+0

@David, j'ai choisi de très mauvais noms. '(v [0]. * f [1])()' donnerait le résultat que vous attendez, mais je soupçonne que vous venez d'être troublé par mon schéma de nommage hâtif. 'v [1]' a la valeur 2, et 'f [2]' pointe vers la fonction 'One'. –

0

Oui, vous voulez probablement quelque chose comme:

#include <vector> 
#include <iostream> 
#include <string> 

using namespace std; 

class A { 
    string m_name; 

    public: 
    A(const string& name) : m_name(name) {} 
    void doSomething() { cout << m_name << "::doSomething()" << endl; } 
}; 

int main(void) { 
    A f1("f1"); 
    A f2("f2"); 
    A f3("f3"); 
    A f4("f4"); 
    vector<A*> foo_list; 
    foo_list.push_back(&f1); 
    foo_list.push_back(&f3); 

    for (vector<A*>::iterator it = foo_list.begin(); it != foo_list.end(); *it++) { 
    static_cast<A*>(*it)->doSomething(); 
    } 

    return 0; 
} 
0

Si je comprends bien, vous voulez avoir une liste de pointeurs vers des membres des fonctions qui doivent être doSomething()?

Ensuite, vous pouvez avoir une liste de pointeurs de fonction vers un membre de votre classe, mais vous devrez lui fournir l'objet associé, alors pourquoi ne pas simplement garder une liste de (pointeurs vers) les objets?

3

Avez-vous pensé simple approche OO:

struct Can_Do_Something 
{ 
    virtual void doSomething() = 0; 
}; 

class A : public Can_Do_Something 
{ 
    ... 
}; 

std::list<Can_Do_Something*> my_list; 

my_list[n]->doSomething(); 

Ceci est limitativement maintenir l'accès à la partie de l'interface A - héritée par type Can_Do_Something - que vous envisagez d'accéder via la liste. Il documente et applique cette restriction.

Si vous avez une préférence pour quelque chose de plus proche de votre vision originale, pensez à ...

#include <iostream> 
#include <vector> 
#include <boost/function.hpp> 

struct A 
{ 
    A(int n) : n_(n) { } 

    int f(int x) { std::cout << "A::f() this " << (void*)this 
          << ", n_ " << n_ 
          << ", x_ " << x << '\n'; } 

    int n_; 
}; 

int main() 
{ 
    typedef boost::function<int (int n)> Function; 
    typedef std::vector<Function> Functions; 

    Functions functions; 
    A a1(1), a2(2), a3(3); 

    functions.push_back(std::bind1st(std::mem_fun(&A::f), &a1)); 
    functions.push_back(std::bind1st(std::mem_fun(&A::f), &a2)); 
    functions.push_back(std::bind1st(std::mem_fun(&A::f), &a3)); 

    for (Functions::iterator i = functions.begin(); 
      i != functions.end(); 
      ++i) 
     (*i)(42); 
} 

Ici, boost :: fonction est utilisée pour créer un rappel aux fonctions spécifiques qui vous intéressent.

+0

Cette idée est contenue dans l'entrée que j'ai mentionnée dans la dernière phrase. – David

1

Un pointeur de fonction membre n'a pas de pointeur vers une instance particulière: il décrit comment appeler une fonction membre avec une certaine signature en fonction d'un pointeur et de paramètres this. À la place, placez des pointeurs sur les objets qui vous intéressent dans la liste, puis passez en revue cette liste en appelant doSomething sur chaque élément.

+0

J'ai supposé que 'this' était implicite dans la signature de la fonction. Il y a beaucoup de questions sur SO qui posent des questions sur les tableaux de fonctions pointeurs-membres. Je suis curieux de savoir ce qui les distingue des conteneurs STL. – David

+0

Le paramètre 'this' est implicite dans la signature. La * valeur * du paramètre ne l'est pas. Comment est-ce possible? Qu'est-ce qui distingue un tableau de pointeurs aux fonctions membres d'un conteneur de bibliothèque standard? La même chose qui distingue un tableau d'entiers d'un conteneur de bibliothèque standard. –

1

Vous devriez vérifier boost :: function et boost :: bind.

Questions connexes