假设我有一个 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 {
...
}
答案 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();