设计一个以两个抽象 Base class objects 作为参数的函数,并根据 Derived class 和 objects 做不同的事情
Designing a function that takes two abstract Base class objects as arguments, and does different things based on what Derived class the objects are
==编辑 3==
最后,我只是向 Shape
添加了一个 checkIntersect(Shape)
和 checkIntersectSpecific(Circle/Polygon/Triangle)
抽象方法,并让它们调用我已经实现的免费 (non-member) 函数在一个地方,同时使用一些预处理器和 header 技巧来为自己保存一些重复代码,以防我需要添加其他子 classes。为了完成起见,我将标记 Jeffrey 的回答,因为他的回答最接近我所做的,但是我感谢你们所有人向我展示了一些我实际上不知道的很酷的东西(函数模板)并将我链接到其他 2 个问题也提出 Visitor/Double dispatch 作为解决方案。
虽然我不得不说,但我希望我们能尽快在 C++ 中看到多方法。
==编辑结束==
所以我有一个基础 class Shape
及其 children:Triangle
、Polygon
、Circle
和 Vector
和 10 个静态函数,它们采用不同对的 children 来检查它们是否相交。
我还有一个 GameObject class,它有一个 Shape*
成员,我想实现碰撞检测。出于这个原因,我需要像 bool checkIntersection(Shape*, Shape*)
这样的东西来处理任何形状。
我最初的想法是只有一个 (Shape, Shape)
函数并以某种方式检查形状的类型,然后调用适当的交集检查函数,但我读到这称为 RTTI,通常被认为是不好的。我阅读了 Visitors 和 Double dispatch,但在我看来,这些并不能真正解决我的问题。再一次,如果我错了,请随时纠正我。无论如何,现在我被困住了。我什至想不出这个标题。
EDIT2:不一定非要这样设计。我只需要在某种程度上易于维护,最好不需要更新每个 Shape subclass 如果我决定稍后添加另一个 subclass。
编辑:
澄清一下,这是我要完成的工作:
class Shape {...} //this is an abstract class
class Circle : public Shape {...}
class Triangle : public Shape {...}
class Polygon : public Shape {...}
bool checkIntersection(const Shape &s1, const Shape &s2)
{
//Do some magic and call the right function
}
bool checkIntersection(const Circle &c, const Triangle &t) {..check...}
bool checkIntersection(const Circle &c, const Polygon &p) {...check...}
//and the rest of the functions for the different combinations
class GameObject
{
Shape * shape;//Shape is abstract
bool collidesWith(const GameObject& obj)
{
return checkIntersection(*this->shape, *obj.shape);
}
}
不同的想法:使用形状枚举
enum class ShapeType{
Triangle ,
Circle
}
现在,每个形状都有 ShapeType 作为内部成员变量
class Shape{
private:
ShapeType m_ShapeType;
}
每个形状都会在其构造函数中将变量初始化为正确的类型。
现在在 Shape 中创建一个函数,其中 return ShapeType:
ShapeType getType (){
return m_ShapeType;
}
在Shape :: checkIntrsection (Shape* , Shape*)
只需将每个 Shape* return 设为类型,您就知道类型了。
另一种选择是使用模板。由于您可能必须为所有可能的 Shape 组合实现交集逻辑,因此您可以执行以下操作:
#include <iostream>
using namespace std;
struct ShapeA {};
struct ShapeB {};
struct ShapeC {};
struct ShapeD {};
template <class A, class B>
bool checkIntersection(A& a, B& b)
{
// intersection Logic (generic)
}
// you can implement specific logic for some intersections
template <>
bool checkIntersection<ShapeA,ShapeB>(ShapeA& a, ShapeB& b)
{
cout << "Intersection for ShapeA and ShapeB" << endl;
}
int main() {
// your code goes here
ShapeA a;
ShapeB b;
ShapeC c;
ShapeD d;
checkIntersection(a,b);
checkIntersection(a,a);
checkIntersection(c,b);
// and so on. The beauty here is the function guessing the input parameter types
return 0;
}
我在这种方法中看到的一些优点是:
1) 没有类型检查(没有转换,没有 switch/case 代码,遵循 Open/Close 原则)。
2) 你仍然可以将它与继承结合起来。
模板当然有缺点,在这种情况下没有灵丹妙药,但我发现在这种情况下它特别好,因为您可以让模板函数担心参数类型:)
希望对您有所帮助!
您正在尝试擦除该类型,然后再使用该类型。这没什么意义。只需使用重载。无需在此处使用基数 class:
checkIntersection(const& Triangle, const& Polygon) { ... }
checkIntersection(const& Triangle, const& Circle) { ... }
// ...
checkIntersection(const& Polygon p, const& Triangle t) {
return checkIntersection(t, p);
}
// ...
==编辑 3==
最后,我只是向 Shape
添加了一个 checkIntersect(Shape)
和 checkIntersectSpecific(Circle/Polygon/Triangle)
抽象方法,并让它们调用我已经实现的免费 (non-member) 函数在一个地方,同时使用一些预处理器和 header 技巧来为自己保存一些重复代码,以防我需要添加其他子 classes。为了完成起见,我将标记 Jeffrey 的回答,因为他的回答最接近我所做的,但是我感谢你们所有人向我展示了一些我实际上不知道的很酷的东西(函数模板)并将我链接到其他 2 个问题也提出 Visitor/Double dispatch 作为解决方案。
虽然我不得不说,但我希望我们能尽快在 C++ 中看到多方法。
==编辑结束==
所以我有一个基础 class Shape
及其 children:Triangle
、Polygon
、Circle
和 Vector
和 10 个静态函数,它们采用不同对的 children 来检查它们是否相交。
我还有一个 GameObject class,它有一个 Shape*
成员,我想实现碰撞检测。出于这个原因,我需要像 bool checkIntersection(Shape*, Shape*)
这样的东西来处理任何形状。
我最初的想法是只有一个 (Shape, Shape)
函数并以某种方式检查形状的类型,然后调用适当的交集检查函数,但我读到这称为 RTTI,通常被认为是不好的。我阅读了 Visitors 和 Double dispatch,但在我看来,这些并不能真正解决我的问题。再一次,如果我错了,请随时纠正我。无论如何,现在我被困住了。我什至想不出这个标题。
EDIT2:不一定非要这样设计。我只需要在某种程度上易于维护,最好不需要更新每个 Shape subclass 如果我决定稍后添加另一个 subclass。
编辑: 澄清一下,这是我要完成的工作:
class Shape {...} //this is an abstract class
class Circle : public Shape {...}
class Triangle : public Shape {...}
class Polygon : public Shape {...}
bool checkIntersection(const Shape &s1, const Shape &s2)
{
//Do some magic and call the right function
}
bool checkIntersection(const Circle &c, const Triangle &t) {..check...}
bool checkIntersection(const Circle &c, const Polygon &p) {...check...}
//and the rest of the functions for the different combinations
class GameObject
{
Shape * shape;//Shape is abstract
bool collidesWith(const GameObject& obj)
{
return checkIntersection(*this->shape, *obj.shape);
}
}
不同的想法:使用形状枚举
enum class ShapeType{
Triangle ,
Circle
}
现在,每个形状都有 ShapeType 作为内部成员变量
class Shape{
private:
ShapeType m_ShapeType;
}
每个形状都会在其构造函数中将变量初始化为正确的类型。
现在在 Shape 中创建一个函数,其中 return ShapeType:
ShapeType getType (){
return m_ShapeType;
}
在Shape :: checkIntrsection (Shape* , Shape*)
只需将每个 Shape* return 设为类型,您就知道类型了。
另一种选择是使用模板。由于您可能必须为所有可能的 Shape 组合实现交集逻辑,因此您可以执行以下操作:
#include <iostream>
using namespace std;
struct ShapeA {};
struct ShapeB {};
struct ShapeC {};
struct ShapeD {};
template <class A, class B>
bool checkIntersection(A& a, B& b)
{
// intersection Logic (generic)
}
// you can implement specific logic for some intersections
template <>
bool checkIntersection<ShapeA,ShapeB>(ShapeA& a, ShapeB& b)
{
cout << "Intersection for ShapeA and ShapeB" << endl;
}
int main() {
// your code goes here
ShapeA a;
ShapeB b;
ShapeC c;
ShapeD d;
checkIntersection(a,b);
checkIntersection(a,a);
checkIntersection(c,b);
// and so on. The beauty here is the function guessing the input parameter types
return 0;
}
我在这种方法中看到的一些优点是: 1) 没有类型检查(没有转换,没有 switch/case 代码,遵循 Open/Close 原则)。 2) 你仍然可以将它与继承结合起来。
模板当然有缺点,在这种情况下没有灵丹妙药,但我发现在这种情况下它特别好,因为您可以让模板函数担心参数类型:)
希望对您有所帮助!
您正在尝试擦除该类型,然后再使用该类型。这没什么意义。只需使用重载。无需在此处使用基数 class:
checkIntersection(const& Triangle, const& Polygon) { ... }
checkIntersection(const& Triangle, const& Circle) { ... }
// ...
checkIntersection(const& Polygon p, const& Triangle t) {
return checkIntersection(t, p);
}
// ...