8
votes

Puis-je lancer std :: vecteur to std :: vecteur sans regarder chaque élément?

J'ai une classe de base avec plusieurs classes en prolongant. J'ai des utilitaires de bibliothèque génériques qui créent un vecteur contenant des pointeurs sur la classe de base afin que l'une des sous-classes fonctionnera. Comment puis-je lancer tous les éléments du vecteur à une classe enfant spécifique? XXX PRE>

Ma solution naïve ressemblerait à ceci: P>

// A method is called that assumes that a vector containing
// Dogs casted to Animal is passed.
void myDogCallback(vector<Animal*> &animals) {
    // I want to cast all of the elements of animals to
    // be dogs.
    vector<Dog*> dogs;
    vector<Animal*>::iterator iter;
    for ( iter = animals.begin(); iter != animals.end(); ++iter ) {
        dogs.push_back(dynamic_cast<Dog*>(*iter));
    }
}


4 commentaires

Duplicaté: Stackoverflow.com/questions/902667/ ...


Ce n'est pas tout à fait dupe - Notez qu'il ne copie pas de vecteur à vecteur , mais l'inverse!


Je suppose qu'il cherche un ajout automatique / implicite!


Merci pour les commentaires. :) Je ne savais pas comment demander cela et oui, j'ai eu du mal à savoir quoi chercher!


7 Réponses :


0
votes

Votre code comme écrit mettra un tas de pointeurs nuls dans votre vecteur de chiens lorsque le vecteur d'animaux contient d'autres spécialisations animales. xxx


0 commentaires

0
votes

Il n'est généralement pas très bon d'utiliser dynamic_cast pour la sous-emploi. Vous devez probablement refroidir votre code afin que vous n'ayez pas besoin d'utiliser la radiographie explicite.

voir FAQ CPP Lite pour plus d'autres informations.

upd aussi, voir STROSTRUP Page (recherche de "Pourquoi ne puis-je pas affecter un vecteur à un vecteur?")


0 commentaires

12
votes

Vous pouvez utiliser std :: transformer . Il utilise toujours pour () en interne, mais vous obtiendrez une implémentation de deux chaînes: xxx


1 commentaires

Ceci est toujours "en regardant chaque élément", le flux est juste arrangé différemment.



0
votes

Il y a deux options. Le plus simple consiste à utiliser quelque chose comme supprimer_copy_if code>. Je ne peux pas expliquer pourquoi ils l'appellent cela, mais il copie les éléments d'un conteneur à un autre que ne répond pas au prédicat. Voici l'idée de base (non testée): xxx pré>

} p>

Je suppose un moyen de regarder supprimer_copy_if code> est à penser comme copy_unless code>. p>

une approche alternative, si vous baseez votre code autour des itérateurs uniquement, est d'envelopper l'itérateur de vecteur avec celui qui ne renvoie que les chiens de la collection. L'avantage clé ici est que vous n'avez toujours qu'un seul conteneur, mais bien sûr, vous payez un peu plus que votre algorithme naviguera sur toute la collection d'animaux. P>

class dog_iterator  // derive from std::iterator probably with bidirectinoal tag
{
private:
  vector<Animals*>::iterator getNextDogIter (vector<Animals*>::iterator iter) {
    while (iter != m_end) {
      if (0 != dynamic_cast<Dog*> (*iter)) {
        break;
      }
      ++iter;
    }
    return iter;
  }

public:
  dog_iterator (vector<Animals*>::iterator iter, vector<Animals*>::iterator end)
  : m_end (end)
  , m_iter (getNextDogIter (iter))
  {
  }

  // ... all of the usual iterator functions

  dog_iterator & operator++ ()
  {
    // check if m_iter already is at end - otherwise:
    m_iter = getNextDogIter (m_iter + 1);
    return *this;
  }
  // ...
};


0 commentaires

0
votes

Si vous dites que vous pouvez garantir que chaque élément est vraiment un chien, alors static_cast code> IE

void myDogCallback(vector<Animal*> &animals) {

    const vector<Animal*>::size_type numAnimals = animals.size();

    vector<Dog*> dogs;
    dogs.reserve( numAnimals );

    for ( vector<Animal*>::size_type i = 0; i < numAnimals; ++i ) {
        dogs.push_back(static_cast<Dog*>( animals[i] ));
    }
}


0 commentaires


0
votes

Mélange de la méthodologie std :: transformation code> avec un static_cast code> (car vous êtes certain de sa sécurité) pourrait ressembler à:

std::transform(animals.begin(), animals.end(),
               std::back_insert_iterator<std::vector<Dog*>>(dogs),
               [](auto ptr) { return static_cast<Dog*>(ptr); });


0 commentaires