【问题标题】:Passing derived class to base function将派生类传递给基函数
【发布时间】:2015-08-20 07:26:27
【问题描述】:

我在将派生类传递给接受基类作为参数的函数时遇到问题。基类由“障碍物”组成,这些“障碍物”将被放置在“板”上 void Board::setvalue(int length, int width, Obstacle& barrier);

但是,这会导致编译器给出“no known conversion for argument...”错误。在网站上阅读时,我发现我应该将派生对象作为 const 传递,但这会导致问题,因为无法将 const 分配给电路板(因为它包含指向非 const 障碍的指针)。
反过来,将 Board 更改为持有 const Obstacles 会导致项目其他地方出现很多问题,尤其是对于 Board 和 Obstacle 的操作员 我尝试将对象作为 const 传递,然后使用 Obstacle ob = new barrier(const 障碍) 但这使它们成为通用的 Obstacle 对象而不是 Player/Barrel/Wall 对象。

有没有办法将这些对象作为非常量传递或将它们分配为非常量?我尝试使用 const_cast() 但这会导致未定义的行为。

函数调用示例:

Board_->setvalue(x, y, Player(data, moveable, x, y));

这是我的代码:

基类

class Obstacle
{
    public:
    Obstacle* _properlyinitialized;
    string Name;
    bool Moveable;
    int x;
    int y;
    Obstacle();
    Obstacle(string Name, bool Moveable, int x, int y);
    virtual ~Obstacle();
    bool properlyInitialized();
    friend std::ostream& operator<<(std::ostream& stream, Obstacle& Obstacle);
};

派生类的一个例子(其他派生类还没有特殊功能)

class Player: public Obstacle
{
public:
    Player():Obstacle(){};
    Player(string Name, bool Moveable, int x, int y):Obstacle(Name, Moveable, x, y){this->_properlyinitialized = this;};
    ~Player(){};
    /*void Moveleft();
    void Moveright();
    void Moveup();
    void Movedown();*/
};

Board 类头

class Board
{
private:
    Board* _properlyinitialized;
    int length;
    int width;
    Obstacle * * * playfield;

public:
    /*
     **ENSURE(this->properlyInitialized(),
                "Object wasn't initialized when calling object");
     */
    Board();
    Board(int length, int width);
    ~Board();
    bool properlyInitialized();
    /*
     **REQUIRE(this->properlyInitialized(),
            "Object wasn't initialized when calling properlyinitialized");
     */
    void clear();
    const int getLength();
    const int getWidth();
    Obstacle*** getBoard();
    Obstacle* getTile(int length, int width);
    void setvalue(int length, int width, Obstacle& obstacle);
    friend std::ostream& operator<<(std::ostream& stream, Board& Board);
};

std::ostream& operator<<(std::ostream& stream, Board& Board);

最后是 setvalue 函数。

void Board::setvalue(int length, int width, Obstacle& obstacle)
{
    this->playfield[length][width] = &obstacle;//value;
    return;
}

如果需要,我很乐意提供更多代码。

【问题讨论】:

  • 代码越简洁越好。
  • 我认为您需要使用指针。这使得保留原始类成为可能。
  • @davidhigh 我尝试对其进行一些清理,更好地分离部分并删除其他派生类,因为此时它们实际上是重复的。现在好看了吗?
  • @FelixNeijzen:很好,现在看起来好多了。但是对于一个真正的最小示例,您可以将所有构造函数、析构函数、不相关的 getter、setter 和数据成员放在一边(然后您可能会得到 20 行代码)。

标签: c++ inheritance pass-by-reference derived-class


【解决方案1】:

让我们直接进入你提到的例程,而不是完整的代码审查(-- 这不是 SO 的用途)

void Board::setvalue(int length, int width, Obstacle& obstacle)
{
    this->playfield[length][width] = &obstacle;
    return;
}

设置三重指针

Obstacle *** playfield;

这种设计不好有几个原因,但主要的原因是:当你想通过Board::playfield 调用它时,根本不清楚它是否还活着。没有人能确保玩家不会被长期摧毁,而您将很难记录这一事实。

相反,我建议你让董事会拥有障碍。因此,代替障碍物原始指针,设置唯一指针向量,

std::vector<std::unique<Obstacle> > playfield;

然后复制或移动类:

template<typename O>
void Board::setvalue(int length, int width, O&& obstacle)
{
    playfield.push_back(std::make_unique<O>(std::forward<O>(obstacle));
}

(我已经把场几何放在一边,我怀疑将它与障碍物的实际存储混合是否有用——但如果你仍然想要,你可以使用向量的向量或单个向量二维索引方案)。

回到你的意图:通过上述方法,你直接摆脱了所有的常量问题。你又名。 Board 拥有这些东西,可以随心所欲地使用它。

【讨论】:

  • 很好的解决方案。但是 std::make_unique 不只是 c++14 吗?编译可能有点棘手。 std::make_shared 可能足以满足他的要求。
  • @Bastyen:是的,这是一个 C++14 特性。这是 C++11 的解决方法 [stackoverflow.com/a/12580468/2412846]
  • @FelixNeijzen:是的,很明显你没有要求它。尽管如此,如果这是codereview,我还会质疑其他一些事情......比如Board* _properlyinitialized;和其他人。 (如果你有兴趣,我鼓励你去那里询问关于你的代码的问题)。
  • 不是在寻找代码审查(我希望这很清楚),还有一堆其他代码。我采用这种方法而不是向量,因为在一次处理特定项目时,向量不太容易使用。在这种情况下,我可以使用 X/Y 坐标。我也不确定如何处理空字段。不过我会尝试一下,就设计而言,它确实看起来更干净
  • _properlyinitialized 是必须包含在项目中的(这是一个大学项目),我其实也不是很喜欢它。
【解决方案2】:

这里的问题是您尝试传递一个 const 值 (Player(data, moveable, x, y)) 作为参考。你不能这样做。关于将对象存储在数组 playfield 中的事实,您应该明确地使用指针或更好的 shared_ptr 并将其存储在 std::liststd::vector 中,以避免删除问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-18
    • 1970-01-01
    • 1970-01-01
    • 2023-04-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多