Question

J'ai un code similaire à celui-ci dans mon application:

class A
{
  public: int b;
}

class C
{
  public: int d;
}

void DoThings (void *arg1, MYSTERYTYPE arg2);

A obj_a;
C obj_c;

DoThings(&obj_a, &A::b);
DoThings(&obj_c, &C::d);

La question est la suivante: que doit être MYSTERYTYPE? ni void * ni int travail, malgré la valeur & amp; A :: b étant correctement imprimé si vous le sortez par un printf.

Clarifications: Oui, & amp; A :: b est défini sous C ++. Oui, j'essaie de compenser un membre du groupe. Oui, je suis délicate.

Éditer: Oh, je peux utiliser offsetof (). Merci quand même.

Était-ce utile?

La solution

Vous avez un pointeur de membre de données sur deux classes non apparentées. Eh bien, vous ne pouvez pas trouver un type commun pouvant contenir les deux pointeurs. Cela fonctionnera uniquement si le paramètre de fonction est un pointeur de membre de données vers un membre du dérivé, car il est garanti qu'il contiendra également le membre, si une base le contient:

struct a { int c; }; struct b : a { }; int main() { int b::*d = &a::c; }

Mise à jour : je pense que je devrais écrire pourquoi le texte ci-dessus est converti de a::* à b::* de manière implicite. Après tout, nous devons généralement b* à a*! Considérez:

struct a { };
struct b : a { int c; };
struct e : a { };
int main() { int a::*d = &b::c; e e_; (e_.*d) = 10; /* oops! */ }

Si ce qui précède est valable, vous risquez vraiment de vous tromper. Ce qui précède n’est pas , car la conversion de e à b n’est pas implicite. Comme vous le voyez, nous avons assigné un pointeur à b :: c, puis nous pourrions le déréférencer en utilisant une classe qui ne le contient pas du tout! (a). Le compilateur applique cette commande:

int main() { int b::*d = &b::c; e e_; (e_.*d) = 10; /* bug! */ }

La compilation échoue , car <=> n'est pas dérivé de <=>, la classe à laquelle appartient le pointeur de membre. Bien! Ce qui suit est cependant très valide et compile bien sûr (classes modifiées <=> et <=>):

struct a { int c; };
struct b : a { };
struct e : a { };
int main() { int e::*d = &a::c; e e_; (e_.*d) = 10; /* works! */ }

Pour que cela fonctionne dans votre cas, vous devez faire de votre fonction un modèle:

template<typename Class>
void DoThings (int Class::*arg) { /* do something with arg... */ }

Maintenant, le compilateur déduira automatiquement la bonne classe à laquelle appartient le pointeur de membre donné. Vous devrez passer l'instance à côté du pointeur membre pour pouvoir l'utiliser:

template<typename Class>
void DoThings (Class & t, int Class::*arg) { 
    /* do something with arg... */ 
    (t.*arg) = 10;
}

Si vous souhaitez simplement définir un membre que vous connaissez déjà au moment où vous écrivez DoThings, les éléments suivants suffisent:

template<typename Class>
void DoThings (Class & t) {  
    t.c = 10;
}

Autres conseils

Essayez-vous simplement d'appeler une fonction avec l'adresse d'un entier qui vit dans un objet A ou C? Dans ce cas, la réponse de Jeff McGlynn est la voie à suivre.

Autrement, si vous essayez vraiment de faire quelque chose de délicat nécessitant le système de pointeur sur membre étrange de C ++ (et vous ne l'êtes certainement pas):

Étant donné que les classes <=> et <=> ne sont pas liées, vous aurez besoin d'une fonction de modèle pour gérer les deux:

template <typename T>
void DoThings(int T::*x);

Si <=> était réellement dérivé de <=>, les éléments suivants fonctionneraient:

void DoThings(int A::*x);

& amp; A :: b et & amp; C :: d sont insensés, il n'y a pas d'adresse associée. Essayez-vous d'obtenir le décalage du membre?

Êtes-vous sûr de ne pas vouloir quelque chose comme ce qui suit?

DoSomething(&obj_a,&obj_a.b);

Si vous utilisez des modèles comme le suggère j_random_hacker et que le compilateur connaisse le type de chaque classe à l'endroit où vous appelez la fonction, la réponse littérale à votre question est & "; template <typename CLASS> void DoThings (CLASS * object, int CLASS::*MEMBER) &".

Voici comment cela s'insérerait dans votre exemple:

#include <iostream>

class A {
public: 
    int b;
};

class C {
public: 
    int d;
};

template <typename CLASS>
void DoThings (CLASS * object, int CLASS::*MEMBER)
{
    std::cout << object->*MEMBER << std::endl;
}

A obj_a = { 2 };
C obj_c = { 4 };

int main (int argc, const char * argv[])
{
    DoThings(&obj_a, &A::b);
    DoThings(&obj_c, &C::d);
    return 0;
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top