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

Polymorphism and get object type in C++

本文关键字:对象 类型 C++ 获取 多态性      更新时间:2023-10-16

假设我有 4 个类,B,C,D,E继承自A(抽象基类)。 我还有一个类型为A*的容器 (std::vector),其内容指向B,C,D,E对象。 以下是一些规则: 如果B对象和C对象交互,它们将从矢量中删除,并在其位置创建一个D对象。

另外,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;
}

我将如何实现交互功能?

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

你可以烘焙一些标志,比如虚拟函数,它将返回每种类型的id,但更像是解决方法,而不是解决方案。也很容易弄错。

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

变种

如果类型是固定的(例如,您不打算添加或删除类),则可以使用std::variant<>(C++17) 或 boost.variant,而不是多态性。要与之交互,您需要使用访问者并调用std::visit()。可能更难与之交互,但在我看来,它更适合作为您描述的问题的解决方案。

您可以使用虚拟函数来执行多次调度

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
}