从行为类中的函数访问参数 - 多态性

Posted

技术标签:

【中文标题】从行为类中的函数访问参数 - 多态性【英文标题】:Access parameter from function in behaviour class - polymorphism 【发布时间】:2020-11-19 00:02:34 【问题描述】:

我正在创建一个程序来模拟不同跑步者之间的比赛,使用行为类来实现不同类型的跑步者动作。

为此,将实现一个抽象的 MoveBehaviour 类,以及其他几个具体的子类(例如 WalkBehaviour、SleepBehaviour、SlideBehaviour)。

抽象的 MoveBehaviour 类将需要一个纯虚拟 move() 函数,并且适当的行为将在具体的子类中实现。给定跑步者的当前位置 oldPos,此 move() 函数计算跑步者的新位置 newPos,并且 move() 函数将在 log 参数中返回移动的简短文本描述(等等。“向前走 1 步”) ,将在后面的步骤中打印到屏幕上。我感觉好像我没有在这些函数中正确返回我的日志值,这与另一个问题有关。

在 Runner.cc 的 update() 函数中,我应该随机选择跑步者的下一步移动行为。这涉及 40% 时间的新步行行为、40% 时间的睡眠行为和 20% 时间的滑行行为。我应该使用新的行为对象来计算将存储在 newPos 参数中的新位置,然后我要在跑步者的当前日志数据成员中记录移动。以此类推,如果跑步者名为 Timmy,并且新的移动行为是步行,则当前日志数据成员将存储字符串“Timmy walk one step”。

回到我的日志,我不确定如何访问我在每个行为类的每个移动函数中声明的字符串。我注意到 Runner.cc 中有一个 getLog() 函数,但我觉得使用它没有意义。这让我觉得我不应该在移动类中声明“走一步”字符串等,而是在更新类中声明。

另外,我不明白如何让新的行为对象计算一个新的位置,该位置将存储在 newPos 参数中,我也希望能得到一些帮助。

为了获取日志值,我只是在下面打印跑步者的名字,我尝试将日志值中的任何内容附加到这句话中,但我不确定如何访问日志值。

如果需要,我可以包含 SleepBehaviour 和 SlideBehaviour 类,但它们实际上与 WalkBehaviour 相同,我认为只需要一个示例。

Runner.cc

void Runner::update(Position& newPos)
    int r;
    r = random(100) + 1;
    if(r <= 40) 
        WalkBehaviour* walk = new WalkBehaviour;
    else if (r <= 40)
        SleepBehaviour sleep = new SleepBehaviour;
    else
        SlideBehaviour* slide = new SlideBehaviour;
    
    cout << name << endl;
    

位置.cc

#include <iostream>
using namespace std;
#include <string>
#include "Position.h"

Position::Position(int i1, int i2) : row(i1), column(i2) 

Position::getRow() return row; 
Position::getColumn() return column; 
void Position::setRow(int r) row = r; 
void Position::setColumn(int c) column = c; 

MoveBehaviour.h

#ifndef MOVEBEHAVIOUR_H
#define MOVEBEHAVIOUR_H

#include <iostream>
#include "Position.h"
using namespace std;

class MoveBehaviour

  public:
    virtual void move(Position&, Position&, string&) = 0;
    virtual ~MoveBehaviour() = default;
;

class WalkBehaviour : public MoveBehaviour
  public:
    virtual void move(Position&, Position&, string&);
    virtual ~WalkBehaviour();
;

class SleepBehaviour : public MoveBehaviour
  public:
    virtual void move(Position&, Position&, string&);
    virtual ~SleepBehaviour();
;

class SlideBehaviour : public MoveBehaviour
  public:
    virtual void move(Position&, Position&, string&);
    virtual ~SlideBehaviour();
;

WalkBehaviour.cc

#include <iostream>
using namespace std;
#include <string>
#include "MoveBehaviour.h"

void WalkBehaviour::move(Position& oldPos, Position& newPos, string& log)  
    newPos.setColumn(oldPos.getColumn() + 1);
    newPos.setRow(oldPos.getRow());
    log = (" walked one step \n");
 

WalkBehaviour::~WalkBehaviour()

【问题讨论】:

警告:您有许多陈述,但没有明确的问题。您可能希望编辑问题以加强对唯一问题的关注。 我将我想要完成的主要任务加粗:“记录跑步者当前日志数据成员中的移动”。我想我误解了在 move 函数中返回 log 参数的含义。 旁注:如果析构函数没有注意,零规则建议您将其忽略或在标头中明确声明为默认值 (~WalkBehaviour() = default)。无需将覆盖的函数声明为虚拟函数。一个函数在基类中是虚拟的,它保持virtual,所以virtual void move(Position&amp;, Position&amp;, string&amp;); 应该是void move(Position&amp;, Position&amp;, string&amp;) override; override 关键字有助于保护应该覆盖的函数免受基类中的更改或使其过于不同的拼写错误覆盖。 【参考方案1】:

首先,您需要通过声明指向基类MoveBehaviour 对象的指针来实际使用多态性,并让该对象指向派生实例。 另外,你需要确保你不会泄漏内存,所以我选择了std::unique_ptr,它会在函数退出时自动释放。

接下来,您可以简单地为函数传递一个空的std::string 以将日志分配到,并使用std::stringstream 构造一个带有名称和移动描述的行。然后将此字符串流的输出一次性添加到log 成员中。

void Runner::update(Position& newPos) 
    int r;
    r = random(100) + 1;
    std::unique_ptr<MoveBehaviour> movement;
    if(r <= 40)  
        movement = make_unique<WalkBehaviour>();
     else if (r <= 80) 
        movement = make_unique<SleepBehaviour>();
     else 
        movement = make_unique<SlideBehaviour>();
    

    std::string moveLog;
    movement->move(currPos, newPos, moveLog);
    currPos = newPos;
   
    std::stringstream ss;
    ss << name << " " << moveLog << std::endl;
    log += ss.str();

【讨论】:

【参考方案2】:

这里:

if(r <= 40) 
    WalkBehaviour* walk = new WalkBehaviour;
else if (r <= 40)
    SleepBehaviour sleep = new SleepBehaviour;
else
    SlideBehaviour* slide = new SlideBehaviour;

你正在创造新的行为并立即泄露它们。您应该将它们分配给 RunnerMoveBehaviour* behaviour;,首先删除其旧行为:

delete behaviour;
if(r <= 40) 
    behaviour = new WalkBehaviour;
else if (r <= 40)
    behaviour = new SleepBehaviour;
else
    behaviour = new SlideBehaviour;

您的WalkBehaviour::move() 正确使用log(除非您不需要将文本文字包含在()

【讨论】:

不能解决提问者的问题,但绝对是他们需要注意的事情。 @user4581301 很好,它回答了他的一个问题:I don't understand how to get the new behaviour object to compute a new position :) 同意,但我只能投票一次。旁注:log几乎被正确使用。这是private 等一下。我读错了这些东西。忽略我对log 的吐槽。

以上是关于从行为类中的函数访问参数 - 多态性的主要内容,如果未能解决你的问题,请参考以下文章

类多态抽象接口小结

[ C++ ] 抽象类 虚函数 虚函数表 -- C++多态

3.多态性

c++中的虚函数有啥作用?

多态与转型

方法的多态中的重写