接受子引用作为参数的父函数(或三个相互依赖类的冒险)

Parent function accepting child reference as parameter (or The Adventures of the Three Mutually Dependent Classes)

本文关键字:三个 冒险 依赖 参数 函数 引用      更新时间:2023-10-16

如果已经有人问我这个问题,我很抱歉,但我已经找了几个小时了,我只找到了类似但不完全相同的问题的答案,而这些问题在我的情况下都不起作用。我是一个新手程序员,所以我的代码很可能因为令人尴尬的设计或一个非常简单、愚蠢的错误而无法工作。我心中有一个替代设计,但我想知道这个设计是真的不可能,还是我只是错误地实现了它。

所以我要做的是:我正在编写2D碰撞检测代码,它需要同时适用于多边形和圆形。多边形需要能够检测圆和其他多边形上的碰撞,圆需要能够检测多边形和其他圆上的碰撞。我认为能够将所有可压缩对象(多边形和圆)放在一个名为"可压缩"的std::向量中会很好,而不是为每个类都有一个单独的向量。因此,我创建了抽象的Shape类,它将是Circle和Polygon的父类,并将包含虚拟碰撞检测功能。Collidables向量将是一系列Shape指针。以下是这些类的样子:

//in shape.h:
#ifndef __SHAPE_H_INCLUDED__
#define __SHAPE_H_INCLUDED__
class Polygon;
class Circle;
class Shape {
//number of functions and variables irrelevant to the issue
//relevant functions, note that Vector with capital 'V' is not std::vector but a class I wrote myself:
virtual Vector* detectCollision(const Shape& Collidable) const = 0;
virtual Vector* detectCollision(const Polygon& Collidable) const = 0;
virtual Vector* detectCollision(const Circle& Collidable) const = 0;
};
#endif

//in polygon.h
#ifndef __POLYGON_H_INCLUDED__
#define __POLYGON_H_INCLUDED__
#include "shape.h"
//edit: deleted #include "circle.h", this is now included in polygon.cpp
//edit: deleted redundant Circle forward declaration
class Polygon: public Shape {
//irrelevant stuff
Vector* detectCollision(const Shape& Collidable) const {return Collidable.detectCollision(*this)};
Vector* detectCollision(const Polygon& Collidable) const;
Vector* detectCollision(const Circle& Collidable) const;
};
#endif

//in circle.h
#ifndef __CIRCLE_H_INCLUDED__
#define __CIRCLE_H_INCLUDED__
#include "shape.h"
//edit: deleted #include "polygon.h", this is now included in circle.cpp
class Circle: public Shape {
//irrelevant stuff
Vector* detectCollision (const Shape& Collidable) const {return Collidable.detectCollision(*this);}
Vector* detectCollision (const Polygon& Collidable) const;
Vector* detectCollision (const Circle& Collidable) const;
};
#endif

这里的想法是,任何形状都应该能够检测到任何其他形状上的碰撞,甚至在调用detectCollision函数时都不知道它是在检测多边形上还是在圆上的碰撞。假设你是一个圆,并且你正在对Collidables std::向量进行迭代。第一个元素是多边形,但你不知道,你只知道你是一个圆,你的detectCollision函数得到的参数是对Shape的引用。所以你告诉Shape"看,我不知道你是什么,但我是一个圆。在这里,我会把自己作为一个参数传递给你的detectCollision函数,这样你就可以把结果返回给我"。因此,Shape调用了它的虚拟detectCollision(const&Circle),然后将其传递给它的子项Polygon的detectColliction(const&aamp;Circle,它有一个实际的工作实现,然后应该返回一个指向交叉点的指针(如果没有交叉点,则返回一个空指针)。

当只编写Shape和Polygon类时,这很好,但一旦我添加了Circle类,我的代码就不会再编译了。我得到的错误是:

在polygonal.cpp:1:0:中包含的文件中:polygon.h:在成员函数"虚拟向量*多边形::detectCollision(const Circle&)const"中:polygon。h:45:78:错误:无效使用不完整的类型"const struct Circle"shape.h:8:7:错误:"const struct Circle"的正向声明

我认为这是一个设计问题,因为这里存在大量的循环依赖:形状依赖于它的子函数,因为它的一些虚拟函数接受子函数作为参数,多边形取决于Shape(因为它从中继承)和Circle(因为它有一个接受Circle&参数的detectCollision函数),Circle取决于Shape(因为它继承)和Polygon(因为它还有一个接受Polygon&参数的detectCorsion函数)。最简单的方法可能就是放弃将多边形和圆放在一个序列容器中的想法,只将它们放在两个单独的std::向量中。尽管如此,我还是想知道我的第一个设计是天生不可能的,可能的但丑陋的,还是坚实的但实施错误的。我通常更喜欢自己找到这类东西,但经过几个小时的搜索和尝试不同的解决方案,我不得不承认,我根本不理解这个问题。

(编辑:Dave建议的一些代码更改)

编辑,链接到完整来源,如果有人想要更多信息:https://github.com/KoenP/medieval-melee-combat-cpp

我只编译polygon.cpp、circ.cpp、vector.cpp和line.cpp文件;test.cpp当前不相关。矢量和直线对于这个错误并没有那么重要,不编译它们(只编译多边形和圆)会产生完全相同的错误。我使用的确切命令是"g++-o test circle.cpp polygon.cpp line.cpp vector.cpp"。

这种设计有些常见。使其工作的方法是在标头中转发declare(而不是#include),并在cpp中转发到#include。你走在了正确的轨道上。。。

circle.hpolygon.h中,仅包括shape.h。从polygon.h中删除class Circle;(这是多余的,因为您已经从包含Shape.h中获得了它)。然后,在polygon.cpp#include "circle.h"。在circle.cpp#include "polygon.h"