Question

Considérez ces classes.

class Base
{
   ...
};

class Derived : public Base
{
   ...
};

cette fonction

void BaseFoo( std::vector<Base*>vec )
{
    ...
}

Et enfin mon vecteur

std::vector<Derived*>derived;

Je souhaite transmettre dérivé à la fonction BaseFoo , mais le compilateur ne me le permet pas. Comment résoudre ce problème sans copier l'intégralité du vecteur dans un std :: vector < Base * > ?

Était-ce utile?

La solution

vecteur < Base * > et vecteur < Derived * > ne sont pas liés, vous ne pouvez donc pas le faire. Ceci est expliqué dans la FAQ C ++ ici . .

Vous devez modifier votre variable de vecteur & Derrière * > à un vecteur > et insérer des objets Derived . en elle.

De plus, pour éviter de copier inutilement le vecteur , vous devez le passer par référence const et non par valeur:

void BaseFoo( const std::vector<Base*>& vec )
{
    ...
}

Enfin, pour éviter les fuites de mémoire et sécuriser votre code, envisagez d’utiliser un conteneur conçu pour gérer les objets alloués au tas, par exemple:

#include <boost/ptr_container/ptr_vector.hpp>
boost::ptr_vector<Base> vec;

Vous pouvez également modifier le vecteur afin qu'il contienne un pointeur intelligent au lieu d'utiliser des pointeurs bruts:

#include <memory>
std::vector< std::shared_ptr<Base*> > vec;

ou

#include <boost/shared_ptr.hpp>
std::vector< boost::shared_ptr<Base*> > vec;

Dans tous les cas, vous devrez modifier votre fonction BaseFoo en conséquence.

Autres conseils

Au lieu de transmettre l'objet conteneur ( vector < > ), transmettez les itérateurs begin et end comme le reste des algorithmes STL. . La fonction qui les reçoit sera modélisée et peu importe si vous passez à Derived * ou Base *.

Ce problème se produit dans les langages de programmation comportant des conteneurs mutables. Vous ne pouvez pas faire passer un sac de pommes mutable comme un sac de fruits, car vous ne pouvez pas être sûr que quelqu'un d'autre ne mette pas de citron dans ce sac de fruits, après quoi il ne sera plus considéré comme un sac de pommes. Si le sac de pommes ne pouvait pas être modifié, le faire passer comme un sac de fruits serait bien. Recherche de covariance / contravariance.

une option consiste à utiliser un modèle

template<typename T>
void BaseFoo( const std::vector<T*>& vec)
{
 ...
}

L'inconvénient est que l'implémentation doit être dans l'en-tête et vous obtiendrez un peu de code. Vous allez vous retrouver avec différentes fonctions instanciées pour chaque type, mais le code reste le même. Selon le cas d'utilisation, c'est une solution rapide et délicate.

Modifier, je dois noter que la raison pour laquelle nous avons besoin d’un modèle est que nous essayons d’écrire le même code pour les types non liés, comme indiqué par plusieurs autres affiches. Les modèles vous permettent de résoudre ces problèmes. Je l'ai également mis à jour pour utiliser une référence const. Vous devez également passer " heavy " des objets comme un vecteur par référence const lorsque vous n’avez pas besoin d’une copie, ce qui est toujours le cas.

Généralement, vous commenceriez avec un conteneur de pointeurs de base, et non l'inverse.

Prise de La réponse de Matt Price ci-dessus, étant donné que vous savez à l'avance les types que vous souhaitez utiliser avec votre fonction, vous pouvez déclarer le modèle de fonction dans le fichier d'en-tête, puis ajouter des instanciations explicites pour ces types:

// BaseFoo.h
template<typename T>
void BaseFoo( const std::vector<T*>& vec);

// BaseFoo.cpp
template<typename T>
void BaseFoo( const std::vector<T*>& vec);
{
 ...
}

// Explicit instantiation means no need for definition in the header file.
template void BaseFoo<Base> ( const std::vector<Base*>& vec );
template void BaseFoo<Derived> ( const std::vector<Derived*>& vec );

Si vous utilisez une bibliothèque tierce et que ceci est votre seul espoir, vous pouvez le faire:

BaseFoo (*reinterpret_cast<std::vector<Base *> *>(&derived));

Sinon, corrigez votre code avec l'une des autres suggestions.

Si std :: vector supportait ce que vous demandiez, il serait alors possible de vaincre le système de types C ++ sans recourir à des conversions (edit: le lien de ChrisN vers la FAQ C ++ Lite parle de le même problème):

class Base {};
class Derived1 : public Base {};
class Derived2 : public Base {};

void pushStuff(std::vector<Base*>& vec) {
    vec.push_back(new Derived2);
    vec.push_back(new Base);
}

...
std::vector<Derived1*> vec;
pushStuff(vec); // Not legal
// Now vec contains a Derived2 and a Base!

Etant donné que votre fonction BaseFoo () prend le vecteur par valeur, elle ne peut pas modifier le vecteur d'origine que vous avez transmis. Par conséquent, ce que j'ai écrit ne serait pas possible. Mais si cela prend une référence non-const et que vous utilisez reinterpret_cast < std :: vector < Base * > > () pour transmettre votre std :: vector < Derived * * > ; , vous risquez de ne pas obtenir le résultat souhaité et votre programme risque de planter.

Les baies Java prennent en charge le sous-typage covariant , ce qui nécessite Java pour effectue une vérification du type à l'exécution à chaque fois que vous stockez une valeur dans un tableau . Cela aussi est indésirable.

Ce sont des types non liés - vous ne pouvez pas.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top