2017-08-11 161 views
1

想象一下,我有兩個相似的結構A和B.A和B都有一個指向A的指針,但A有一個指向A或B的附加指針。C++:使用基類Derived-class變量

我認爲是這樣的一個基地和一個派生類

template <bool T> struct Derived; 
struct Base { Derived<0> *p1; }; 
template <> struct Derived<0> : public Base { Base *p2; }; 
template <> struct Derived<1> : public Base {}; 

其中A是Derived<0>,B是Derived <1>

這裏的問題是,當通過p2訪問一個類時,編譯器不知道它是哪個派生類,並且類似這樣會給出一個錯誤。

Derived<0> x, y, z; 
x.p2 = &y; 
y.p2 = &z; 
x.p2->p2; // Error 

您是否有任何人知道任何神奇的解決方法,最好只使用編譯時功能?

我也需要知道我使用的派生類型,以便我知道是否可以使用p2。

如果有幫助,你可以想像的事情作爲一個雙鏈表,其中Derived<0>是一個正常的節點,Derived<1>是終端節點,p1上一頁指針和p2下一個指針。

編輯:它不需要使用Base-and-Derived-class-type結構,它可以是任何東西。

+2

這是一個錯誤,因爲'x.p2'是一個指向'Base'的指針,它沒有'p2'成員,所以' - > p2'不能解析任何東西。你可以'dynamic_cast >(x.p2)'並檢查結果是不是'nullptr'。如果不是,則可以通過鑄造的指針訪問' - > p2'。 – cdhowie

+0

(請注意,對於'dynamic_cast'來說,基類必須是多態纔能有條件地正確投射。) – cdhowie

回答

1

一個可能的解決方案是基於雙重調度,這是同樣的想法是最着名的訪問者模式。

它遵循最小,工作示例:

#include<iostream> 

template<int> 
struct Derived; 

struct Visitor { 
    template<int N> 
    void visit(Derived<N> &); 
}; 

struct Base { 
    Derived<0> *p1; 
    virtual void accept(Visitor &) = 0; 
}; 

template<> 
struct Derived<0>: public Base { 
    void accept(Visitor &) override; 
    Base *p2; 
}; 

template<> 
struct Derived<1>: public Base { 
    void accept(Visitor &) override; 
}; 

template<> 
void Visitor::visit(Derived<0> &d) { 
    std::cout << "Derived<0>" << std::endl; 
    d.p2->accept(*this); 
} 

template<> 
void Visitor::visit(Derived<1> &) { 
    std::cout << "Derived<1>" << std::endl; 
} 

void Derived<0>::accept(Visitor &v) { 
    v.visit(*this); 
} 

void Derived<1>::accept(Visitor &v) { 
    v.visit(*this); 
} 

int main() { 
    Visitor v; 
    Derived<0> x, y; 
    Derived<1> z; 
    x.p2 = &y; 
    y.p2 = &z; 
    x.p2->accept(v); 
} 

見它,並在wandbox運行。

如果你可以使用C++ 17,因此std::variant,事情遠遠更簡單:

#include<iostream> 
#include<variant> 

template<int> 
struct Derived; 

struct Base { 
    Derived<0> *p1; 
}; 

template<> 
struct Derived<0>: public Base { 
    std::variant<Derived<0> *, Derived<1> *> p2; 
}; 

template<> 
struct Derived<1>: public Base {}; 

struct Visitor { 
    void operator()(Derived<0> *d) { 
     std::cout << "Derived<0>" <<std::endl; 
     std::visit(*this, d->p2); 
    } 

    void operator()(Derived<1> *) { 
     std::cout << "Derived<1>" <<std::endl; 
    } 
}; 

int main() { 
    Visitor v; 
    Derived<0> x, y; 
    Derived<1> z; 
    x.p2 = &y; 
    y.p2 = &z; 
    std::visit(v, x.p2); 
} 

見它,並在wandbox運行。

+0

嗯,非常好的技巧。謝謝! – gmardau