C ++成员函数无法更改专用字段

时间:2015-11-18 21:34:11

标签: c++ oop c++11 operator-overloading sdl-2

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

对于有关解决方案的请求,可以使用3种主要方式访问粒子对象。 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类中正确实现了它们(?)。

为了澄清情况,恕我直言,最好给出一些代码:

这是我的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);
        }
    }
}

2 个答案:

答案 0 :(得分:0)

对您的代码提出一些意见, 你可以把它们改成成员函数

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作为左操作数的任何操作都可以作为成员函数完成。

答案 1 :(得分:-1)

我可以看到这两个运算符正在按值计算它们的第一个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;
}

修改

这些函数也应该将它们的类args作为const referenecs:

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);