2017-08-08 82 views
0

我使用訪問者模式來處理很多不同的AST問題,結果證明它工作得很好。例如,我正在使用它來檢查靜態類型。這在查找確切類型時效果很好,但它不適用於派生類。即如果我們有從Base繼承的Derived,詢問Derived對象是否爲Base失敗。使用訪客模式檢查派生類的類型?

考慮下面的C++代碼:

#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; 
} 

它輸出如預期以下結果:

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

雖然這是很大的檢索靜態類型的對象的,如何能這如果我想要is_type<Base>(derived)返回true而不是false,以便我可以有效地檢查類繼承嗎?這在C++中可能嗎?

+3

爲什麼你需要所有這些虛擬網,如果你可以簡單地用'的std :: is_base_of'? – SergeyA

+0

嗯,我不知道'std :: is_base_of',看起來非常有用,但問題是,這個函數是否需要RTTI? – Deathicon

+0

@Deathicon號這是一個類型特徵,在編譯時進行評估。 – Rakete1111

回答

3

你不行。重載解析的原因(和你的設計模式)。每個訪問者都有兩個過載,一個用於Base&,另一個用於Derived&LogicVisitor將覆蓋函數的類型作爲模板參數傳遞,因此對於Base它將覆蓋void visit(Base&)

代替(或另外),您希望它替代void visit(Derived&)代替Base。但是,這將需要訪問者找到從Base派生的每個類,這是目前不可能的。

您可以使用std::is_base_of代替:

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

是的,使用'std :: is_base_of'是我應該使用的。當你知道這個功能存在時,這個問題就不再相關了。謝謝! – Deathicon