【问题标题】:(SFML) Issues with inheritance (C++)(SFML) 继承问题 (C++)
【发布时间】:2021-01-04 21:07:45
【问题描述】:

所以,我正在使用 SFML,我正在尝试设置一个实体类和一个继承自它的播放器子类,但这是我第一次使用继承,我遇到了问题: 首先,我有一个 AssetManager 类,我从不同的来源拼凑而成,因为我还不太了解它们是如何工作的:

资产管理器.h:

class AssetManager {
public:
    AssetManager();
    
    static sf::Texture& LoadTexture(std::string const& path);
    static sf::SoundBuffer& LoadSoundBuffer(std::string const& path);
    static sf::Font& LoadFont(std::string const& path);

private:
    std::map<std::string, sf::Texture> m_Textures;
    std::map<std::string, sf::SoundBuffer> m_SoundBuffers;
    std::map<std::string, sf::Font> m_Fonts;

    static AssetManager* sInstance;
};

但你只需要看到与纹理相关的部分,这里是 AssetManager.cpp 中的部分:

AssetManager* AssetManager::sInstance = nullptr;

AssetManager::AssetManager() {
    assert(sInstance == nullptr);
    sInstance = this;
}

sf::Texture& AssetManager::LoadTexture(std::string const& path) {

    auto& texMap = sInstance->m_Textures;
    auto pairFound = texMap.find(path);

    if (pairFound != texMap.end()) {
        return pairFound->second;
    }
    else {
        auto& texture = texMap[path];
        texture.loadFromFile(path);
        return texture;
    }

}

然后该类的一个对象包含在Sprite 类中,这有助于为我声明精灵。

Sprite.h:

class Sprite {
public:
    AssetManager manager;
    sf::Texture m_Texture;
    sf::Sprite m_Sprite;

    sf::Vector2f sprite_scale;
    sf::Vector2u original_size;
    sf::Vector2f texture_size;

    Sprite(std::string path,sf::IntRect rect,sf::Vector2f size);
    
};

Sprite.cpp:

Sprite::Sprite(std::string path, sf::IntRect rect, sf::Vector2f size) {
    m_Texture = sf::Texture(AssetManager::LoadTexture(path));
    m_Sprite.setTextureRect(rect);
    m_Sprite.setTexture(m_Texture);

    original_size = m_Texture.getSize();

    texture_size.x = static_cast<float>(original_size.x);
    texture_size.y = static_cast<float>(original_size.y);

    sprite_scale.x = size.x / texture_size.x;
    sprite_scale.y = size.y / texture_size.y;

    m_Sprite.setScale(sf::Vector2f(sprite_scale.x, sprite_scale.y));
    m_Sprite.setOrigin(sf::Vector2f(original_size.x / 2, original_size.y / 2));

}

然后,Sprite 类的对象本身包含在 Entity 类中。

Entity.h:

class Entity {
public:
    Sprite entity_sprite;
    int health;
    float speed;
    bool collision = false;

    bool entity_collision(sf::Sprite entity2_sprite);// Entity.cpp only contains the declaration of this function so far so no need to post it.
    

};

现在,由于我不明白的原因,我无法在声明 entity_sprite 对象时直接为其分配任何参数,并且我只能在没有参数的情况下声明它,尽管类没有默认构造函数。 但是我可以使用赋值来解决它: Entity entity_sprite = Entity("res/wildcard.png", { 0,0,36,63 }, { 36,63 });

但这不是主要问题,直接使用Entity 类不是我想要做的,我正在尝试编写Player 子类并改用它:

Player.h:

class Player:public Entity {
    Player() {
        entity_sprite = Sprite("res/wildcard.png", { 0,0,36,63 }, { 36,63 });
    }
};

现在我再次无法直接将参数直接分配给对象,因为call of an object of a class type without appropriate operator() or conversion function to pointer-to-function type(如果我回到Entity 对象并在那里分配参数并假装错误没有存在,Player类产生的错误变为Too many arguments' and 'Too many initializers

这太令人困惑了。

尽管如此,我再次能够使用赋值来绕过它,与以前完全相同,只是这次我收到错误消息 the default constructor "Entity" cannot be referenced -- its a deleted function.,所以我回到 Entity 类并添加一个空构造函数像这样:Entity() { } 但是这个构造函数给了我另一个错误说no default constructor exists for class "Sprite",即使 Entity 类并不完全继承自 Sprite 类,所以我更进一步回到 Sprite 类并给它一个空的构造函数:Sprite(){},错误似乎消失了,直到我在main.cpp 文件中声明一个Player 对象并尝试编译并获得指向AssetManager.cpp 中以下行的调试错误:assert(sInstance == nullptr);

这么看似简单的任务却遇到这么多问题,我该如何摆脱困境?

【问题讨论】:

  • 即使 Entity 类并不完全继承自 Sprite 类它也不必。它有一个Sprite 类型的字段,所以它需要知道如何构造这样一个字段。您添加构造函数并没有解决任何问题,因为编译器正在删除构造函数,因为 Sprite 的潜在问题 - 所以您必须确保值持有的所有类型都是可构造的。
  • 您能否提供一个产生错误的代码示例?您在最后两段中所说的内容还不是很清楚。顺便说一句,请考虑删除警告的屏幕截图或将其移至其他问题,因为它与此问题无关,并且会使阅读更加混乱。谢谢
  • @Miguel 明白了,我已经删除了这部分问题,并添加了我自己的答案,因为我就这个问题咨询了 SFML 论坛。 en.sfml-dev.org/forums/index.php?topic=27616.0

标签: c++ visual-studio sfml


【解决方案1】:

好的,在咨询了 SFML 论坛后,我已将代码重构为以下内容:

Sprite.h:

#include "AssetManager.h"

class Sprite{
public:
    sf::Sprite m_sprite;

    sf::Vector2f sprite_scale;
    sf::Vector2u original_size;
    sf::Vector2f texture_size;

    Sprite(){}
    sf::Sprite set_sprite(sf::Texture& tx, sf::IntRect rect, sf::Vector2f size);
};

Sprite.cpp:

#include "Sprite.h"

sf::Sprite Sprite::set_sprite(sf::Texture& tx, sf::IntRect rect, sf::Vector2f size) {

    sf::Sprite spr(tx);

    spr.setTextureRect(rect);

    original_size =tx.getSize();

    texture_size.x = static_cast<float>(original_size.x);
    texture_size.y = static_cast<float>(original_size.y);

    sprite_scale.x = size.x / texture_size.x;
    sprite_scale.y = size.y / texture_size.y;

    spr.setScale(sf::Vector2f(sprite_scale.x, sprite_scale.y));
    spr.setOrigin(sf::Vector2f(original_size.x / 2, original_size.y / 2));

    return spr;
}

Entity.h:

#pragma once
#include "Sprite.h"
#include "collision.h"
#include "Timer.h"

class Entity {
public:
    Sprite spr;
    sf::Sprite entity_sprite;
    int health;
    float max_speed;
    sf::Vector2f speed;
    sf::Vector2f direction;
    float acceleration;
    bool collision = false;
    timer t;
    float acc_time;
};

Player.h:

#pragma once
#include "Entity.h"

class Player:public Entity {
public:
    Player();
    float acc_time = t.accumulate_time();
    void keyboard_controls();
    void mouse_controls(sf::Vector2f cursor);
};

Player.cpp:

#include "Player.h"
#include <math.h>


Player::Player() {
    
    speed = { 0,0 };
    acceleration = 2;
    max_speed = 500 + acceleration;
    entity_sprite = spr.set_sprite(AssetManager::LoadTexture("res/wildcard.png"), { 0,0,60,63 }, { 60,63 });
}

简而言之,Sprite 类的构造函数被替换为具有相同角色的方法,这样我就可以在 Entity 类中简单地声明一个不带参数的 Sprite 对象,我不会派生的 Player 类没有任何问题,因为不会要求我为 Sprite 和 Entity 类创建默认构造函数。

【讨论】:

    猜你喜欢
    • 2016-06-11
    • 2012-05-11
    • 2011-09-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-25
    • 2012-05-11
    • 1970-01-01
    相关资源
    最近更新 更多