如果派生类作为基类返回,如何访问派生类的方法?
Posted
技术标签:
【中文标题】如果派生类作为基类返回,如何访问派生类的方法?【英文标题】: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 (***.com/help/mcve) 以便我们可以真正看到您编写的代码,而不是从您的描述中猜测。
【参考方案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
并在使用前检查结果是否为空以上是关于如果派生类作为基类返回,如何访问派生类的方法?的主要内容,如果未能解决你的问题,请参考以下文章