【问题标题】:Class method being called in main, changes don't persist outside class method?在main中调用类方法,更改不会在类方法之外持续存在?
【发布时间】:2023-04-05 21:23:02
【问题描述】:

基本上,我有两个类,Peg 和 Disk。 (这是一个河内塔程序)我拥有的文件是 Disk.h、Disk.cpp、Peg.h、Peg.cpp 和 main.cpp。不确定这是否重要。这是 Disk.h 中的磁盘类

#include <vector>
#include "gwindow.h"
#ifndef DISK_H
#define DISK_H

class Disk
{
private:
    int xCoord; //x and y coords are for drawing in a gwindow
    int yCoord;
    int mHeight;
    int mWidth;
    COLOR mColor;
    int mName;  //helps me keep track of which is which

public:
    Disk(); //default constructor
    Disk(int x, int y, int heightIn, int widthIn, COLOR colorIn);
    void setXY(int x, int y); //this is the one I'm having trouble with
    int getHeight();
    int getWidth();
    int getX();
    int getY();
    COLOR getColor();
    std::string diskColor();
    void draw(GWindow &gw);
    void nameDisk(int name);  //yet this one is working?
    int getName();
};

#endif

但是,我在使用 setXY 函数时遇到了问题。当我从 main 调用它时,它会正确调用函数,在 setXY 范围内更改变量,但该值不会在函数之外持续存在。然而,nameDisk 工作正常并且基本上是一样的,只是它改变的是 mName 而不是 xCoord 和 yCoord。这里是setXY:

void Disk::setXY(int x, int y)
{
    xCoord = x;
    yCoord= y;
}

这是我从 main 中调用它的方式:

pegVec[2].getDisks()[0].setXY(690, 200);

我知道这看起来很疯狂,但基本上 pegVec 是 3 个 peg 对象的向量。每个 peg 对象都有一个函数 getDisks(),它返回当前 peg 上所有磁盘的向量。因此,上面的行试图在第 2 根钉子上的第一个钉子上执行 setXY。抱歉,如果不清楚,但我已经尝试制作一个新的磁盘对象并在其上调用它,但也没有用。

这里是 getDisks,如果重要的话:

std::vector<Disk> Peg::getDisks()
{
    return disksOn;
}

disksOn 只是 Peg 的一个成员变量:

std::vector<Disk> disksOn;

我认为 getDisks() 的工作方式可能存在问题。我是菜鸟,但我猜返回向量 disksOn 会对其进行“复制”,有点像我用 setXY 函数更改的内容,但与关联的实际 disksOn 向量不同Peg 对象?我不知道这是否有意义。

到目前为止我已经尝试过:

  • 制作 xCoord 和 yCoord 公共变量并手动更新它们,而不是制作 setter 函数。这不起作用。
  • 我在每一步都打印出 x 和 y 值。在 setXY 内部,值已成功更新,但当函数结束时,它们又回到原来的状态。
  • 我尝试将 const 关键字弄得乱七八糟,但我不理解它,甚至无法让它运行。
  • 通过引用/值传递所有内容
  • 在 main 中创建一个接受磁盘向量作为输入的新函数,并使用 getDisks 作为该函数的输入。没用,同样的问题。
  • 测试了我的另一个setter 函数nameDisk,它工作正常。它本质上与 setXY 相同,这就是为什么我认为问题出在 getDisks 的原因。
  • 自始至终在不同点使用指针(呵呵),但我不确定最好的方法。我昨晚搞砸了,所以我不记得 100%,但我想我试图让 getDisks 返回一个指针而不是向量,我认为这不起作用,但这更有可能是我的语法问题和我如何使用指针。我认为这可能行得通,但我不知道如何动摇它。

帮助?

【问题讨论】:

    标签: c++ class vector methods setter


    【解决方案1】:

    您在正确的轨道上 - 不知何故,您看到的对象与您认为的对象不同。使用引用是一个很好的解决方案,但您可能没有找到正确的解决方案;-)

    试试:

    // Return reference to the disks on the peg.
    std::vector<Disk>& Peg::getDisks()
    {
        return disksOn;
    }
    

    【讨论】:

    • 啊,成功了!太感谢了。我记得昨晚尝试过,但我做得比必要的复杂。
    【解决方案2】:

    问题是 std::vector&lt;Disk&gt; getDisks() { return disksOn; } 返回 disksOn 的全新且单独的临时副本,而不是对原始文件的引用。因此,您正在修改一个临时副本,该副本在语句末尾被丢弃。

    你需要使用 std::vector&lt;Disk&gt; &amp;getDisks() { return disksOn; } 以便将 reference 返回到 disksOn。

    尽管如果您要返回对向量成员对象的引用,您最好将该对象作为公共对象直接访问,因为此时任何人都可以操作该向量并摆脱 getDisks() 函数,因为它没有任何作用访问保护方面的目的。

    更好的设计是提供对单个磁盘的访问权限:

    Disk &getDisk(int index) { 
      return disksOn[index]; 
    }
    
    const Disk &getDisk(int index) const { 
      return disksOn[index]; 
    }
    

    不直接访问向量背后的想法是,您可以稍后根据需要更改底层容器类型,而无需更改 Peg 类之外的代码。

    第二个版本 (const) 是访问 const Peg 对象的 const Disks 所必需的。

    【讨论】:

    • 感谢您的回答。您能否解释一下 const Disk 对象和常规 Disk 对象之间的区别是什么? const Disk 对象是不可变的吗?
    • 简单地说:是的。 const 对象是您无法直接更改且只能在其上调用 const 成员函数的对象。然而,它可以通过对同一对象使用不同的非常量指针或非常量引用来更改,并且某些函数可能会通过执行 const_cast&lt;&gt;() 导致它发生更改,这对于例如实现 reference 是必要的-counted 对象 作为引用计数需要更新,即使该对象在概念上被称为 const。所以要学究起来,它并不是严格不可变的。
    • 例如 int a = 5; const int &amp;const_ref_a = a; cout &lt;&lt; const_ref_a &lt;&lt; "\n"; a = 10; cout &lt;&lt; const_ref_a &lt;&lt; "\n"; 即使 const_ref_a 是对 a 的 const 引用,对象 a 也可以更改。但是const_ref_a = 20; 会产生编译错误。你必须看到一个 const 引用或指针来表达“我不打算使用这个引用(或指针)来改变值,编译器请告诉我如果我不小心做了”而不是“这个值永远不会改变”,因为在非常复杂的系统中你可能会得到惊喜。
    • 感谢您的解释,这真的很有帮助 - 我现在明白为什么在某些情况下这会是一个有用的结构。
    猜你喜欢
    • 2020-05-27
    • 1970-01-01
    • 2014-03-05
    • 2012-06-25
    • 1970-01-01
    • 2017-01-11
    • 2016-02-06
    • 1970-01-01
    • 2021-03-30
    相关资源
    最近更新 更多