Родительская функция, принимающая дочернюю ссылку в качестве параметра (или «Приключения трех взаимозависимых классов»)

Извините, если этот вопрос уже задавался, но я искал несколько часов и нахожу ответы только на похожие, но не совсем те же проблемы, и ни одна из них не работает в моем случае. Я начинающий программист, так что, скорее всего, мой код не работает из-за неуместного дизайна или из-за очень простой, глупой ошибки. Я имею в виду альтернативный дизайн, но я хотел бы знать, является ли проект буквально невозможным или я просто неправильно его реализую.

Итак, вот что я пытаюсь сделать: я пишу двумерный код обнаружения столкновений, который должен работать как для многоугольников, так и для кругов. Полигоны должны быть способны обнаруживать столкновения на окружностях и других многоугольниках, а круги должны быть способны обнаруживать столкновения на многоугольниках и других окружностях. Я подумал, что было бы неплохо иметь возможность поместить все встречные объекты (многоугольники и окружности) в один std :: vector, называемый «Collidables», вместо того, чтобы иметь отдельный вектор для каждого класса. Поэтому я создал абстрактный класс 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. Представьте, что вы круг и перебираете Stl :: vector Collidables. Первый элемент — это Polygon, но вы этого не знаете, вы только знаете, что вы круг, и что параметр, который получает ваша функция detectCollision, является ссылкой на Shape. Итак, вы говорите Shape: «Послушайте, я не знаю, кто вы, но я круг. Здесь я передам себя в качестве параметра вашей функции detectCollision, чтобы вы могли вернуть мне результат». Таким образом, Shape получает свой виртуальный deteCollision (const &Circle) вызывается, который затем передается на detectCollision (const &Circle) его потомка, Polygon, который имеет фактическую рабочую реализацию и который затем должен возвращать указатель на точку пересечения (или нулевой указатель, если пересечения нет).

Это работало нормально, когда были написаны только классы Shape и Polygon, но как только я добавил класс Circle, мой код больше не компилировался. Я получаю ошибку:

В файле из polygon.cpp: 1: 0:
polygon.h: В функции-члене ‘виртуальный вектор * Polygon :: detectCollision (const Circle&) const ’:
polygon.h: 45: 78: ошибка: недопустимое использование неполного типа «const struct Circle»
shape.h: 8: 7: ошибка: предварительное объявление константной структуры Circle

Я предполагаю, что это проблема проектирования из-за нелепого количества циклической зависимости, происходящей здесь: Shape зависит от своих потомков, потому что некоторые из его виртуальных функций принимают потомков в качестве параметра, Polygon зависит от Shape (потому что он наследует от него) и Circle (потому что у него есть функция detectCollision, принимающая круг& Параметр) и Circle зависит от Shape (потому что он наследуется от него) и Polygon (потому что у него есть функция detectCollision, принимающая Polygon& параметр). Самый простой выход, вероятно, состоит в том, чтобы просто отказаться от идеи помещения многоугольников и окружностей в один контейнер последовательности и просто поместить их в два отдельных std :: vectors. Тем не менее, я хотел бы знать, является ли мой первый дизайн просто изначально невозможным, возможным, но уродливым или твердым, но неправильно реализованным. Я обычно предпочитаю находить подобные вещи самостоятельно, но после нескольких часов поиска и проб разных решений, я должен признать, что просто не понимаю эту проблему.

(редактировать: некоторые изменения кода, предложенные Дейвом)

РЕДАКТИРОВАТЬ, ссылку на полный источник, если кто-то хочет получить больше информации: https://github.com/KoenP/medieval-melee-combat-cpp

Я только компилирую файлы polygon.cpp, circle.cpp, vector.cpp и line.cpp; test.cpp в настоящее время не имеет значения. Не то, чтобы вектор и линия имели большое значение для этой ошибки, их не компилирование (только компиляция многоугольника и круга) дает точно такую ​​же ошибку. Точная команда, которую я использую: «g ++ -o test circle.cpp polygon.cpp line.cpp vector.cpp».

0

Решение

Такой дизайн довольно распространен. Способ заставить это работать, состоит в том, чтобы объявить в заголовках (не #include) и к #include в cpps. Вы были на правильном пути …

В circle.h а также polygon.h включают только shape.h, Удалить class Circle; от polygon.h (это избыточно, так как вы уже получили его от Shape.h). Затем в polygon.cpp, #include "circle.h", И в circle.cpp, #include "polygon.h",

1

Другие решения

Других решений пока нет …