我得到了经典的Shape层次结构示例......
struct Shape { // abstract type
Shape (int x, int y);
int x;
int y;
};
struct Rectangle : public Shape {
Rectangle (int x, int y, int w, int h);
int w;
int h;
};
struct Circle : public Shape {
Circle (int x, int y, int r);
int r;
};
一个Shapes容器,填充矩形和圆圈
std::list<Shape*> container;
和打印功能(在我的情况下,这些是碰撞检测功能)
void print_types (Shape&, Shape&) {
std::cout << "Shape, Shape" << std::endl;
}
void print_types (Rectangle&, Rectangle&) {
std::cout << "Rectangle, Rectangle" << std::endl;
}
void print_types (Rectangle&, Circle&) {
...
当然,当我这样做时:
std::list<Shape*> it;
Rectangle r (0, 0, 32, 32);
for (it = container.begin(); it != container.end(); it++)
print_types(r, **it);
我不想只打印“Shape,Shape”行。我知道虚拟方法,dynamic_casts和访问者。但是,如果没有这些解决方案并保留我的外部功能,是否有任何优雅的方法可以摆脱它?
答案 0 :(得分:7)
你应该坚持使用虚函数,并且只有一个print_types函数
void print_types(Shape&)
然后将虚拟PrintName函数添加到基类并在派生类中重写它。
这是最优雅的方式。
答案 1 :(得分:4)
简短的回答是否定的,函数调用在编译时解决。所以没有办法(AFAIK)用你现有的免费功能来做这件事。
我相信你必须投资double-dispatch mechanism,或者做@Peter在答案中的建议(听起来更优雅)。
答案 2 :(得分:0)
我不能称之为优雅,它有几个陷阱,但在dynamic_cast
之前执行此操作的经典方法是virtual
函数,例如virtual char* name()
,{ {1}}并让每个派生类重写该函数以返回正确的名称。
最明显的缺陷是你必须手工维护整个事情。
答案 3 :(得分:0)
回应问题的编辑:
最好的解决方案仍然是找到一种能够提供所需要的虚拟方法。为了检测形状碰撞,也许您可以使用一个函数将每个形状转换为多边形(一组线)并对其进行检测。
C ++使用您在编译时声明的类型来选择要调用的重载函数;它没有能力在运行时进行选择。这就是为什么你每次都看到“形状,形状”作为输出。有一种方法可以帮助编译器,但这将是乏味的。尝试将每个Shape *转换为适当的类型,如果成功,则可以调用更具体的函数。
我并不是在鼓吹这个;你可以看到它只是两个形状失控,想象你添加更多的丑陋!它仍然显示了如何做你在C ++中尝试做的事情。
void print_types (Rectangle*, Rectangle*) {
std::cout << "Rectangle, Rectangle" << std::endl;
}
void print_types (Rectangle*, Circle*) {
...
void print_types (Rectangle* left, Shape* right) {
Rectangle* rightRect = dynamic_cast<Rectangle*>(right);
if (rightRect != NULL) {
print_types(left, rightRect);
return;
}
Circle* rightCirc = dynamic_cast<Circle*>(right);
if (rightCirc != NULL) {
print_types(left, rightCirc);
return;
}
throw /* something to indicate invalid shape */;
}
void print_types (Circle* left, Shape* right) {
...
void print_types (Shape* left, Shape* right) {
Rectangle* leftRect = dynamic_cast<Rectangle*>(left);
if (leftRect != NULL) {
print_types(leftRect, right);
return;
}
Circle* leftCirc = dynamic_cast<Circle*>(left);
if (leftCirc != NULL) {
print_types(leftCirc, right);
return;
}
throw /* something to indicate invalid shape */;
}