以编程方式进行C ++编译:可以完成吗?

时间:2008-10-28 12:26:37

标签: c++ casting

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

8 个答案:

答案 0 :(得分: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();

答案 1 :(得分:9)

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

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

答案 2 :(得分:5)

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);}

答案 3 :(得分: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.
}

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

答案 4 :(得分:3)

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

答案 5 :(得分:2)

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

答案 6 :(得分:1)

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

答案 7 :(得分:1)

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