5

假设我有一个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 {
  ...
}
4

8 回答 8

22

不。

阅读多态性。几乎每一个“动态转换”情况都是多态性难以实现的例子。

无论您在动态演员阵容中做出的决定都已经做出。只需将实际工作委托给子类即可。

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

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();
于 2008-10-28T12:49:43.453 回答
9

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

如果您需要特定于子类的处理,模板方法可能会有所帮助,但在不知道您要达到什么目的的情况下,这只是一个模糊的猜测。

于 2008-10-28T12:34:56.760 回答
5
Derived1* d1 = dynamic_cast< Derived1* >(object);
if (d1 == NULL)
{
    Derived2* d2 = dynamic_cast< Derived2* >(object);
    //etc
}

我的智能指针类型有以下方法,模拟 C# 'is' 和 '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);}
于 2008-10-28T12:38:48.607 回答
4

您可以使用 来执行此操作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.
}

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

于 2008-10-28T12:39:28.467 回答
3

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

于 2008-10-28T12:32:18.230 回答
2

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

于 2008-10-28T12:35:45.150 回答
1

您的示例不会移植,因为未指定 name() 的确切格式。您可以尝试连续的dynamic_casts。 Dynamic_cast如果转换为错误的类型,则返回空指针。但是,如果您正在做一个像这样的类型切换,那么您的设计就有问题。

于 2008-10-28T12:34:21.830 回答
1

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

于 2008-10-28T13:17:22.553 回答