2010-04-26 25 views
1

Supposons que l'on me donne une classe A. Je voudrais envelopper les pointeurs dans une petite classe B, une sorte de pointeur intelligent, avec la contrainte qu'un B* est automatiquement converti en A* de sorte que je n'ai pas besoin de réécrire le code qui utilise déjà A*.Conversion automatique d'un A * en B *

Je voudrais donc modifier B afin que les compiles suivants ...

struct A { 
    void foo() {} 
}; 

template <class K> 
struct B { 
    B(K* k) : _k(k) {} 
    //operator K*() {return _k;} 
    //K* operator->() {return _k;} 
private: 
    K* _k; 
}; 

void doSomething(A*) {} 

void test() { 
    A a; 
    A* pointer_to_a (&a); 
    B<A> b (pointer_to_a); 
    //b->foo();    // I don't need those two... 
    //doSomething(b); 

    B<A>* pointer_to_b (&b); 

    // Following represents existing code I don't want to change... 
    pointer_to_b->foo();  // 'foo' : is not a member of 'B<K>' 
    doSomething(pointer_to_b); // 'doSomething' : cannot convert parameter 1 from 'B<K> *' to 'A *' 
} 

Notez que B héritant de A n'est pas une option (cas de A sont créés dans les usines hors de mon contrôle). ..

Est-ce possible?

Merci.

+2

Avez-vous pensé pointeur intelligent existant implémentations, comme 'auto_ptr' ou' shared_ptr'? – Amber

+0

La conversion en 'A *' n'est pas la seule responsabilité que je veux de 'B': elle doit en particulier hériter des autres classes. Et je devrais changer le code actuellement en utilisant 'A *', n'est-ce pas? –

+0

Alors, pourquoi vos opérateurs sont-ils commentés? – AnT

Répondre

3

Le type de pointeur_to_b est pointeur à B, qui est un type que vous ne pouvez pas modifier; c'est implémenté par le compilateur.

Vous pouvez faire (* pointer_to_b) -> foo(), ce qui fera l'affaire (en supposant que vous avez l'opérateur surchargé ->()). Cependant, cela ne laissera pas l'autre code faire la bonne chose, si vous y passez pointer_to_be. Permettez-moi également d'ajouter que vous pouvez remplacer l'opérateur & sur B pour retourner un A *, ce qui pourrait résoudre votre problème, en fonction des cas d'utilisation spécifiques.

+0

Je ne voudrais pas avoir à mettre à jour tout le code existant ... :( –

+0

Ma suggestion ne vous oblige pas à mettre à jour tout le code, si c'est OK pour l'opérateur et sur B pour retourner un A * –

2

Qu'en est-il de la fonction get() comme dans boost::shared_ptr?

template <class K> 
struct B { 
    B(K* k) : _k(k) {} 
    K* get() { return _k;} 
private: 
    K* _k; 
}; 

Ensuite, vous pouvez l'utiliser comme suit:

pointer_to_b->get()->foo();  
doSomething(pointer_to_b->get()); 
+0

Je voudrais encore pour changer le code existant ... –

+0

Oui, mais à mon humble avis, il sera clair –

0

Les opérateurs que vous avez des commentaires dans votre struct B regarder comme ils devraient le faire faire ce que vous voulez ... pourquoi sont-ils en commentaire? Cela ne fonctionne-t-il pas lorsqu'ils ne sont pas commentés, et si non, pouvez-vous publier les erreurs?

+0

Ajout de ces opérateurs permet les deux conversions que j'ai commenté parce que je n'ai pas besoin d'eux.Nommer ces opérateurs ne change pas les erreurs qui apparaissent sur le deux dernières lignes. –

0

Si je me souviens de la façon dont shared_ptr contourne le problème, je pense que vous avez est que vous ne passez jamais un shared_ptr*, vous passez un objet shared_ptr. De cette façon, le operator-> fonctionne parce qu'il est appelé sur l'objet, pas le pointeur sur l'objet. Je recommande que vous passiez autour de B<A> au lieu de B<A>*. Qui se soucie de savoir si la classe wrapper est un pointeur ou non, tant qu'elle représente un pointeur sur A cela ne devrait pas avoir d'importance.

0

B héritant de A est une option, cette compile (VS 2008 au moins):

struct A { 
    void foo() {} 
}; 

template <typename T> 
struct B : T 
{ 
    B(const T& t) : T(t) 
    {} 
}; 

void doSomething(A*) {} 

void test() { 
    A a; 
    B<A> b (a); 

    B<A>* pointer_to_b (&b); 

    // Following represents existing code I don't want to change... 
    pointer_to_b->foo();  
    doSomething(pointer_to_b); 
} 
0

Cela devrait fonctionner de mon point de vue

struct A { 
    void foo() {} 
}; 

template <class K> 
struct B { 
    B(K* k) : _k(k) {} 
    operator K*() {return _k;} 
    K* operator->() {return _k;} 
private: 
    K* _k; 
}; 

void doSomething(A*) {} 

void test() { 
    A a; 
    A* pointer_to_a (&a); 
    B<A> pointer_to_b (pointer_to_a); 

    // Following represents existing code NOT CHANGED 
    pointer_to_b->foo();  
    doSomething(pointer_to_b); 

}