2016-12-25 54 views
0

假設我有4個類,B,C,D,EA(抽象基類)繼承。 另外,我有一個A*類型的容器(std::vector),其內容指向 B,C,D,E對象。 這裏有一些規則: 如果一個B對象和一個C對象相互作用,它們將從矢量中移除,並在它們的位置創建一個D對象。多態性並獲取C++中的對象類型

此外,C + D = E

現在,假設我隨機選擇的所述向量內容之一;爲了實現交互機制,我該如何去了解哪個對象是哪種類型的?

注:我不希望使用typeid運算符,動態轉換或標誌。其他解決方案?

下面是一些代碼

#include <iostream> 

class A { 
protected: 
    int v; 
public: 
    A(){} 
    ~A(){} 
}; 

class B :public A { 
public: 
    B(){} 
    ~B(){} 
}; 

class C : public A { 
public: 
    C(){} 
    ~C(){} 
}; 

class D : public A { 
public: 
    D(){} 
    ~D(){} 
}; 

class E : public A { 
public: 
    E(){} 
    ~E(){} 
}; 

int main() 
{ 
    std::vector<A*> container; 
    return 0; 
} 

我將如何實現交互功能(S)?

+2

而不是描述一些代碼,請嘗試創建一個[最小,完整,可驗證的示例]( http://stackoverflow.com/help/mcve)並向我們展示。 –

+4

什麼是*「互動」*!?你知道的物品的位置如何在他們*「互動」*時被移除? – StoryTeller

+2

關於「獲取對象類型」,這確實不是一個好主意,尤其是在C++中,它會創建運行時開銷。相反,使用虛擬功能來處理不同類別行爲的設計通常是一種方法。 –

回答

0

您可以使用虛擬函數做多分派

struct B; 
struct C; 
struct D; 
struct E; 

struct A 
{ 
    virtual ~A() = default; 

    virtual std::unique_ptr<A> interactWithA(const A&) const = 0; 

//protected: 
    virtual std::unique_ptr<A> interactWithB(const B&) const = 0; 
    virtual std::unique_ptr<A> interactWithC(const C&) const = 0; 
    virtual std::unique_ptr<A> interactWithD(const D&) const = 0; 
    virtual std::unique_ptr<A> interactWithE(const E&) const = 0; 
}; 

// Your interact rules 

template <typename LHS, typename RHS> 
std::unique_ptr<A> interact(const LHS&, const RHS&) { return nullptr; } 

// Note that definitions and declarations must be split in reality 
// to be able to compile it 
std::unique_ptr<A> interact(const B&, const C&) { return std::make_unique<D>(); } 
std::unique_ptr<A> interact(const C&, const D&) { return std::make_unique<E>(); } 
// Maybe the reflexive case, C/B D/C ? 


// The derived classes 
struct B : A 
{ 
    std::unique_ptr<A> interactWithA(const A& a) const override { return a.interactWithB(*this); } 

    // Even if code look similar for other inherited class 
    // the difference is in the runtime type of the objects are known. 
    std::unique_ptr<A> interactWithB(const B& rhs) const override { return interact(rhs, *this); } 
    std::unique_ptr<A> interactWithC(const C& rhs) const override { return interact(rhs, *this); } 
    std::unique_ptr<A> interactWithD(const D& rhs) const override { return interact(rhs, *this); } 
    std::unique_ptr<A> interactWithE(const E& rhs) const override { return interact(rhs, *this); } 
}; 

struct C : A 
{ 
    std::unique_ptr<A> interactWithA(const A& a) const override { return a.interactWithC(*this); } 
    std::unique_ptr<A> interactWithB(const B& rhs) const override { return interact(rhs, *this); } 
    std::unique_ptr<A> interactWithC(const C& rhs) const override { return interact(rhs, *this); } 
    std::unique_ptr<A> interactWithD(const D& rhs) const override { return interact(rhs, *this); } 
    std::unique_ptr<A> interactWithE(const E& rhs) const override { return interact(rhs, *this); } 
}; 

struct D : A 
{ 
    std::unique_ptr<A> interactWithA(const A& a) const override { return a.interactWithD(*this); } 
    std::unique_ptr<A> interactWithB(const B& rhs) const override { return interact(rhs, *this); } 
    std::unique_ptr<A> interactWithC(const C& rhs) const override { return interact(rhs, *this); } 
    std::unique_ptr<A> interactWithD(const D& rhs) const override { return interact(rhs, *this); } 
    std::unique_ptr<A> interactWithE(const E& rhs) const override { return interact(rhs, *this); } 
}; 

struct E : A 
{ 
    std::unique_ptr<A> interactWithA(const A& a) const override { return a.interactWithE(*this); } 
    std::unique_ptr<A> interactWithB(const B& rhs) const override { return interact(rhs, *this); } 
    std::unique_ptr<A> interactWithC(const C& rhs) const override { return interact(rhs, *this); } 
    std::unique_ptr<A> interactWithD(const D& rhs) const override { return interact(rhs, *this); } 
    std::unique_ptr<A> interactWithE(const E& rhs) const override { return interact(rhs, *this); } 
}; 

然後

std::vector<std::unique_ptr<A>> v /* = .. */; 

auto a = v[i]->interactWithA(*v[j]); 
if (a) { 
    // Remove v[i] and v[j] 
    // Insert a 
} 
1

你的問題聽起來像一個糟糕的抽象。所以實際上你並沒有解決正確的問題。當您不需要知道對象的確切類型時,應該使用繼承,而應該依賴運行時多態。

你可以烘烤一些標誌,比如虛擬函數,它將返回每種類型的標識,但是相當有效,而不是解決方案。弄錯它也很容易。

class A 
{ 
    ... 
    virtual int get_id() = 0; 
} 

變種

相反多態性,如果類型是固定的(例如,你不打算添加或刪除類),你可以使用std::variant<>(C++ 17)或升壓。變種。要與之互動,您需要使用訪問者並致電std::visit()。可能會更難與它互動,但在我看來,它更適合作爲你所描述的問題的解決方案。

+0

還有別的辦法嗎?一個不需要標誌或std :: variant? –

+1

@JohnLannister,你不會提供任何細節。我可以寫信給你:「我現在在吃巧克力,猜猜我吃的是什麼巧克力?」。 ABCDE沒有任何意義。你對這個問題的描述也不是 – Incomputable