欢迎多发!本质上,您要求一种相对于多个对象的运行时类型是虚拟的方法 - 在您的情况下,两个形状的类型被测试是否重叠。
在 C++ 中实现双重调度有几种常见的方法:例如,您可以使用访问者模式,或者基于RTTI制作地图。选择其中一个由您决定。
如果您决定使用访问者模式,您可以Shape
通过添加访问方法来实现“可访问”。
这是基于访问者的方法的示例。诚然,它相当冗长,但它也解决了一项复杂的任务,因此需要大量代码是公平的。我将下面的示例剥离到最低限度——只有两个没有数据成员的形状,以及除了打印之外不做任何事情的方法。不过,这应该足以让您入门:
#include <iostream>
using namespace std;
class ShapeVisitor;
struct Shape {
virtual void accept(ShapeVisitor& v) = 0;
virtual bool overlaps(Shape& other) = 0;
};
class Circle;
class Square;
struct ShapeVisitor {
virtual void visitCircle(Circle& c) = 0;
virtual void visitSquare(Square& s) = 0;
};
// These three methods do the actual work
bool checkOverlap(Square& s, Circle& c) {
cout << "Checking if square overlaps circle" << endl;
return false;
}
bool checkOverlap(Square& a, Square& b) {
cout << "Checking if square overlaps square" << endl;
return false;
}
bool checkOverlap(Circle& a, Circle& b) {
cout << "Checking if circle overlaps circle" << endl;
return false;
}
class Square : public Shape {
struct OverlapVisitor : public ShapeVisitor {
OverlapVisitor(Square& _my) : result(false), my(_my) {}
virtual void visitCircle(Circle& c) {
result = checkOverlap(my, c);
}
virtual void visitSquare(Square& s) {
result = checkOverlap(my, s);
}
bool result;
Square& my;
};
public:
virtual void accept(ShapeVisitor& v) {
v.visitSquare(*this);
}
virtual bool overlaps(Shape& other) {
OverlapVisitor v(*this);
other.accept(v);
return v.result;
}
};
class Circle : public Shape {
struct OverlapVisitor : public ShapeVisitor {
OverlapVisitor(Circle& _my) : result(false), my(_my) {}
virtual void visitCircle(Circle& c) {
result = checkOverlap(my, c);
}
virtual void visitSquare(Square& s) {
// Important: note how I switched the order of arguments
// compared to Square::OverlapVisitor! There is only one
// square/circle overlap function checker, and it expects
// the square to be the first argument.
result = checkOverlap(s, my);
}
bool result;
Circle& my;
};
public:
virtual void accept(ShapeVisitor& v) {
v.visitCircle(*this);
}
virtual bool overlaps(Shape& other) {
OverlapVisitor v(*this);
other.accept(v);
return v.result;
}
};
这是ideone 上的运行演示。
使用 RTTI 方法,您将创建一个map<pair<type_info,type_info>,checker>
where 检查器是一种函数类型,它接受两个指向 的指针,并根据形状是否重叠Shape
返回true
或。false
您为每一对对象类型创建一个这样的函数,根据type_info
预期的参数类型使用指向这些函数的指针填充映射,并在运行时使用此映射来调用所需的函数。
《更有效的 C++ 》一书的第 31 项深入解释了这两种方法,并提供了一些很好的示例。事实上,书中讨论的用例检测一对游戏对象之间的碰撞,与您正在实施的用例相似。