假设我有一个 Base 类和几个 Derived 类。有没有办法将对象强制转换为派生类之一,而无需编写类似这样的东西:


string typename = typeid(*object).name();
if(typename == "Derived1") {
   Derived1 *d1 = static_cast< Derived1*>(object);
}
else if(typename == "Derived2") {
   Derived2 *d2 = static_cast < Derived2*>(object);
}
...
else {
  ...
}
有帮助吗?

解决方案

别。

阅读多态性。几乎每一个“动态演员阵容”都是情况是多态性难以实施的一个例子。

无论你在动态演员表中做出什么决定都已经完成了。只需将实际工作委托给子类。

您遗漏了示例中最重要的部分。有用的多态工作。

string typename = typeid(*object).name();
if(typename == "Derived1") {
   Derived1 *d1 = static_cast< Derived1*>(object);
   d1->doSomethingUseful();
}
else if(typename == "Derived2") {
   Derived2 *d2 = static_cast < Derived2*>(object);
   d2->doSomethingUseful();
}
...
else {
  ...
}

如果每个子类都实现了doSomethingUseful,这就简单得多了。而且是多态的。

object->doSomethingUseful();

其他提示

您可以使用 dynamic_cast 并测试NULL,但我强烈会考虑重构代码。

如果您需要特定于子类的处理,模板方法可能会有所帮助,但不知道你想要实现的是什么,这只是一个模糊的猜测。

Derived1* d1 = dynamic_cast< Derived1* >(object);
if (d1 == NULL)
{
    Derived2* d2 = dynamic_cast< Derived2* >(object);
    //etc
}

我的smartpointer类型有以下方法,模拟C#'是'和'as':

template< class Y > bool is() const throw()
    {return !null() && dynamic_cast< Y* >(ptr) != NULL;}
template< class Y > Y* as() const throw()
    {return null() ? NULL : dynamic_cast< Y* >(ptr);}

您可以使用 dynamic_cast 执行此操作,例如:

if ( Derived1* d1 = dynamic_cast<Derived1*>(object) ) {
    // object points to a Derived1
    d1->foo();
}
else if ( Derived2* d2 = dynamic_cast<Derived2*>(object) ) {
    // object points to a Derived2
    d2->bar();
}
else {
    // etc.
}

但正如其他人所说的那样,这样的代码可能表明设计不好,你通常应该使用虚函数来实现多态行为。

通常,这是一个糟糕设计的标志。你为什么需要这样做?有可能重新设计,以便不需要这样做。

你到底想要完成什么? 根据我的经验,这样的事情是糟糕设计的标志。重新评估您的类层次结构,因为面向对象设计的目标是使这样的事情变得不必要。

您的示例不会移植,因为未指定name()的确切格式。您可以尝试一系列 dynamic_cast 。如果转换为错误的类型, Dynamic_cast 将返回空指针。但是,如果您正在进行类似这样的类型切换,那么您的设计就会出现问题。

我认为dynamic_cast是要走的路,但我并不特别认为这是一个针对所有可能条件的糟糕设计,因为要转换的对象可能是某些第三方模块提供的东西。假设对象是由应用程序作者不知道的插件创建的。并且该特定插件可以创建Derived1(作为旧版本)类型对象或Derived2(作为新版本)类型对象。也许插件接口不是为了做特定于版本的东西,它只是创建对象,因此应用程序必须进行这种检查以确保正确的转换/执行。在此之后,我们可以安全地调用object.doSomethingUsefulThatDoesNotExistInDerived1();

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top