class 层次结构中 dynamic_cast 的替代项

Alternatives to dynamic_cast in class hierarchy

我有一个 class 结构,其中包含大量不同的 child class es,它们都继承自相同的抽象基础 class。这个基础 class 在那里是因为所有这些 classes 在编译时自注册到它们被构建的工厂。这真的很整洁,让我免于在下游某处维护一个巨大的开关或任何其他流机制的负担。

              +---------------+
              |     Base      |
              +--+---------+--+
                 |         |
         +-------+-+     +-+-------+
         |  Kid1   |     |  Kid2   |
         +----+----+     +----+----+
              |               |
  +---+---+---+               +---+---+---+
  |   |   |   | ...           |   |   |   | ....

但是,这些 Kid1Kid2 class 是不同的,问题是我必须在我的代码中的某处区分它们,而我唯一拥有的是Base 指针。我不想为此打扰工厂并尽可能保持简单。

我现在解决这个问题的方法是让 Base 稍微了解这两个兄弟姐妹。它有一个虚拟方法 type(),其中 returns 是一个区分 Kid1Kid2 的枚举类型。两个孩子都忽略了这个 (基本上说我是 KidX) 这样我就知道我在和谁打交道。然后将此类型用于 dynamic_cast Base 给其中一个孩子,程序继续进行。

但是,这是正确的方法吗?

例如,我可以向基础添加更多 virtual 方法,一方面用层次结构的一部分使用的方法污染它,但另一方面节省了 dynamic_cast

有什么想法吗?

您不需要 dynamic_castdynamic_cast 已经使用内部运行时类型信息来确定它是否能够将传递的 pointer/reference 转换为所需的类型,但您已经在检查它通过 type() 方法。 static_cast 在您的情况下就足够了,因为您已经自己提供了 RTTI。

或者您也可以删除 type() 方法并直接使用 dynamic_cast,如果它无法将对象转换为您想要的类型,则会产生 nullptr

如果你真的想避免这样的事情,那么你必须将所需的行为封装到 virtual 方法中,这样无论你需要使用 Kid1Kid2,你将有不同的实现而无需真正区分两者,只需让多态性发挥作用即可。

在多重继承中,dynamic_cast会根据需要移动指针,这是必须的。因此,摆脱它是危险的。如果您的系统扩展到使用 MI 的某个点,您可能会遇到各种奇怪的行为。

也许您可以使用 typeid 运算符。因为:

N3337 5.2.8/2 说:

When typeid is applied to a glvalue expression whose type is a polymorphic class type (10.3), the result refers to a std::type_info object representing the type of the most derived object (1.8) (that is, the dynamic type) to which the glvalue refers ....

示例:

struct Base
{
    virtual void f(){} //to ensure that Base is polymorphic object
};

struct Derived: Base{};

struct AnotherDerived: Base{};



int main()
{
    Base *ptr = new AnotherDerived;

    if(typeid(*ptr) == typeid(Derived)) //Do not forget to dereference pointer, otherwise typeid() will return type_info for pointer itself
    {
         cout << "ptr is pointing to object of type Derived" << endl;
    }

    if (typeid(*ptr) == typeid(AnotherDerived))
    {
        cout << "ptr is pointing to object of type AnotherDerived" << endl;
    }

}

但是,如果您必须在代码中区分它们,为什么要使用指向 Base 的指针?如何将仅使用 Base 属性的代码与使用 child 类 的特定属性的代码分开?这就是多态性的全部意义。

编辑: 正如 davmac 指出的那样。只有当这些 sub类 最派生 类.

时,它才会起作用

我通常更喜欢能够在不使用强制转换的情况下获得所需类型的句柄。这意味着将方法添加到 Base class:

virtual Kid1 *asKid1()
{
    return null;
}

virtual Kid2 *asKid2()
{
    return null;
}

子classes 然后适当地覆盖这些:

// (in Kid1)
virtual Kid1 *asKid1() override
{
    return this;
}

虽然你的Baseclass仍然"polluted"有额外的方法,但只需要这两个方法,即使subclasses在未来。

(你可以让它们 return 引用而不是指针,在这种情况下它们应该默认抛出异常)。

您可以尝试 Visitor pattern

When should I use the Visitor Design Pattern?