(SFML) 继承问题 (C++)
(SFML) Issues with inheritance (C++)
所以,我正在使用 SFML,我正在尝试设置一个实体 class 和一个从它继承的玩家子 class,但这是我第一次使用继承我有问题:
首先,我有一个 AssetManager class,它是我从不同来源拼凑而成的,因为我还不太了解它们是如何工作的:
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;
}
}
然后 class 的对象包含在 Sprite
class 中,这有助于为我声明精灵。
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
class 的对象本身包含在 Entity
class.
中
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
对象时直接将任何参数分配给它,我只能在没有参数的情况下声明它,尽管 class 没有默认构造函数。
但是我可以使用赋值来解决它:
Entity entity_sprite = Entity("res/wildcard.png", { 0,0,36,63 }, { 36,63 });
但这不是主要问题,直接使用 Entity
class 不是我想要做的,我正在尝试编写 Player
sub-class 并改用它:
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
class 产生的错误更改为 Too many arguments' and 'Too many initializers
这太令人困惑了。
尽管如此,我又一次能够使用赋值来绕过它,和以前完全一样,除了这次我得到一个错误 the default constructor "Entity" cannot be referenced -- its a deleted function.
,所以我回到 Entity
class 并添加一个像这样的空构造函数:Entity() { }
但是此构造函数又给我另一个错误提示 no default constructor exists for class "Sprite"
,即使实体 class 并不完全继承自 Sprite class,所以我进一步回到 Sprite class 并给它一个空的构造函数:Sprite(){}
,错误似乎消失了,直到我声明一个 Player
main.cpp
文件中的对象并尝试编译并获取指向 AssetManager.cpp
中以下行的调试错误:assert(sInstance == nullptr);
看似简单的任务却有这么多问题,我该如何摆脱困境?
好的,在查阅了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
class' 构造函数被替换为具有完全相同作用的方法,这样我就可以简单地声明一个没有参数的 Sprite
对象Entity
class,派生的 Player
class 不会有任何问题,因为我不会被要求为 Sprite 和 Entity 创建默认构造函数classes.
所以,我正在使用 SFML,我正在尝试设置一个实体 class 和一个从它继承的玩家子 class,但这是我第一次使用继承我有问题: 首先,我有一个 AssetManager class,它是我从不同来源拼凑而成的,因为我还不太了解它们是如何工作的:
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;
}
}
然后 class 的对象包含在 Sprite
class 中,这有助于为我声明精灵。
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
class 的对象本身包含在 Entity
class.
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
对象时直接将任何参数分配给它,我只能在没有参数的情况下声明它,尽管 class 没有默认构造函数。
但是我可以使用赋值来解决它:
Entity entity_sprite = Entity("res/wildcard.png", { 0,0,36,63 }, { 36,63 });
但这不是主要问题,直接使用 Entity
class 不是我想要做的,我正在尝试编写 Player
sub-class 并改用它:
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
class 产生的错误更改为 Too many arguments' and 'Too many initializers
这太令人困惑了。
尽管如此,我又一次能够使用赋值来绕过它,和以前完全一样,除了这次我得到一个错误 the default constructor "Entity" cannot be referenced -- its a deleted function.
,所以我回到 Entity
class 并添加一个像这样的空构造函数:Entity() { }
但是此构造函数又给我另一个错误提示 no default constructor exists for class "Sprite"
,即使实体 class 并不完全继承自 Sprite class,所以我进一步回到 Sprite class 并给它一个空的构造函数:Sprite(){}
,错误似乎消失了,直到我声明一个 Player
main.cpp
文件中的对象并尝试编译并获取指向 AssetManager.cpp
中以下行的调试错误:assert(sInstance == nullptr);
看似简单的任务却有这么多问题,我该如何摆脱困境?
好的,在查阅了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
class' 构造函数被替换为具有完全相同作用的方法,这样我就可以简单地声明一个没有参数的 Sprite
对象Entity
class,派生的 Player
class 不会有任何问题,因为我不会被要求为 Sprite 和 Entity 创建默认构造函数classes.