类层次结构中dynamic_cast的替代方法

时间:2016-05-18 18:33:50

标签: c++ inheritance dynamic-cast virtual-method

我有一个包含不同子类的负载的类结构,所有子类都继承自同一个抽象基类。这个基类是因为所有这些类在编译时自行注册到构建它们的工厂。这非常简洁,让我免于在下游某处维护一个巨大的交换机或任何其他流量机制的负担。

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

但是,这些Kid1Kid2类是不同的,问题是我必须在我的代码中的某个地方区分它们,我唯一拥有的是Base指针。我不想用这个来打扰工厂,并尽可能简单。

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

然而,这是正确的方法吗?

我可以添加一些virtual方法作为基础,一方面用方法污染它只有层次结构的一部分使用但另一方面保存我dynamic_cast

有什么想法吗?

5 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:1)

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

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

如果你真的想避免这些事情,那么你不得不将所需的行为封装到virtual方法中,这样无论你需要使用Kid1还是Kid2,你都会有不需要真正区分两者,只需让多态实现它的工作。

答案 2 :(得分:0)

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

N3337 5.2.8 / 2说:

  

当typeid应用于glvalue表达式,其类型为多态类类型(10.3)时,结果引用   到表示最派生对象(1.8)类型的std :: type_info对象(即动态   glvalue引用的类型 ....

示例:

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属性和代码的地方分隔代码,在哪里使用子类的特定属性?这就是多态性的全部要点。

编辑: 正如davmac指出的那样。只有当这些子类是大多数派生类时才会起作用。

答案 3 :(得分:0)

我通常更喜欢能够在不使用演员表的情况下获得所需类型的句柄。这意味着向Base类添加方法:

virtual Kid1 *asKid1()
{
    return null;
}

virtual Kid2 *asKid2()
{
    return null;
}

子类然后根据需要覆盖这些:

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

虽然你的Base课程仍然受到污染,但是#34;使用额外的方法,只需要这两个方法,即使将来扩展子类。

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

答案 4 :(得分:0)