多态性并获取C++中的对象类型

问题描述:

假设我有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++中,它会创建运行时开销。相反,使用虚拟功能来处理不同类别行为的设计通常是一种方法。 –

您可以使用虚拟函数做多分派

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 
} 

你的问题听起来像一个糟糕的抽象。所以实际上你并没有解决正确的问题。当您不需要知道对象的确切类型时,应该使用继承,而应该依赖运行时多态。

你可以烘烤一些标志,比如虚拟函数,它将返回每种类型的标识,但是相当有效,而不是解决方案。弄错它也很容易。

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

变种

相反多态性,如果类型是固定的(例如,你不打算添加或删除类),你可以使用std::variant<>(C++ 17)或升压。变种。要与之互动,您需要使用访问者并致电std::visit()。可能会更难与它互动,但在我看来,它更适合作为你所描述的问题的解决方案。

+0

还有别的办法吗?一个不需要标志或std :: variant? –

+1

@JohnLannister,你不会提供任何细节。我可以写信给你:“我现在在吃巧克力,猜猜我吃的是什么巧克力?”。 ABCDE没有任何意义。你对这个问题的描述也不是 – Incomputable