2013-03-21 12 views
8

Mam obiekt (Z), który pochodzi od dwóch innych obiektów (A i B).Podwójne dziedziczenie enable_shared_from_this

A i B pochodzą z enable_shared_from_this<>, odpowiednio enable_shared_from_this<A> i enable_shared_from_this<B>.

Oczywiście nazywam się shared_from_this() na Z. I oczywiście kompilator zgłasza to jako niejednoznaczny.

Moje pytania są następujące:

  • jest to bezpieczne, aby odziedziczyć dwa razy z enable_shared_from_this<> lub będzie utworzyć dwa oddzielne liczniki referencyjnych
  • Jeśli nie jest bezpieczne, jak mogę rozwiązać ten problem (zły!)?

Uwaga: Znalazłem to inne pytanie bad weak pointer when base and derived class both inherit from boost::enable_shared_from_this, ale tak naprawdę nie odpowiada. Czy powinienem również użyć sztuczki virtual?

+0

możliwy duplikat [boost shared \ _from \ _this and multiple dziedziczenie] (http://stackoverflow.com/questions/14939190/boost-shared-from-this-and-multiple-inititance) – user

Odpowiedz

11

Tak, zgodnie z bad weak pointer when base and derived class both inherit from boost::enable_shared_from_this rozwiązaniem jest wykorzystanie wirtualnego dziedziczenia. Oto implementacja dla C++ standard 11 shared_ptr (nie Boost):

#include <memory> 

struct virtual_enable_shared_from_this_base: 
    std::enable_shared_from_this<virtual_enable_shared_from_this_base> { 
    virtual ~virtual_enable_shared_from_this_base() {} 
}; 
template<typename T> 
struct virtual_enable_shared_from_this: 
virtual virtual_enable_shared_from_this_base { 
    std::shared_ptr<T> shared_from_this() { 
     return std::dynamic_pointer_cast<T>(
     virtual_enable_shared_from_this_base::shared_from_this()); 
    } 
}; 

struct A: virtual_enable_shared_from_this<A> {}; 
struct B: virtual_enable_shared_from_this<B> {}; 
struct Z: A, B { }; 
int main() { 
    std::shared_ptr<Z> z = std::make_shared<Z>(); 
    std::shared_ptr<B> b = z->B::shared_from_this(); 
} 

To nie jest elementem realizacji domyślnej, prawdopodobnie ze względu na napowietrznej wirtualnego dziedziczenia.

+0

Myślę, że lepiej jest użyć 'static_pointer_cast' tutaj – kassak

+0

@kassak' static_pointer_cast' nie będzie działać; jest to dziedziczenie wirtualne, więc wymagany jest dynamiczny rzut. – ecatmur

+0

ale jest to prosty downcasting z 'virtual_enable_shared_from_this_base' na' T', wyprowadzony z niego. Kompilator narzeka? – kassak

1

Tak, klasa będzie pochodzić z dwóch różnych klas enable_shared_from_this<A> i enable_shared_from_this<B> i mieć dwa różne słaby REF za

trick że odpowiedź pozwala mieć jedną klasę bazową, z powodu dziedziczenia wirtualnego

+0

Dlaczego to nie jest sztuczka zintegrowana domyślnie z 'enable_shared_from_this'? – Offirmo

+0

@LucDanton Nie może sobie z tym poradzić, ponieważ obie instacje z włączonym udostępnianiem są odrębnymi klasami. Dlatego nawet odziedziczone po raz pierwszy są różne. Jedynym sposobem jest posiadanie jednej wirtualnej klasy, która dziedziczy ją dowolnym argumentem typu, a następnie używa tej wirtualnej klasy jako bazy. Jedyny problem może być w 'make_shared', ale nie jestem pewien – kassak

+0

@LucDanton o tym myśląc, używając" wirtualnej "sztuczki, aby obiekt wyprowadzony miał wirtualny stolik, dzięki czemu jest większy. Ponieważ filozofia C++ to "płacisz tylko za to, o co prosisz", wirtualna sztuczka nie powinna być używana domyślnie. – Offirmo