C++成员函数无法更改私有字段

C++ Member Function Cannot Change Private Field

本文关键字:字段 成员 函数 C++      更新时间:2023-10-16

OH!我发现了问题。正如我最后所说,这是一个简单的问题。在for循环中,我迭代了"粒子"的副本。我更新了它们,但操作不会影响存储在矢量中的原始值。

对于有关解决方案的请求,可以使用三种主要方式访问粒子对象。lvalue-ref对象方式:

for (auto& p: particles)
    ...

或者通过迭代器:

for (auto it=particles.begin(); i<particles.end();++it)
    ...

或者通过简单索引:

for (size_t i=0; i<particles.size(); ++i)
    ...

对于那些对代码感兴趣的人,你可以看看下面:


如果我没有错过一些非常明显的东西,我会遇到一个非常奇怪的问题。

为了简化这个问题,我有一个名为"Particle"的类,它有一个叫做"update"的函数。粒子类有一些私有变量,如位置、速度等。更新函数应该进行一些计算,并为这些私有变量添加适当的值。但是,这根本不起作用。

事实上,我对变量的类型持怀疑态度,这是我写的一个类,"Vector2"。

为了给变量添加值,我使用了"+="运算符,我认为我在Vector2类中正确地实现了它们(?)。

为了澄清情况,IMHO,最好给出一些代码:

这是我的Vector2.h:

namespace sim {
#include <ostream>
#include <cmath>
using namespace std;
struct Vector2 {
    double x, y;
    Vector2& operator+=(const Vector2& rhs) {
        this->x += rhs.x;
        this->y += rhs.y;
        cout << "op+=" << endl;
        return *this;
    }
    Vector2& operator*=(double k) {
        x *= k;
        y *= k;
        cout << "op*=" << endl;
        return *this;
    }
    friend ostream& operator<<(ostream& os, const Vector2& v2);
    friend Vector2 operator+(Vector2 lhs, const Vector2& rhs);
    friend Vector2 operator-(Vector2 lhs, const Vector2& rhs);
    friend Vector2 operator*(Vector2 lhs, double k);
    friend Vector2 operator*(double k, Vector2 rhs);
};
ostream& operator<<(ostream& os, const Vector2& v2) {
    os << "[ " << v2.x << "; " << v2.y << " ]";
    return os;
}
Vector2 operator+(Vector2 lhs, const Vector2& rhs) {
    lhs += rhs;
    cout << "op+" << endl;
    return lhs;
}
Vector2 operator*(Vector2 lhs, double k) {
    lhs *= k;
    cout << "op*" << endl;
    return lhs;
}

(删除了一些不相关的部分,如构造函数)

这是粒子类:

class Particle {
private:
    Vector2 pos;
    Vector2 vel;
    Vector2 acc;
    double rad;
    SDL_Color clr;
public:
    Particle(
            Vector2 _p,
            Vector2 _v,
            Vector2 _a,
            double _r = 10.0,
            SDL_Color _c = { 255, 255, 255, 255 }) {
        pos = _p;
        vel = _v;
        acc = _a;
        rad = _r;
        clr = _c;
    }
    Vector2& move_particle(Vector2 move_by) {
        return (pos += move_by);
    }
    void update(double dt) {
        this->vel += acc * dt;
        this->pos += vel * dt;
        cout << "update " << pos << vel << acc << endl;
    }
    void render(SDL_Renderer* renderer) {
        // TODO: this was supposed to be a circle, but, who cares? ;)
        SDL_Rect r = { int(pos.x), int(pos.y), int(rad), int(rad) };
        SDL_RenderFillRect(renderer, &r);
        cout << "render" << endl;
    }
};

结果是:更新不会更新。

我怎么知道(猜测)我的过载是否有效

对于3个Vector2对象,我可以执行我正确定义的任何类型的操作。结果正是他们所期望的。(或者,也许不是?)

但调试更新函数大致让我明白,实际上+=运算符只工作一次,不会再工作了,但这种行为只在更新函数中表现出来。

我知道,这将是一个如此简单的错误,我可能会感到羞愧(只是开玩笑)。

哦,当然还有主要代码:

int main() {
    SDL_Init(SDL_INIT_EVERYTHING);
    auto window = SDL_CreateWindow("My Very First Particle Simulation", -1, -1,
            1024, 768, SDL_WINDOW_SHOWN);
    auto renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
    const Vector2 g(0.0, 9.8);
    double dt = 0.1;
    std::vector<Particle> particles;
    bool quit = false;
    while (!quit) {
        SDL_Event event;
        while (SDL_PollEvent(&event)) {
            switch (event.type) {
            case SDL_QUIT:
                quit = true;
                break;
            case SDL_MOUSEBUTTONUP:
                particles.emplace_back(Vector2(event.button.x, event.button.y), Vector2(1.0, 0.0), g);
                break;
            default:
                break;
            }
            SDL_RenderClear(renderer);
            for (auto p : particles) {
                p.update(dt);
                p.render(renderer);
            }
            SDL_RenderPresent(renderer);
        }
    }
}

对代码的一些评论,你可以将这些更改为会员功能

friend Vector2 operator+(Vector2 lhs, const Vector2& rhs);
friend Vector2 operator-(Vector2 lhs, const Vector2& rhs);
friend Vector2 operator*(Vector2 lhs, double k);
friend Vector2 operator*(double k, Vector2 lhs);

Vector2 operator+(const Vector2& rhs);
Vector2 operator-(const Vector2& rhs);
Vector2 operator*(const double k);
friend Vector2 operator*(const double k, Vector2 lhs);

在它们中,将this复制到新的Vector2,然后更新值并返回。第四个函数是作为朋友保存的,这样你就可以拥有类似double*Vector2的东西,而第三个函数则负责Vector2*double

任何将Vector2作为左操作数的操作都可以作为成员函数执行。

我可以看到这两个运算符正在按值获取它们的第一个args。更改它们,以便通过引用获取它们的参数。

Vector2 operator+(Vector2 lhs, const Vector2& rhs) { // lhs should be a const reference
    lhs += rhs;
    cout << "op+" << endl;
    return lhs;
}
Vector2 operator*(Vector2 lhs, double k) { // lhs should be a const reference
    lhs *= k;
    cout << "op*" << endl;
    return lhs;
}

编辑:

此外,这些函数应该将其类参数作为const引用:

friend Vector2 operator+(Vector2 lhs, const Vector2& rhs);
friend Vector2 operator-(Vector2 lhs, const Vector2& rhs);
friend Vector2 operator*(Vector2 lhs, double k);
friend Vector2 operator*(double k, Vector2 rhs);