2010-02-03 5 views
3

modèles Je pense que je ne peux pas implémenter le conteneur de base sur un modèle de classe, ce qui nécessiterait alors un algorithme de traversée basé sur des classes de modèles qui ne sont pas connues à l'avance. Le conteneur de base peut être hérité et implémenté en utilisant n'importe quel type de conteneur (personnalisé ou standard) à l'intérieur. Voici quelques exemples de code pour le rendre clair:Utilisation d'Iterators pour masquer le conteneur interne et effectuer un fonctionnement générique sur un conteneur de base

struct MyObject { 
    int myInt; 
} 

// an abstract container 
class BaseContainer { 
public: 
    virtual void insertMyObject(MyObject& obj) = 0; 
    virtual iterator getFirst(); // the iterator type is for demonstration purposes only 
    virtual iterator getLast(); // the iterator type is for demonstration purposes only 
} 

// Sample container class that uses a std::vector instance to manage objects 
class BaseContainer_Vector : public BaseContainer { 
public: 
    void insertMyObject(MyObject& obj); // e.g. just pushes back to the vector 
    iterator getFirst(); // needs to override the iterator? 
    iterator getLast(); // needs to override the iterator? 
private: 
    std::vector<MyObject> objectContainer; 
} 

Je vais donc avoir une liste d'objets de conteneurs, et je veux itérer sur ces deux conteneurs et les objets stockés.

std::vector<MyContainer*> containers; 
for(int i=0 ; i<containers.size() ; i++){ 
    iterator i = containers[i]->getFirst(); 
    iterator iend = containers[i]->getLast(); 
    for(; i != iend ; i++) { 
    std::cout << (*i).myInt << std::endl; 
    } 
} 

Je tiens en outre d'avoir un soutien pour la déclaration macro boost foreach. Il prend en charge les extensions tant que les fonctions range_begin et range_end sont correctes. Mais, l'exemple dans boost doc utilise std :: string :: iterator comme type de retour, alors que ce dont j'ai besoin est une classe d'itérateur générique et je n'ai pas encore trouvé comment faire cela.

std::vector<MyContainer*> containers; 
for(int i=0 ; i<containers.size() ; i++){ 
    BOOST_FOREACH(MyObject obj, *(containers[i])) { 
    std::cout << obj.myInt << std::endl; 
    } 
} 

Je pense que je peux définir ma propre classe itérateur, chaque classe qui étend BaseContainer devrait définir leur propre iterator étendre cette iterator de base. Pourtant, je préférerais utiliser des itérateurs standards (stl ou boost) pour supporter cette structure, plutôt que d'écrire mes propres itérateurs. Je suppose que cette approche fonctionnera, mais je suis ouvert aux commentaires concernant son efficacité.

Y a-t-il une approche réalisable qui peut résoudre ce problème avec élégance? Ou est-ce que je manque un point simple qui peut résoudre ce problème sans douleur?

Une question similaire peut être trouvée here, mais les solutions proposées semblent un peu complexes pour mes besoins, et les exigences diffèrent autant que je peux comprendre.

+1

Quel est le cas d'utilisation réel auquel vous faites face?Avez-vous vraiment besoin de deux versions dynamiquement sélectionnées du conteneur ou pouvez-vous le pousser pour compiler l'heure? –

+0

Je ne sais pas si ça va bien fonctionner avec STL et boost. Ceux-ci supposent généralement que les itérateurs sont des types de valeurs simples; Si vous utilisez des conceptions polymorphes, les types de valeur ne seront pas utilisables. – visitor

+0

La bibliothèque que je développe devra permettre aux utilisateurs de définir leurs propres conteneurs et de les enregistrer dans le système. Le système itère sur tous les conteneurs enregistrés et les traite, ce que j'ai montré un exemple de code qui utilise boost. Le système est également responsable d'insérer automatiquement les types MyObject dans ce conteneur. Je souhaite que l'utilisateur puisse étendre cette classe de conteneur afin qu'il puisse appliquer l'ordre qu'il souhaite sur la structure qu'il utilise pour gérer ces objets insérés. – AdilYalcin

Répondre

1

Ça va être compliqué.

Comme nous l'avons déjà dit, vous devez d'abord avoir une valeur sémantique pour vos itérateurs car, étant donné qu'ils sont généralement copiés, cela entraînerait un découpage d'objet.

class BaseContainer 
{ 
protected: 
    class BaseIteratorImpl; // Abstract class, for the interface 

public: 
    class iterator 
    { 
    public: 
    iterator(const BaseIteratorImpl& impl); 
    private: 
    BaseIteratorImpl* m_impl; 
    }; 

    iterator begin(); 
    iterator end(); 
}; // BaseContainer 

Ensuite, BaseIterator avant toutes les méthodes à m_impl. De cette façon, vous obtenez une syntaxe sémantique de valeur avec un noyau polymorphe.

De toute évidence, vous devrez gérer la sémantique de copie en profondeur et la destruction appropriée.

Quelques notes:

  • publier à la fois un iterator et une const_iterator classe
  • nom de vos méthodes empty, size, begin, end etc ... pour la compatibilité avec les algorithmes STL

Vous pouvez vérifier SGI Iterators pour obtenir de l'aide sur les Concepts et les opérations que vos opérateurs doivent prendre en charge pour une compatibilité maximale.

+0

Merci pour la réponse, je vais maintenant essayer d'implémenter un itérateur personnalisé en fonction de votre approche. L'utilisateur devra éventuellement définir des opérations d'incrément, de début et de fin personnalisées pour le (s) conteneur (s) utilisé (s) en interne. Je vais rapporter sur les résultats bientôt :) :) – AdilYalcin

+0

J'ai hérité de la classe d'itérateur publique que vous avez proposée de std :: itérateur , et ainsi pourrais le faire fonctionner aussi avec BOOST_FOREACH :) Merci d'avoir choisi dans la bonne direction, cela fonctionne comme je le voulais, avec un minimum de surcharge de code :) – AdilYalcin

+0

C'est toujours un plaisir d'aider les gens avec des problèmes intéressants ... ou au moins les problèmes qui m'intéressent :) –

Questions connexes