2010-04-30 14 views
2

J'ai clairement été coincé dans la terre de Java depuis trop longtemps ... Est-il possible de faire l'équivalent C++ du code Java suivant:C++ Liste générique Attribution

interface Foo {} 

class Bar implements Foo {} 

static List<Foo> getFoo() { 
    return new LinkedList<Foo>(); 
} 

static List<Bar> getBar() { 
    return new LinkedList<Bar>(); 
} 

List<? extends Foo> stuff = getBar(); 

Où Foo est une sous-classe de Bar.

Donc, en C++ ....

std::list<Bar> * getBars() 
{ 
    std::list<Bar> * bars = new std::list<Bar>; 
    return bars; 
} 

std::list<Foo> * stuff = getBars(); 

espoir qui fait sens ....

+1

Etes-vous sûr que cela fonctionne en Java? Parce que je viens de vérifier, et ce n'est pas parce que Java ne supporte pas les génériques covariants. De plus, cela n'aurait de sens que si 'Bar' était une sous-classe de' Foo'. –

+0

Correct. Mon erreur. J'ai maintenant corrigé l'extrait de code. – S73417H

Répondre

3

Non à mon avis cela n'a pas de sens en C++.

D'abord, vous renvoyez une référence qui n'existe plus. Pour éviter cela, vous pouvez passer votre std :: liste en tant que paramètre de référence à modifier dans la fonction, comme

void fillFoos(std::list<Foo> & foos) 

Deuxièmement, foos ne sont pas des barres et ne peuvent pas être copiés un à l'autre, sauf que je pense si vous fournissez le bon opérateur de copie. Mais si vous utilisez l'héritage, tous vos foos et barres devraient être des pointeurs (et si vous pouvez les intelligents en tant que pointeurs shared_ptr de boost ou tr1). Mais cela ne signifie pas que la copie fonctionne.

Je ne suis pas vraiment sûr de ce que vous voulez faire, mais la transposition de JAVA en C++ dans ce cas ne fonctionne pas. Si vous créez des foos, ils auront tout de barres automatiquement.

std::list<Foo> foos; // just work fine 

Si vous voulez une liste de barres construites comme foos:

std::list< Bar * > bars; 
bars.push_back(new Foo()); 

Ou comme je le mettrais en vrai code C++ avec shared_ptr:

typedef boost::shared_ptr<Bar>; 
typedef boost::shared_ptr<Foo>; 
typedef std::list<BarPtr> BarList; 

BarList bars; 

bars.push_back(FooPtr(new Foo())); 
1

tout va bien, sauf vous revenez référence à la variable locale. il est maintenu en pile et sera libéré après le retour de la fonction.

+0

Eh bien, je suis perdu. J'ai juste essayé son Java et est le code C++, et ne fonctionne pas. Aucune des deux langues n'a de génériques/modèles covariants, alors comment cela est-il supposé fonctionner?! –

+0

@ Space_C0wb0y - Je viens de réaliser qu'il a Foo et Boo ... cela ne devrait pas fonctionner, vous avez raison – Andrey

2

vous avez besoin de l'objet pour soutenir les constructeurs pour ces opérations, vous ne devriez pas retourner un refernce plutôt un objet droit qui sera copié, sinon retourne un pointeur-à-dire:

std::list<Bar> getBars() 
{ 
    std::list<Bar> Bars; 
    return Bars; 
} 

ou

std::list<Bar>* getBars() 
{ 
    return new std::list<Bar>(); 
} 

std :: liste prend en charge la copie des objets d'une autre liste, mais seulement si cette liste est du même type, à savoir: vous ne pouvez pas copier de std::list<Bar> à std::list<Foo> implicitement, mais vous pouvez copier std::list<Foo> à 0.123..

+0

Comment feriez-vous cela? – Snake

+0

Soyez averti que cela entraînera presque certainement une fuite de mémoire. –

+0

oui, si vous ne le faites pas attention, mieux vaut l'envelopper dans un pointeur intelligent/partagé, donc il se supprime automatiquement quand il n'est plus utilisé – Necrolis

4

changement

std::list<Bar> & getBars() 

à

std::list<Bar> getBars() 

Cette volonté en retour principe en valeur, mais il y a mécanisme éludant construction de copie, afin d'optimiser les compilateurs devraient être optimiser en mesure

std::list<Bar> bars (getBars()); 

à ne pas impliquer le constructeur de copie et juste construire directement bars.

De plus, en C++ 0x il y a un constructeur de déplacement, donc le code ci-dessus est efficace même si le copier/déplacer n'est pas éliminé pour une raison quelconque.

EDIT pour la question sous-classe manqué:

En général, ce n'est pas possible de le faire proprement en C++ (je suppose que Foo est un superclasse de Bar, sinon ce que vous faites peu de sens) . C'est probablement possible avec de la magie noire, mais je vous déconseille vivement.

approximation la plus proche est probablement ce (avec getBars() ajusté en conséquence):

std::list <Bar*> bars (getBars()); 
std::list <Foo*> foos (bars.begin(), bars.end()); 

Cependant, ce qui impose une certaine charge de la gestion de la mémoire non trivial sur vous. L'utilisation d'un certain type de pointeurs automatiques peut aider, mais pour autant que je me souvienne, seulement shared_ptr peut être utilisé dans des conteneurs.

Enfin, Foo/Bar la hiérarchie de classe devrait utiliser des fonctions virtuelles, sinon ce que vous voulez faire ne fonctionnera presque certainement pas (c.-à-d.sauf si vous voulez vraiment ignorer les remplacements dans la sous-classe).

+0

-1 parce que vous ne répondez pas à la question des auteurs pour une assignation covariante ' std :: liste 'à' std :: liste '. –

+0

@ Space_C0wb0y: Droit, j'ai raté la question.L'édition le couvre, bien qu'il ne fournisse pas de réponse directe. – doublep

+0

Suppression du downvote. Cependant, je me demande encore pourquoi personne ne voit que cela ne fonctionne même pas en Java. –

0

De plus, la nouvelle liste std :: list retournera un pointeur, pas une référence.

2

Soit je reçois quelque chose totalement faux ici, ou votre Java-Code ne fonctionne pas. J'ai juste essayé. Ça ne marche pas. La raison en est, que les conteneurs génériques en Java are not covariant (cela signifie, il ne fonctionne pas non plus si Bar est une sous-classe de Foo). Deuxièmement, si Foo est une sous-classe de Bar, alors vous pouvez assigner Foo références à Bar, mais pas l'inverse (ni en Java ni en C++).

Les conteneurs en C++ ne sont pas non plus covariants. Mais vous pouvez faire

std::list<Foo*> FooList; 
// fill FooList; 
std::list<Bar*> BarList(FooList.begin(), FooList.end()); 

si Foo est une sous-classe de Bar. Cela aura cependant pour effet que tous les pointeurs de FooList sont copiés dans BarList. Cela signifie que si vous modifiez FooList par la suite en ajoutant ou en supprimant des éléments, ces modifications ne seront pas reflétées dans .