我将游戏状态(本质上是实体集合)存储在共享指针的向量中。将状态添加到向量中时,状态的派生部分将丢失,它们将还原为基本状态类。一切都可以编译,但是当我查询州名时,它们都以DEFAULT_STATE_NAME
的形式返回。我已经阅读了很多有关对象拆分的信息,但是我看不到这里出了什么问题。
State.hpp
class State {
protected:
Game &game;
public:
typedef shared_ptr<State> Pointer;
static const StateName name = DEFAULT_STATE_NAME;
explicit State(Game &game_) : game(game_) ;
virtual ~State() {}
};
派生状态类示例
namespace {
class Overworld : public State {
public:
static const StateName name;
Overworld(Game &game) : State(game) {}
};
const StateName Overworld::name = OVERWORLD;
}
Game.hpp
class Game {
private:
vector<State::Pointer> states;
public:
void addState(const State::Pointer &state) {
if(!state)
throw "invalid state error";
states.push_back(state);
}
// ...
}
答案 0 :(得分:2)
要通过指向基类的指针(或引用)访问派生类的成员方法,您必须必须使用多态性(不是) 。例如
struct Base {
virtual string name() const { return "Base"; }
};
struct Derived : Base {
string name() const override { return "Derived"; }
};
const Base*ptr = new Derived;
assert(ptr->name()=="Derived");
这种多态性仅适用于非静态成员方法,不适用于数据成员或静态成员函数。在您的情况下,没有多态性,因此Base::name
仍然是Base::name
。
在您的特定情况下,还有其他两种可能的解决方案。首先,您可以使用RTTI,尽管通常对此并不满意。另一种选择是将name
保留为Base
中的数据成员并在构造时将其传递:
struct Base {
const string name = "Base";
Base() = default;
protected:
Base(string const&n)
: name(n) {}
};
struct Derived : Base {
Derived()
: Base("Derived") {}
};
const Base*ptr = new Derived;
assert(ptr->name=="Derived");
不涉及多态性(因此不涉及虚拟表和其他间接访问)时,但以数据成员name
为代价。
答案 1 :(得分:0)
name
中的 State
和name
中的Overworld
是两个完全独立的类变量。它们不是任何实例状态的一部分,也不能直接向实例查询类变量,因为它们不能为virtual
。为了多态访问类变量,您需要使用虚函数。
将这样的成员函数添加到State
中,不要忘记根据需要在派生类中重写它。或者,您知道,您可以只使用typeid
语言标准的RTTI。