2016-07-07 36 views
5

Non riesco a risolvere questo problema. Diciamo che ho questo vettoreConversione da shared_ptr a weak_ptr polymorphism

std::vector<std::shared_ptr<Car>> cars; 

Car è una classe astratta. Voglio essere in grado di restituire puntatori deboli di tipi diversi, quindi faccio quanto segue.

template<typename T> 
    std::weak_ptr<T> GetCar() 
    { 
     for (std::vector<std::shared_ptr<Car>>::iterator it = cars.begin(); it != cars.end(); ++it) 
     { 
      T* derived = dynamic_cast<T*>((*it).get()); 
      if (derived != nullptr) 
      { 
       std::weak_ptr<T> carPointer = *it; 
       return carPointer; 
      } 
     } 
     return std::weak_ptr<T>(); 
    } 

Viene visualizzato il seguente errore quando si tenta di utilizzare la funzione con una classe che eredita da Car. Error C2440 'initializing': cannot convert from 'std::shared_ptr<Car>' to 'std::weak_ptr<Saab>' Potrebbe non esserci una macchina valida quando richiesto. Ho provato a usare boost :: facoltativo ma non gestisce il polimorfismo. Potrei andare con i puntatori grezzi se non riesco a farlo funzionare.

+1

Il tipo puntato da 'shared_ptr' e' weak_ptr' deve essere lo stesso. Lo farei in tre passaggi: restituire un 'weak_ptr ' e convertirlo in un 'shared_ptr ', quindi in un 'T *'. –

+0

Grazie per la risposta rapida @MarkRansom Mmm. Questo è per una funzione utente di una libreria, quindi preferirei non dare allo sviluppatore che potrebbe usarlo più lavoro. Avrei dovuto dirlo, mio ​​male. Consiglieresti di lavorare solo con i puntatori grezzi in modo da poterne restituire uno? Oppure restituire derivato pari, – miniconco

+0

Puoi certamente avere una singola funzione che esegue tutti e tre i passaggi, ma lo scopo di convertire un 'weak_ptr' in un' shared_ptr' è di mantenere vivo l'oggetto mentre stai lavorando con esso; mettere il 'shared_ptr' in una sconfitta temporanea a tale scopo. –

risposta

5

Non si può costruire direttamente il vostro weak_ptr<Saab> dalla shared_ptr<Car> perché il parametro di template Car deve essere convertibile in modo implicito Saab per lavorare.

Ma in primo luogo è possibile convertire il numero shared_ptr<Car> in shared_ptr<Saab>, quindi creare il numero weak_ptr in seguito. Nel mio esempio qui sotto, ho usato il std::dynamic_pointer_cast per farlo.

Ecco quello che mi si avvicinò con:

#include <iostream> 
#include <vector> 
#include <memory> 

struct Car 
{ 
    virtual void name() = 0; 
}; 

struct Saab : Car 
{ 
    virtual void name() { std::cout << "Saab" << std::endl; } 
}; 

struct Renault : Car 
{ 
    virtual void name() { std::cout << "Renault" << std::endl; } 
}; 

template<typename T> 
std::weak_ptr<T> GetCar(std::vector<std::shared_ptr<Car>> cars) 
{ 
    for (std::vector<std::shared_ptr<Car>>::iterator it = cars.begin(); it != cars.end(); ++it) 
    { 
     auto derived = std::dynamic_pointer_cast<T>(*it); 
     if (derived != nullptr) 
     { 
      std::weak_ptr<T> carPointer(derived); 
      return carPointer; 
     } 
    } 
    return std::weak_ptr<T>(); 
} 

int main() 
{ 
    std::vector<std::shared_ptr<Car>> cars; 
    cars.push_back(std::make_shared<Saab>()); 
    cars.push_back(std::make_shared<Renault>()); 

    auto wp = GetCar<Saab>(cars); 

    auto sp = wp.lock(); 
    if (sp) 
    { 
     sp->name(); 
    } 

    auto wp2 = GetCar<Renault>(cars); 

    auto sp2 = wp2.lock(); 
    if (sp2) 
    { 
     sp2->name(); 
    } 

} 

esso stampa:

Saab

Renault

Coliru link: http://coliru.stacked-crooked.com/a/9dbb85b556b83597

+0

Wow! Esattamente quello che stavo cercando! Buona giornata signore. – miniconco