2017-08-08 9 views
0

Ich verwende das Besuchermuster, um mit vielen verschiedenen AST-Problemen umzugehen, was sehr gut funktioniert. Zum Beispiel verwende ich es, um nach statischem Typ zu suchen. Dies funktioniert gut, wenn nach dem genauen Typ gesucht wird, jedoch nicht für abgeleitete Klassen. Wenn wir Derived haben, die von Base erben, wird gefragt, ob ein Derived Objekt ein Base Fehler ist.Verwenden eines Besuchermusters zum Überprüfen des abgeleiteten Klassentyps?

Betrachten Sie den folgenden C++ Code:

#include <iostream> 
#include <functional> 
#include <memory> 

using namespace std; 

class Base; 
class Derived; 

class Visitor { 
public: 
    virtual void visit(Base& object) = 0; 
    virtual void visit(Derived& object) = 0; 
}; 

class EmptyVisitor : public Visitor { 
public: 
    virtual void visit(Base& object) override {} 
    virtual void visit(Derived& object) override {} 
}; 

template <class TYPE> class LogicVisitor : public EmptyVisitor { 
public: 
    LogicVisitor(function<void(TYPE&)> logic) : EmptyVisitor(), logic(logic) {} 
    virtual void visit(TYPE& object) override { logic(object); } 
private: 
    function<void(TYPE&)> logic; 
}; 

class Base { 
public: 
    virtual void accept(Visitor* visitor) { 
     visitor->visit(*this); 
    } 
}; 

class Derived : public Base { 
public: 
    virtual void accept(Visitor* visitor) override { 
     visitor->visit(*this); 
    } 
}; 

template <class TYPE> bool is_type(shared_ptr<Base> base) 
{ 
    bool is_type = false; 
    LogicVisitor<TYPE> logic_visitor([&](TYPE& object) { 
     is_type = true; 
    }); 
    base->accept((Visitor*)&logic_visitor); 
    return is_type; 
} 

int main() { 
    auto base = make_shared<Base>(); 
    auto derived = make_shared<Derived>(); 
    cout << "is_type<Base>(base) = " << (is_type<Base>(base) ? "true" : "false") << endl; 
    cout << "is_type<Derived>(base) = " << (is_type<Derived>(base) ? "true" : "false") << endl; 
    cout << "is_type<Base>(derived) = " << (is_type<Base>(derived) ? "true" : "false") << endl; 
    cout << "is_type<Derived>(derived) = " << (is_type<Derived>(derived) ? "true" : "false") << endl; 
    return 0; 
} 

Es gibt erwartet als das folgende Ergebnis:

is_type<Base>(base) = true 
is_type<Derived>(base) = false 
is_type<Base>(derived) = false 
is_type<Derived>(derived) = true 

Während dieses großen ist den statischen Typen eines Objekts abzurufen, wie kann diese behoben werden, wenn ich wollte is_type<Base>(derived)true anstelle von false zurückgeben, so dass ich Klassenvererbung effektiv überprüfen kann? Ist das in C++ möglich?

+3

Warum Sie das alle virtuellen Gitter brauchen, wenn Sie einfach 'std :: is_base_of' verwenden kann? – SergeyA

+0

Nun, ich wusste nicht, 'std :: is_base_of', das sieht in der Tat sehr nützlich aus, aber dann die Frage ist, benötigt diese Funktion RTTI? – Deathicon

+0

@Deathicon Nein. Es handelt sich um eine Typeigenschaft, die zur Kompilierzeit ausgewertet wird. – Rakete1111

Antwort

3

Sie können nicht. Der Grund dafür ist die Überladungsauflösung (und Ihr Designmuster). Jeder Besucher hat zwei Überladungen, eine für Base& und die zweite für Derived&. LogicVisitor überschreibt die Funktion mit dem Typ, der als Vorlagenparameter übergeben wurde, so dass Basevoid visit(Base&) überschrieben wird.

Sie möchten stattdessen void visit(Derived&) für Base außer Kraft setzen (oder zusätzlich). Aber das würde erfordern, dass der Besucher jede Klasse findet, die sich von Base ableitet, was im Moment nicht möglich ist.

können Sie std::is_base_of statt:

template<typename T, typename U> 
constexpr bool is_type(std::shared_ptr<U>) { 
    return std::is_base_of_v<std::decay_t<T>, std::decay_t<U>>; 
} 
+1

Ja, ich benutze 'std :: is_base_of', was ich hätte benutzen sollen. Die Frage ist nicht mehr relevant, wenn Sie wissen, dass diese Funktionalität existiert. Vielen Dank! – Deathicon

Verwandte Themen