如何访问存储在其基类指针向量中的子对象的接口函数?

问题描述 投票:0回答:1

我想要完成什么:我希望能够循环遍历基类向量并引用子类上的接口。

我现在在哪里:我正在为一个拥有游戏对象的游戏创建一个系统,您可以通过添加组件来向游戏对象添加功能。

我创建了一个包含组件列表的 GameObject 类。该类循环遍历所有组件并调用组件上的三个函数:

handleInput()
update()
draw()

GameObject.h

#include "IInitialize.h"
#include "IInput.h"
#include "IUpdate.h"
#include "IDraw.h"
#include "TransformComponent.h"

class Component;
class GameObject : public IInitialize, IInput, IUpdate, IDraw
{
public:
    TransformComponent transform;

    GameObject();
    void addComponent(Component* component);

    bool IInitialize::initialize()
    {
        return true;
    }

    void IInput::handleInput(sf::RenderWindow* window, sf::Event* event)
    {
        for (auto it = components.begin(); it != components.end(); it++)
        {
            IInput* component = dynamic_cast<IInput*>(*it);

            if (component != nullptr)
            {
                component->handleInput(window, event);
            }
        }
    }

    void IUpdate::update(float deltaTime)
    {
        for (auto it = components.begin(); it != components.end(); it++)
        {
            IUpdate* component = dynamic_cast<IUpdate*>(*it);

            if (component != nullptr)
            {
                component.update(deltaTime);
            }
        }
    }
    
    void IDraw::draw(sf::RenderWindow* window)
    {
        for (auto it = components.begin(); it != components.end(); it++)
        {
            IDraw* component = dynamic_cast<IDraw*>(*it);

            if (component != nullptr)
            {
                component.draw(window);
            }
        }
    }

private:
    std::vector<Component*> components;
};

游戏对象.cpp

#include "GameObject.h"

GameObject::GameObject() 
{
    transform = TransformComponent();
    transform.position = sf::Vector2f(960, 540);
}

void GameObject::addComponent(Component* component)
{
    component->parent = this;
    components.push_back(std::move(component));
}

handleInput()
update()
draw()
函数中,我尝试从组件中获取接口来调用它们。

Component 基类不实现接口,但 Component 基类的子类实现。

组件.h

#include "IInitialize.h"

class GameObject;
class Component : public IInitialize
{
public:
    GameObject* parent;

    Component();

    virtual bool IInitialize:: initialize()
    {
        return true;
    }
};

TextComponent.h

#include "Component.h"
#include "IUpdate.h"
#include "IDraw.h"

class TextComponent : public Component, IUpdate, IDraw
{
public:
    std::string text = "Text";
    sf::Color color = sf::Color::White;
    int size = 25;

    TextComponent(std::string text = "Text", sf::Color color = sf::Color::White, int size = 25);

    void setPosition();

    bool IInitialize::initialize() override
    {
        if (!_font.loadFromFile(_fontPath))
        {
            return false;
        }

        return true;
    }

    void IUpdate::update(float deltaTime)
    {
        _text.setString(text);
        _text.setFillColor(color);
        _text.setCharacterSize(size);
        setOrigin();
        setTextPosition();
    }

    void IDraw::draw(sf::RenderWindow* window)
    {
        window->draw(_text);
    }

private:
    sf::Font _font;
    sf::Text _text;

    std::string _fontPath = "Assets/Fonts/accidental_presidency.ttf";

    void setOrigin();
};

我的问题:我的问题是我存储在组件向量中的对象是从 Component 类派生的子类。我认为发生对象切片是因为基组件类没有实现任何接口,并且当 GameObject 尝试将组件类转换为

IInput
IUpdate
IDraw
时,它会失败,因为基类没有实现不实现这些接口。

我尝试过的:

  1. 我考虑过尝试将组件向下转换为正确的类型以获得接口,但这需要游戏对象了解不同类型的组件,并且我不确定它是否需要了解它们。它还需要我在每次创建新组件时更新 GameObject 类。

  2. 我尝试创建一个始终从接口派生的中间人类。这限制了接口的使用,并使得有时某个函数因为组件不需要使用它而未被使用。

  3. 我已将接口添加到基类中,并在子类中重写它们。这也导致有时有些接口功能无法使用。我的目标是只将接口添加到需要使用它们的对象中。

我的问题:如何设计架构,以便我可以在子对象上使用接口,而不必向游戏对象提供太多有关组件类型的信息?

c++ game-development sfml game-programming
1个回答
0
投票

详细说明@user4581301的评论,并解答您的疑虑:

这也导致有时有些接口功能无法使用。我的目标是只将接口添加到需要使用它们的对象中。

您可以将接口定义为

pure virtual
并在基类中提供默认实现(它可以不执行任何操作,或记录某些内容等)。

请参阅带有实现的纯虚函数了解更多详细信息。

© www.soinside.com 2019 - 2024. All rights reserved.