2013-02-19 20 views
5
class Interface 
{ 
}; 

class Class : public Interface 
{ 
}; 

class Foo 
{ 
public: 
    std::vector<std::shared_ptr<Interface>>& GetInterfaces() 
    { 
     return *(std::vector<std::shared_ptr<Interface>>*)(&m_data); 
     //return m_data; 
    } 

private: 
    std::vector<std::shared_ptr<Class>> m_data; 
}; 

To działa, ale jest brzydkie i przerażające. Czy istnieje lepszy/bezpieczniejszy sposób na zrobienie tego? Nie chcę, aby m_data typu std::vector<std::shared_ptr<Interface>> ponieważ moduł Foo należący do działa całkowicie z Class „s, Interface (i Foo::GetInterfaces()) są realizowane w interakcje z oddzielnym module, który powinien wiedzieć tylko o funkcjonalności Interface.Jak rzutować wektor shared_ptrs z klasy pochodnej na wektor share_ptrs klasy bazowej

Daj mi znać, jeśli coś tu jest niejasne, ma to dla mnie sens, ale od pewnego czasu walczę z tym problemem.

Odpowiedz

7

Rzucanie nie jest poprawne, są to różne typy; Jestem prawie pewien, że przywołujesz niezdefiniowane zachowanie.

Musisz zbudować nowy wektor i zwrócić go według wartości.

std::vector<std::shared_ptr<Interface>> b (m_data.begin(), m_data.end()); 
return b; 

To powinno być dość tanie (1 przydział).

+0

Jaki jest wspólny wskaźnik zamiar zrobić w tej sytuacji? Nie jestem pewien, czy chce dzielić wskaźniki pomiędzy dwoma różnymi typami współdzielonych wskaźników! –

+0

@MichaelKohne no to jest w porządku. – 111111

+0

Ahh, przesuń semantykę, aby wygrać! powinieneś powrócić po wartości ok. –

4

Poza tym nie jest to możliwe przy wdrażaniu vector, problem polega również na tym, że referencje się nie konwertują. Twój kod jest jeszcze gorszy i ma niezdefiniowane zachowanie.

Co można zrobić, to udostępnić interfejs, który odsłania zakres lub begin/end zamiast samego kontenera. Jeśli połączysz to z transform_iterator, który dokonuje konwersji, powinieneś ustawić.

Przykładowy kod:

class Interface { 
    virtual ~Interface(); 
}; 

class X : public Interface {}; 

class C { 

private: 
    typedef std::shared_ptr<Interface> iptr_type; 
    typedef std::shared_ptr<Class> ptr_type; 
    std::vector<ptr_type> v_; 

    struct F { 
    iptr_type 
    operator()(ptr_type p) { return iptr_type(p); } 
    }; 

    typedef boost::transform_iterator< 
    F, std::vector<ptr_type>::iterator> iiterator; 

public: 
    iiterator 
    begin() 
    { 
    return boost::make_transform_iterator(
     begin(v_), F()); 
    } 

    iiterator 
    end() 
    { 
    return boost::make_transform_iterator(
     end(v_), F()); 
    } 
}; 
+0

Jeśli ma to sens w twoim przypadku użycia, to wystawiając ' .begin() 'i' .end() 'interfejs iteratora jest dobrym rozwiązaniem. – 111111

+0

@ 111111 Pewnie, że również. Sądzę jednak, że zakresy są bardziej modne. – pmr

+0

mój komentarz był jeden na poparcie twojego pomysłu :) – 111111

Powiązane problemy