【问题标题】:How can I access a derived class' methods if it is returned as the base class?如果派生类作为基类返回,如何访问派生类的方法?
【发布时间】:2019-02-07 02:46:14
【问题描述】:

我正在创建一个允许您将状态添加到堆栈中的状态机。以下是它包含的几个方法:

void pushState(State* state);

State* getCurrentState();

State 只是一个用于创建派生类的基类。所以我创建了一个名为GameState 的派生类,它有一个名为foo 的独特方法。如果我执行以下操作,它不会让我访问 foo,因为“类 State 不存在名为 'foo' 的方法。

State* currentState = myStateMachine.getCurrentState();

我也尝试将State* 更改为GameState*,但它不起作用,因为getCurrentState() 返回类型State。当我实际上不知道当前的派生状态是什么时,如何获取堆栈上的当前状态?

我也不知道为什么它允许我将GameState 推送到期待State 的堆栈上,但不允许我将它作为GameState 检索。相反,它让我在State 检索它。

【问题讨论】:

  • 你如何从State 导出GameState?您是否使用了virtual 关键字?
  • @thb 我刚刚做了class GameState : public State
  • 您是否在 C++ 书籍中阅读过如何创建虚函数?
  • 创建一个 MCVE (stackoverflow.com/help/mcve) 以便我们可以真正看到您编写的代码,而不是从您的描述中猜测。

标签: c++ class oop


【解决方案1】:

试试这个:

#include <iostream>

namespace {
    class State {
    public:
        virtual int foo() const = 0;
    };
    class GameState : public State {
    public:
        int foo() const { return 5; }
    };
}

int main() {
    const GameState s{};
    std::cout << s.foo() << "\n";
    const State *const p = &s;
    std::cout << p->foo() << "\n";
    return 0;
}

对于GameState要替换C++中State的方法foo(),该方法必须是虚的。原因是,默认情况下,为了提高效率,C++ 编译器会在编译时计算foo() 的地址。 virtual 关键字通过指向列出GameState 类型的虚方法的结构的指针来间接寻址。

您的问题是,除非foo() 是虚拟的,否则您的计算机无法在运行时判断State * 对象是指向State 对象还是GameState 对象。

但是,如果foo() 是虚拟的,那么包括GameState 对象在内的每个State 对象都包含一个指向隐藏vtable 的指针。State 类型 em> 有一个 vtable。 GameState 类型有另一个 vtable。 每个 vtable 引用正确的函数 foo()

[示例中的= 0 顺便通知编译器不会为State 对象提供任何实际函数foo()。您可以在代码中省略= 0,如果愿意,可以提供State::foo()。]

【讨论】:

    【解决方案2】:

    您应该将类​​型 State* 转换为 GameState*

    我的意思是:

    State* currentState = myStateMachine.getCurrentState();
    

    应该是

    // if State class don't have any virtual method, you should use static_cast<>
    GameState* currentState = static_cast<GameState*>(myStateMachine.getCurrentState());
    

    // if State class has at least virtual method, you should use dynamic_cast<>
    GameState* currentState = dynamic_cast<GameState*>(myStateMachine.getCurrentState());
    

    会有用的

    【讨论】:

    • Ofc 你应该不喜欢 c 风格的演员表,而是写正确的演员表,如果getCurrentState 改变它的回报或GameState 停止继承State 将节省麻烦
    • 使用dynamic_cast并在使用前检查结果是否为空
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-28
    • 2020-02-11
    • 1970-01-01
    • 1970-01-01
    • 2018-11-03
    • 2017-09-30
    相关资源
    最近更新 更多