Как «установить» объект для определенного базового класса в множественном наследовании? - PullRequest
0 голосов
/ 08 июня 2019

Я пытаюсь наследовать от двух базовых классов в C ++ , которые имеют одинаковые именованные функции. Я хочу, чтобы объект этого класса принадлежал определенному базовому классу, возможно ли это сделать?

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

Я хочу сделать это, просто используя один класс, если это возможно.

У меня есть код;

#include <SFML\Graphics.hpp>

class entity :public sf::CircleShape, public sf::RectangleShape {
public: 
    entity(int radius = 0) { setRadius(radius); }
    entity(sf::Vector2f size) { setSize(size); }
    float xspeed =0, yspeed =0;
};
entity ball(6);
entity block(10, 10);
window.draw(block);   // ambiguity error as both have base class sf::drawable
window.draw(ball);    // and draw function accepts sf::drawable

Проблема в том, что я хочу, чтобы "мяч" просто наследовался от sf::CircleShape, а не от sf::RectangleShape.

Я ожидал, что использование оператора разрешения области будет относиться к классу circleshape, или я могу просто использовать его неправильно.

Редактировать: проблема, которую я пытаюсь решить, состоит в том, что я хочу нарисовать "шарик" и прямоугольный блок на окне, и когда я пытаюсь это сделать, мне представляется ошибка двусмысленности, поскольку они оба отрисовка (т.е. sf::RectangleShape и sf::CircleShape наследуются от sf::drawable)

Редактировать (2): Диаграмма наследования

Таким образом, функция window.draw(); принимает любой объект sf::drawable в качестве параметра. Но поскольку я наследую и форму окружности, и форму прямоугольника, я получаю ошибку неоднозначности: base class is ambiguous.

Я знаю, что это алмазная ситуация смерти, однако использование виртуальных базовых классов невозможно, поскольку они являются частью библиотеки SFML, и я не хочу их изменять

Ответы [ 2 ]

0 голосов
/ 08 июня 2019

Анализ проблемы

class entity :public sf::CircleShape, public sf::RectangleShape

В этой декларации говорится, что каждый entity является одновременно CircleShape и RectangleShape. Это не то, что вы хотите. Вы, кажется, хотите сущность, которая может быть или кругом или прямоугольником. Так что это наследство не является правильной стратегией.

Учитывая, что вы добавляете горизонтальную и вертикальную скорости, создается впечатление, что вы пытаетесь добавить базовую анимацию к элементам, которые можно нарисовать. Анимация - это абстрактное понятие, основанное на рисовании (анимация должна быть нарисована, но не все рисунки должны быть анимированными). Определенные движущиеся фигуры будут строиться поверх анимации, поэтому ваше идеальное наследование будет больше похоже на следующее:

circle -> entity -> drawable

Однако есть несколько недостатков. Один недостаток заключается в том, что это заставляет все круги быть анимированными объектами, когда некоторые круги можно просто нарисовать в одном месте. Кроме того, классы circle и drawable взяты из библиотеки, поэтому вы не можете связываться с этой конкретной схемой наследования.

Я могу придумать две разумные альтернативы на макушке. (Кстати, «сущность» - не лучшее название для вашего класса, но я буду придерживаться его для последовательности. Вам следует придумать более описательное имя для класса. Это будет хорошая практика, именование вещей иногда является одной из самых сложных частей написания кода. :))

Сущность как базовый класс

Вы можете определить entity как базовый класс, а затем определить новый класс для каждой фигуры.

             --> sf::CircleShape --> sf::Drawable
            /
MyCircle --<
            \
             --> entity

Это может работать, но это не очень хорошо, если entity нужно вызывать функции, определенные в Drawable. Не является невозможным: приведение стороны может сделать возможным вызов функций Drawable. Просто тогда вы должны учитывать случай сбоя приведения, поскольку компилятор не может это уловить.

Фигуры в качестве членов

Что бы я, вероятно, сделал, это полностью отказаться от наследства. Вместо того, чтобы пытаться сказать, что ваша сущность является кругом (наследование), я бы придерживался подхода, согласно которому ваша сущность имеет круг (членство). Одним из преимуществ этого подхода является то, что нетрудно расширить его, сказав, что ваша сущность имеет несколько фигур, все они движутся с одинаковой скоростью. Однако сейчас я буду придерживаться одной фигуры.

Сложность этого подхода заключается в том, что вы не знаете, какую форму должен иметь объект - должен ли он иметь круг или прямоугольник? К счастью, с этим полиморфизмом хорошо справляется.

class entity {
    std::unique_ptr<sf::Drawable> shape; // <-- Polymorphism to the rescue!
    float xspeed = 0.0, yspeed = 0.0;

public:
    // Construct a circle.
    entity(int radius = 0) : shape(std::make_unique<sf::CircleShape>(radius)) {}

    // Construct a rectangle.
    entity(sf::Vector2f size) : shape(std::make_unique<sf::RectangleShape>(size)) {}

    // Something will go here to support drawing.
};

Для поддержки рисования есть (как минимум) два варианта. Если уместно иметь entity замену для Drawable, было бы разумно определить неявное преобразование.

    operator const sf::Drawable &() const { return *shape; }

Если неявное преобразование нежелательно, можно указать его explicit.

Если единственное время, когда вам нужно использовать entity в качестве Drawable, это когда вы вызываете window.draw(), вы можете вместо этого указать entity draw метод, который принимает window в качестве параметра .

    void draw(sf::RenderTarget & target, sf::RenderStates states) const
    { target.draw(*shape, states); }

Это делает Drawable доступным для RenderTarget::draw(), оставляя его вне поля зрения (уменьшение помех) в другое время.

0 голосов
/ 08 июня 2019

вместо использования наследования: enter image description here

просто используйте прямую ассоциацию:

в вашем классе сущности, вы хотите иметь RectangleShape и CircleShape, поэтому вместоДелая класс сущности CircleShape и RectangeShape одновременно, лучше рассмотреть вашу сущность, созданную из CircleShape и RectangleShape. Таким образом, вы можете в своем классе сущности создать экземпляр RectangeShape, а CircleShape означает, что «сущность» имеет Rectangle иa CircleShape

enter image description here

это правильный способ сделать это

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...