Domanda

Considera queste classi.

class Base
{
   ...
};

class Derived : public Base
{
   ...
};

questa funzione

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

E infine il mio vettore

std::vector<Derived*>derived;

Voglio passare derivato per funzionare BaseFoo , ma il compilatore non me lo permette. Come posso risolvere questo problema, senza copiare l'intero vettore in un std :: vector < Base * > ?

È stato utile?

Soluzione

vector < Base * > e vector < Derived * > sono tipi non correlati, quindi non puoi farlo. Questo è spiegato nelle FAQ C ++ qui .

Devi cambiare la tua variabile da un vettore < Derivato * > in un vettore < Base * > e inserire oggetti Derivati ?? in esso.

Inoltre, per evitare di copiare inutilmente il vettore , dovresti passarlo per riferimento costante, non per valore:

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

Infine, per evitare perdite di memoria e rendere il tuo codice sicuro dalle eccezioni, considera l'utilizzo di un contenitore progettato per gestire oggetti allocati in heap, ad esempio:

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

In alternativa, modifica il vettore per contenere un puntatore intelligente invece di utilizzare i puntatori non elaborati:

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

o

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

In ogni caso, dovrai modificare di conseguenza la tua funzione BaseFoo .

Altri suggerimenti

Invece di passare l'oggetto contenitore ( vector < > ), passa gli iteratori inizio e fine come il resto degli algoritmi STL . La funzione che li riceve sarà modellata e non importa se passi in Derivato * o Base *.

Questo problema si verifica nei linguaggi di programmazione che hanno contenitori mutabili. Non puoi passare un sacco di mele mutevole come un sacchetto di frutta perché non puoi essere sicuro che qualcun altro non metta un limone in quel sacchetto di frutta, dopodiché non si qualifica più come un sacchetto di mele. Se il sacco di mele non fosse mutevole, passarlo in giro come un sacco di frutta andrebbe bene. Cerca covarianza / contraddizione.

un'opzione è usare un modello

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

Lo svantaggio è che l'implementazione deve essere nell'intestazione e otterrai un po 'di codice in eccesso. Si finirà con l'istanza di diverse funzioni per ciascun tipo, ma il codice rimane lo stesso. A seconda del caso d'uso è una soluzione rapida e sporca.

Modifica, dovrei notare che il motivo per cui abbiamo bisogno di un modello qui è perché stiamo provando a scrivere lo stesso codice per tipi non correlati, come notato da molti altri poster. I modelli consentono di risolvere questi problemi esatti. L'ho anche aggiornato per usare un riferimento const. Dovresti anche passare "pesante". oggetti come un vettore per riferimento const quando non hai bisogno di una copia, che è praticamente sempre.

Generalmente inizieresti con un contenitore di puntatori di base, non viceversa.

Scattare La risposta di Matt Price dall'alto, dato che sai in anticipo quali tipi vuoi usare con la tua funzione, puoi dichiarare il modello di funzione nel file di intestazione e quindi aggiungere istanze esplicite per quei tipi:

// 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 );

Se hai a che fare con una biblioteca di terze parti e questa è la tua unica speranza, puoi farlo:

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

Altrimenti correggi il tuo codice con uno degli altri suggerimenti.

Se std :: vector supporta ciò che stai chiedendo, allora sarebbe possibile sconfiggere il sistema di tipo C ++ senza usare alcun cast (modifica: il link di ChrisN alla FAQ ++ di C ++ parla di lo stesso problema):

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!

Poiché la tua funzione BaseFoo () accetta il vettore in base al valore, non può modificare il vettore originale che hai passato, quindi ciò che ho scritto non sarebbe possibile. Ma se prende un riferimento non const e usi reinterpret_cast < std :: vector < Base * > & amp; > () per passare il tuo std :: vector < Derived * > ; , potresti non ottenere il risultato desiderato e il tuo programma potrebbe bloccarsi.

Le matrici Java supportano sottotipizzazione covariante e questo richiede Java per esegui un controllo del tipo di runtime ogni volta che memorizzi un valore in un array . Anche questo è indesiderabile.

Sono tipi non correlati - non puoi.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top