这可能是一个愚蠢的问题,我怀疑我知道答案(不)因为我好像在这里撞墙。
鉴于我有一组派生自某个类的对象:
class BaseClass;
class DerivedA: public BaseClass;
class DerivedB: public BaseClass;
class DerivedC: public BaseClass;
std::vector<BaseClass> myCollection;
我想根据特定类的类型调用方法:
class Processor {
void doSomething(DerivedA a, DerivedB b);
void doSomething(DerivedA a, DerivedC c);
}
问题是,如果我访问集合中的各个项目并尝试在“处理器”中调用“doSomething”方法,它将无法确定使用哪种方法(afaik)。所以我的问题是:有没有办法用正确的派生类型获取集合中的项目?
答案 0 :(得分:2)
如果要保持doSomething
方法不变,这就是所谓的multiple dispatch,目前C ++不支持。
如果它是BaseClass
的虚拟成员函数,那么它就是在它被调用的对象上运行C ++多态,但它仍然不会自动推断出争论的类型。
要解决此问题,您可以执行类似于早期链接
中建议的操作void collideWith(Thing& other) {
// dynamic_cast to a pointer type returns NULL if the cast fails
// (dynamic_cast to a reference type would throw an exception on failure)
if (Asteroid* asteroid = dynamic_cast<Asteroid*>(&other)) {
// handle Asteroid-Asteroid collision
} else if (Spaceship* spaceship = dynamic_cast<Spaceship*>(&other)) {
// handle Asteroid-Spaceship collision
} else {
// default collision handling here
}
}
基本上继续强制转换为各种可能的派生类,直到一个人工作并适当地调用其中一个方法(因为编译器知道你试图转换为什么类型,所以没有特别的努力)。
重要提示:正如@WhozCraig所指出的那样,你的向量需要保留指针以避免Object-Slicing,并使整个问题无法实现。
答案 1 :(得分:1)
好的,是的,您应该使用多态性,如上所述。如果你的函数需要处理2个对象,尽管它变得非常复杂。
如果派生形成有限的集合并相互了解,则可以使用双重调度。它并不完美,但它解决了这个特殊情况。
class DerivedA;
class DerivedB;
class DerivedC;
class BaseClass
{
public:
virtual ~BaseClass();
virtual void doSomethingWithBase( BaseClass & b2 ) = 0;
virtual void doSomethingWithDerivedA( DerivedA & da ) = 0;
virtual void doSomethingWithDerivedB( DerivedB & db ) = 0;
virtual void doSomethingWithDerivedC( DerivedC & dc ) = 0;
};
class DerivedA : public BaseClass
{
public:
void doSomethingWithBase( BaseClass & b2 )
{
b2.doSomethingWithDerivedA( *this );
}
void doSomethingWithDerivedA( DerivedA & da )
{
// implement for two DerivedA objects
}
void doSomethingWithDerivedB( DerivedB & db )
{
// implement for an A and B
}
void doSomethingWithDerivedC( DerivedC & dc )
{
// implement for an A and C
}
};
// implement DerivedB to call doSomethingWithDerivedB on its parameter
// implement DerivedC to call doSomethingWithDerivedC on its parameter.
你明白了。从你打电话的地方你不需要知道你有哪两种类型,你永远不需要实际查看它。但是,如果您添加更多实现,则需要编辑大量代码,并且可能会考虑使用某种查找表。
如果您需要一个类来定义自己,您可以使用某种虚拟ID。
class BaseClass
{
public:
virtual int id() const = 0;
};
然后你得到类来揭示它们的id并根据这些将处理这两个对象的id找到表中的处理程序。 id不必是整数,它们可以是字符串,这使得更容易避免命名冲突,这比基类的双分派方法不知道它的派生类或它们彼此了解更有优势,可扩展的。你也没必要处理每一对。