我该如何重载 C++运营商允许链接吗?

发布于 2024-08-29 23:51:47 字数 2724 浏览 4 评论 0原文

我和我之前的许多程序员一样,正在抓紧时间编写 C++ 中的通过权矩阵类。我从来没有做过非常严重的运算符重载,这导致了问题。本质上,通过单步执行

这就是我所说的导致问题的原因。

    cMatrix Kev = CT::cMatrix::GetUnitMatrix(4, true);
    Kev *= 4.0f;
    cMatrix Baz = Kev;
    Kev = Kev+Baz;  //HERE!

根据调试器的说法,似乎发生的情况是添加了 Kev 和 Baz,但随后该值丢失了,当重新分配给 Kev 时,内存只是其默认的危险值。如何重载我的运算符以允许此语句? 我的(精简的)代码如下。

//header
class cMatrix
{
private:
    float* _internal;
    UInt32 _r;
    UInt32 _c;
    bool _zeroindexed;

    //fast, assumes zero index, no safety checks
    float cMatrix::_getelement(UInt32 r, UInt32 c)
    {
        return _internal[(r*this->_c)+c];
    }

    void cMatrix::_setelement(UInt32 r, UInt32 c, float Value)
    {
        _internal[(r*this->_c)+c] = Value;
    }

public:
    cMatrix(UInt32 r, UInt32 c, bool IsZeroIndexed);
    cMatrix( cMatrix& m);
    ~cMatrix(void);

    //operators
    cMatrix& operator + (cMatrix m);
    cMatrix& operator += (cMatrix m);
    cMatrix& operator = (const cMatrix &m);
};

//stripped source file
cMatrix::cMatrix(cMatrix& m)
{
    _r = m._r;
    _c = m._c;
    _zeroindexed = m._zeroindexed;
    _internal = new float[_r*_c];

    UInt32 size = GetElementCount();

    for (UInt32 i = 0; i < size; i++)
    {
        _internal[i] = m._internal[i];
    }
}

cMatrix::~cMatrix(void)
{
    delete[] _internal;
}
cMatrix& cMatrix::operator+(cMatrix m) 
{
    return cMatrix(*this) += m;
}

cMatrix& cMatrix::operator*(float f) 
{
    return cMatrix(*this) *= f;
}

cMatrix& cMatrix::operator*=(float f) 
{
    UInt32 size = GetElementCount();

    for (UInt32 i = 0; i < size; i++)
    {
        _internal[i] *= f;
    }

    return *this;
}

cMatrix& cMatrix::operator+=(cMatrix m) 
{
    if (_c != m._c || _r != m._r)
    {
        throw new cCTException("Cannot add two matrix classes of different sizes.");
    }
    if (!(_zeroindexed && m._zeroindexed))
    {
        throw new cCTException("Zero-Indexed mismatch.");
    }

    for (UInt32 row = 0; row < _r; row++)
    {
        for (UInt32 column = 0; column < _c; column++)
        {
            float Current = _getelement(row, column) + m._getelement(row, column);
            _setelement(row, column, Current);
        }
    }

    return *this;
}

cMatrix& cMatrix::operator=(const cMatrix &m) 
{
    if (this != &m) 
    {
        _r = m._r;
        _c = m._c;
        _zeroindexed = m._zeroindexed;

        delete[] _internal;

        _internal = new float[_r*_c];

        UInt32 size = GetElementCount();

        for (UInt32 i = 0; i < size; i++)
        {
            _internal[i] = m._internal[i];
        }
    }
    return *this;
  }

I, like so many programmers before me, am tearing my hair out writing the right-of-passage-matrix-class-in-C++. I have never done very serious operator overloading and this is causing issues. Essentially, by stepping through

This is what I call to cause the problems.

    cMatrix Kev = CT::cMatrix::GetUnitMatrix(4, true);
    Kev *= 4.0f;
    cMatrix Baz = Kev;
    Kev = Kev+Baz;  //HERE!

What seems to be happening according to the debugger is that Kev and Baz are added but then the value is lost and when it comes to reassigning to Kev, the memory is just its default dodgy values. How do I overload my operators to allow for this statement?
My (stripped down) code is below.

//header
class cMatrix
{
private:
    float* _internal;
    UInt32 _r;
    UInt32 _c;
    bool _zeroindexed;

    //fast, assumes zero index, no safety checks
    float cMatrix::_getelement(UInt32 r, UInt32 c)
    {
        return _internal[(r*this->_c)+c];
    }

    void cMatrix::_setelement(UInt32 r, UInt32 c, float Value)
    {
        _internal[(r*this->_c)+c] = Value;
    }

public:
    cMatrix(UInt32 r, UInt32 c, bool IsZeroIndexed);
    cMatrix( cMatrix& m);
    ~cMatrix(void);

    //operators
    cMatrix& operator + (cMatrix m);
    cMatrix& operator += (cMatrix m);
    cMatrix& operator = (const cMatrix &m);
};

//stripped source file
cMatrix::cMatrix(cMatrix& m)
{
    _r = m._r;
    _c = m._c;
    _zeroindexed = m._zeroindexed;
    _internal = new float[_r*_c];

    UInt32 size = GetElementCount();

    for (UInt32 i = 0; i < size; i++)
    {
        _internal[i] = m._internal[i];
    }
}

cMatrix::~cMatrix(void)
{
    delete[] _internal;
}
cMatrix& cMatrix::operator+(cMatrix m) 
{
    return cMatrix(*this) += m;
}

cMatrix& cMatrix::operator*(float f) 
{
    return cMatrix(*this) *= f;
}

cMatrix& cMatrix::operator*=(float f) 
{
    UInt32 size = GetElementCount();

    for (UInt32 i = 0; i < size; i++)
    {
        _internal[i] *= f;
    }

    return *this;
}

cMatrix& cMatrix::operator+=(cMatrix m) 
{
    if (_c != m._c || _r != m._r)
    {
        throw new cCTException("Cannot add two matrix classes of different sizes.");
    }
    if (!(_zeroindexed && m._zeroindexed))
    {
        throw new cCTException("Zero-Indexed mismatch.");
    }

    for (UInt32 row = 0; row < _r; row++)
    {
        for (UInt32 column = 0; column < _c; column++)
        {
            float Current = _getelement(row, column) + m._getelement(row, column);
            _setelement(row, column, Current);
        }
    }

    return *this;
}

cMatrix& cMatrix::operator=(const cMatrix &m) 
{
    if (this != &m) 
    {
        _r = m._r;
        _c = m._c;
        _zeroindexed = m._zeroindexed;

        delete[] _internal;

        _internal = new float[_r*_c];

        UInt32 size = GetElementCount();

        for (UInt32 i = 0; i < size; i++)
        {
            _internal[i] = m._internal[i];
        }
    }
    return *this;
  }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

你怎么这么可爱啊 2024-09-05 23:51:47

您的运算符 + 和 * 必须按值返回,而不是按引用返回。您通过引用返回一个临时变量。另外,当参数应该是 const 引用时,参数是按值传递的:

cMatrix cMatrix::operator+(cMatrix const& m) 
{
    cMatrix matrix(*this);
    matrix += m;
    return matrix;
}

cMatrix cMatrix::operator*(float f) 
{
    cMatrix matrix(*this);
    matrix *= m;
    return matrix;
}

您应该看看 Boost.Operators。这将使您仅实现 operator*=operator+= 并自动为 operator+operator* 提供正确的实现。

PS:如果您只是为了学习体验而实现矩阵类,请毫不犹豫地查看其他实现,例如 矩阵模板库

PPS:如果您不想使用 boost,或者只是想了解最佳实践,请查看 Boost.Operator 并执行他们所做的操作。

Your operators + and * must return by value, not by reference. You're returning a temporary variable by reference. Also, you're arguments are passed by value when it should be a const reference:

cMatrix cMatrix::operator+(cMatrix const& m) 
{
    cMatrix matrix(*this);
    matrix += m;
    return matrix;
}

cMatrix cMatrix::operator*(float f) 
{
    cMatrix matrix(*this);
    matrix *= m;
    return matrix;
}

You should take a look at Boost.Operators. This would let you implement only operator*= and operator+= and automatically provide correct implementations for operator+ and operator*.

PS: If you implement your matrix class just for the learning experience, don't hesitate to look at other implementations like the Matrix Template Library.

PPS: If you don't want to use boost, or if you just want to understand the best practice, take a look at Boost.Operator and do what they do.

毁梦 2024-09-05 23:51:47

IMO 重载加法的规范形式是这样的:

class X {
public:
  X& operator+=(const X& rhs) { /*add rhs to *this*/ }
};

inline X operator+(X lhs, const X& rhs) {lhs+=rhs; return lhs;}

在适用的情况下,-*/ 也是如此。

请注意,+ 返回副本,而不是引用。这很重要,因为 A+B 创建一个新值,因此它无法返回对现有值的引用。
而且,它是一个免费功能。 IMO 最好将那些可以作为成员或自由函数实现的二元运算符实现为自由函数,如果它们对称地对待其操作数(如 + 那样),并且作为成员函数,如果它们不对称地对待其操作数(如 +=,这会更改其左侧参数。如果将 operator+ 实现为成员,则必须使函数 const (X运算符+(const X& rhs) const),这样就可以为左侧的常量元素调用它。

IMO the canonical form of overloading addition is this:

class X {
public:
  X& operator+=(const X& rhs) { /*add rhs to *this*/ }
};

inline X operator+(X lhs, const X& rhs) {lhs+=rhs; return lhs;}

The same goes for -, *, /, where applicable.

Note that + returns a copy, not a reference. That's important, because A+B creates a new value, so it cannot return a reference to an existing one.
Also, it is a free function. IMO it's best to implement those of the binary operators which can be implement either as a member or as a free function as free functions, if they treat their operands symmetrically (as does +), and as member functions, if they treat their operands asymmetrically (as +=, which changes its left argument. If you implement operator+ as a member, you will have to make the function const (X operator+(const X& rhs) const), so that it can be invoked for constant elements on the left side.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文