2015-04-07 5 views
13

Questo sembra un problema piuttosto semplice, ma non riesco a capirlo. Ho un std::vector di puntatori grezzi su oggetti derivati, e voglio solo copiarlo su un altro vettore di puntatori Base usando l'operatore di assegnazione. Con VC++ ottengo l'errore C2679 "binary '=': nessun operatore trovato ..." BTW Non voglio una copia profonda degli oggetti, voglio solo copiare i puntatori. Esempio di codice:Provare ad assegnare il vettore di Base * dal vettore di Derivato *

#include <vector> 
using namespace std; 

struct Base{};  
struct Derived: public Base {}; 

int main (int argc, char* argv[]) 
{ 
    vector<Derived*> V1; 
    vector<Base*> V2; 
    V2 = V1; //Compiler error here 
    return 0; 
} 

Ciò che mi confonde è che posso copiare il vettore da loop attraverso di essa e utilizzando push_back, in questo modo:

for (Derived* p_derived : V1) 
    V2.push_back(p_derived); 

Quindi la mia domanda è: perché non l'assegnazione fallire, mentre push_back lavori? Sembra la stessa cosa per me.

risposta

19

Ecco perché, mentre Base e Derived hanno un rapporto, non v'è alcuna relazione tra vector<Base*> e vector<Derived*>. Per quanto riguarda la gerarchia di classi, sono completamente estranei, quindi non è possibile assegnarne uno all'altro.

Il concetto che stai cercando si chiama covariance. Ad esempio, in Java, String[] è un sottotipo di Object[]. Ma in C++, questi due tipi sono solo diversi tipi e non sono più correlati di String[] e Bar.

push_back opere perché questo metodo accetta solo un T const& (o T&&), quindi tutto convertibili in Base* sarà accettabile - che un Derived* è.

Detto, vector ha un costruttore che prende una coppia di iteratori, che dovrebbe essere più facile da usare qui:

vector<Base*> v2(v1.begin(), v1.end()); 

Oppure, poiché è già costruito:

v2.assign(v1.begin(), v1.end()); 
+0

Suppongo che l'operatore di assegnazione diventerebbe troppo complicato se dovesse accettare vettori di tipi diversi, ma legati. – Carlton

+1

Questa è una (piuttosto comune) FAQ C++ pure. Vedi [questo] (https://isocpp.org/wiki/faq/containers#container-ptr-conversion). – edmz

+0

In C# 'Elenco ' non è correlato a 'Elenco ' ma 'IEnumerable ' è un sottotipo di 'IEnumerable ' perché 'IEnumerable' è variante. – usr

9

push_back esegue conversioni element-wise. L'operatore di assegnazione esiste solo tra vettori dello stesso tipo.

Una soluzione semplice è quella di utilizzare assign:

v2.assign(v1.begin(), v1.end()); 
2

Nel caso generale di modelli, se si dispone di un modello di classe

template <typename T> struct Foo {}; 

Foo<Base> non è una classe base di Foo<Derived>.

Quindi, non si può fare:

Foo<Derived> f1; 
Foo<Base> f2 = f1;