2010-05-30 18 views
15

Potrzebuję napisać program realizujący wzór wizyty gościa. Problem polega na tym, że podstawowa klasa odwiedzającego jest klasą szablonów. Oznacza to, że BaseVisited :: accept() przyjmuje klasę szablonu jako parametr i ponieważ używa "this" i potrzebuję "this", aby wskazać prawidłową instancję wykonawczą obiektu, musi również być wirtualna.
Chciałbym wiedzieć, czy istnieje jakiś sposób obejścia tego problemu.Potrzebuję obejścia wirtualnego szablonu uczestnika

template <typename T> 
class BaseVisitor { 
    public: 
    BaseVisitor(); 
    T visit(BaseVisited *visited); 
    virtual ~BaseVisitor(); 
} 


class BaseVisited { 
    BaseVisited(); 
    template <typename T> 
    virtual void accept(BaseVisitor<T> *visitor) { visitor->visit(this); }; // problem 
    virtual ~BaseVisited(); 
} 
+1

Co jest nie tak z tym? –

+2

to nie będzie kompilacji. http://stackoverflow.com/questions/2354210/template-member-function-virtual – yurib

+2

Kompilator nie zaakceptuje szablonów w funkcjach wirtualnych. – Puppy

Odpowiedz

16

Co należy zrobić, to oddzielić BaseVisitor.

class BaseVisited; 
class BaseVisitorInternal { 
public: 
    virtual void visit(BaseVisited*) = 0; 
    virtual ~BaseVisitorInternal() {} 
}; 
class BaseVisited { 
    BaseVisited(); 
    virtual void accept(BaseVisitorInternal* visitor) { visitor->visit(this); } 
}; 
template<typename T> class BaseVisitor : public BaseVisitorInternal { 
    void visit(BaseVisited* visited); 
}; 

Jeśli potrzebujesz klas pochodnych BaseVisited do bycia zbyt matrycy i przekazać swoje poprawne typy/przeciąża odwiedzić, jesteś oficjalnie martwy.

+0

Uderzyłeś mnie w to! :-) –

+3

Zasadniczo jest to [typ wymazania] (http://stackoverflow.com/questions/2354210/template-member-function-virtual/2354671#2354671). – sbi

+0

Myślę, że mogę być oficjalnie martwy ... :-P – NargothBond

4

wymyśliłem coś nieco innego niż DeadMG:

class BaseVisited; 

class IVisitor { 
    public: 
    virtual void visit(BaseVisited *visited) = 0; 
    virtual ~IVisitor(); 
}; 

template <typename T> 
class BaseVisitor : public IVisitor { 
    public: 
    BaseVisitor(); 
    virtual void visit(BaseVisited *visited); 
    virtual ~BaseVisitor(); 
    virtual T result(); 
}; 


class BaseVisited { 
    public: 
    BaseVisited(); 
    virtual void accept(IVisitor *visitor) { visitor->visit(this); }; 
    virtual ~BaseVisited(); 
}; 

Kopalnia ma dodatkową funkcję result() użytkownika, który pozwala odzyskać wynik ostatniej wizyty.

+0

Nie sądzę, że to zadziała –

4

Nie można deklarować/definiować szablonowych funkcji wirtualnych. Powodem jest to, że mechanizm wirtualnej wysyłki musi być znany, gdy kompilator widzi definicję klasy podstawowej, ale szablony są kompilowane na żądanie.

Ze wspólną implementacją vtable problem polega na tym, że liczba pozycji, które kompilator musiałby zarezerwować dla funkcji wirtualnej, jest niezdefiniowana (ile może być różnych instancji tego typu?), Podobnie jak ich kolejność . Jeśli zadeklarować klasę:

class base { 
public: 
    virtual void foo(); 
    virtual int bar(); 
}; 

Kompilator może zarezerwować dwa wpisy w vtable dla wskaźniki do foo i bar w vtable i vtable jest doskonale zdefiniowane przez to kontrolę definicję klasy. Nie można tego osiągnąć za pomocą szablonów.

+0

Wiem, że to niemożliwe i rozumiem, dlaczego, moje pytanie dotyczyło znalezienia rozwiązania, które nie obejmuje funkcji wirtualnej szablonu . dzięki mimo to. – yurib

+0

@Iurib: chcesz rozwiązania, a jednak nie zgłosiłeś swojego problemu - poprosiłem o to w komentarzu do pytania: co naprawdę chcesz osiągnąć. Pytasz tylko o potencjalne rozwiązanie, które nie działa, a nie o pierwotny problem. –