2009-09-30 10 views
5

Próbuję rzucić od jednego rodzajowego do innego, powiedzieć:C++ Szablony typu odlew z pochodnymi

myClass<MoreAbstract> anItem = myclass<DerivateFromMoreAbstract> anotherObject; 

Albo zrobić coś

aFunction(anotherObject); // myclass<DerivateFromMoreAbstract> anotherObject 

gdzie aFunction podpis jest

aFunction(myClass<MoreAbstract> item); 

W rzeczywistości myClass jest tak naprawdę uproszczoną implementacją shared_ptr, którą znalazłem online. Zastanawiam się, czy jest jakikolwiek sposób, w jaki mogę zmienić typ wskaźnika na inny, który jest enkapsulowany.

Czy istnieje sposób na wykonanie tego odlewu? Jeśli tak, jaki byłby właściwy sposób, aby to zrobić?

Jeśli to pomoże nikogo, VC++ daje mi ten błąd:

Error 1 error C2440: 'type cast' : cannot convert from 'myClass<T>' to 'myClass<T>' 
+1

Czy to C++ netto. generics lub pytanie w szablonie C++? –

+0

@Yannick: Szablony C++. – tomzx

Odpowiedz

10

Nie można wykonywać rzutowania statycznego, ponieważ są one niezgodne. czasami można utworzyć operator zmuszenia typ zamiast

#include <iostream> 

class A { }; 

class B : public A { }; 


template<typename T> 
struct holder { 
    T* value; 

    holder (T*value) : value (value) { } 

    template < typename U > // class T : public U 
    operator holder<U>() const 
    { 
     return holder<U>(value); 
    } 
}; 


int main() 
{ 
    using namespace std; 

    B b; 

    holder<B> hb (&b); 
    holder<A> ha = hb; 

    cout << boolalpha; 

    cout << (hb.value == ha.value) << endl; 

    return 0; 
} 

Czy jest to sensowne działanie raczej zależy semantyczny klasy szablonu - jeśli aFunction można kłaść do obsługi, nie chcemy, bardziej specyficzny obiekt podlegający mutacji. W związku z tym kopiujesz w jakiś sposób, używając operatora przymusu lub konstruktora kopii szablonu i zadania. (przymus jest mniejszy, ale może spowodować utworzenie większej liczby obiektów, jeśli nie użyjesz parametrów odniesienia).

+2

Wolałbym konwertujący konstruktor od operatora konwersji, ponieważ nie można go włączyć ani wyłączyć. –

+0

@Pete Kirkham: Potrzebuję twojej pomocy. Dlaczego użyłeś szablonu wewnątrz modułu struct? Jaki jest jego cel? W komentarzach napisałeś // klasę T: public U. Co to znaczy? – Destructor

3

Niestety, nie jest to możliwe. (No chyba, że ​​robisz paskudne hacki reinterpret_cast, ale nie chcesz tego robić - efekt końcowy nie będzie ładny).

T<Base> i T<Derived> nie są powiązane. Kompilator nie może tego założyć - pamiętaj, że jest całkowicie możliwe, że T był wyspecjalizowany w Derived jako coś zupełnie innego.

1

Szablony w języku C++ oraz generyczne w języku C++ .net nie są kowariantne.

Sprawdź pytanie: this, może dać ci pomysł obejścia tego problemu.

6

Typy nie są w ten sposób przekształcane domyślnie (ponieważ możesz tego nie chcieć). Ogólnie można wziąć dwa podejścia:

Należy wdrożyć wyraźną funkcję rzutowania, która może być przydatna w przypadku rzutowania w czasie wykonywania, na przykład boost's shared_ptr dynamic_pointer_cast. Można by skończyć z czymś takim:

template <typename To, typename From> 
myclass<To> myclass_cast(const myclass<From>&) 
{ /* do a runtime cast, possibly with exceptions */ } 

Drugą metodą jest konwersja konstruktora, co jest dobre, jeśli jest rozstrzygalne w czasie kompilacji, jeśli są one convertable. Na przykład, jeśli wszystkie zajęcia są convertable z matrycy na Pochodzące do matrycy na bazie, oto konstruktor, że będzie działać tylko wtedy, gdy jest to prawda (używając enable_if i boost :: type_traits):

template <typename To> 
class myclass { 
    //converting constructor 
    template <typename From> 
    myclass(const myclass<From>&, 
      typename enable_if<boost::type_traits::is_base_of<To, From> >::type* dummy = 0) 
    { } 
};