在类中调用的重写的[]运算符的错误版本

时间:2013-11-26 11:34:33

标签: c++ vector operators const

我有一个简单的二维线类,它包含两个双精度矢量。我添加了getValue和setValue函数,但是更喜欢公共接口在这些函数旁边使用方括号运算符。以下代码显示了实现和使用:

#include <vector>
#include <algorithm>
#include <cassert>

class Simple2DLine
{
public:
    Simple2DLine();
    // Simple read method with linear interpolation
    double getValue(double x) const;
    // Simple write method, adds a curve point, keeping the arrays sorted
    void setValue(double x, double y);

    double& operator [](double x);
    const double operator [](double x) const;
private:
    std::vector<double> m_X;
    std::vector<double> m_Y;
    int getNearestIndex(double x) const;
};

Simple2DLine::Simple2DLine()
{

}

void Simple2DLine::setValue(double x, double y)
{
    // Get the index of the point at or just before 'x'
    int idx = getNearestIndex(x);

    // Check if the exact point already exists.
    if (idx >= 0)
    {
        if (m_X[idx] == x)
        {
            m_Y[idx] = y;
            return;
        }
        else
        {
            // Insert adds the value just BEFORE idx, so increment it before inserting.
            ++idx;
            m_X.insert(m_X.begin() + idx,x);
            m_Y.insert(m_Y.begin() + idx,y);
            return;
        }
    }

    // Otherwise, just insert at the front.
    m_X.insert(m_X.begin(),x);
    m_Y.insert(m_Y.begin(),y);
}

double Simple2DLine::getValue(double x) const
{
    // Make sure there are points - if not, return 0.
    if (m_X.size() == 0)
    {
        return 0;
    }

    // Make sure it's not out of bounds.
    if (x < m_X.front() || x > m_X.back())
    {
        return 0;
    }

    // Check if it's at or after the last point
    if (x == m_X.back())
    {
        return m_X.back();
    }

    // Find the point just before the given point.
    int idx = getNearestIndex(x);

    // Check if we're on the exact point
    if (m_X[idx] == x)
    {
        return m_X[idx];
    }
    else
    {
        // Find the distance from the nearest point and linearly interpolate.
        double dist = x - m_X[idx];

        return m_Y[idx] + dist * (m_Y[idx + 1] - m_Y[idx]) / (m_X[idx + 1] - m_X[idx]);
    }
}

double& Simple2DLine::operator [](double x)
{
    // Create a space for the new value
    setValue(x,0.0);
    int idx = getNearestIndex(x);
    return m_Y[idx];
}

const double Simple2DLine::operator [](double x) const
{
    return getValue(x);
}

// Returns the index of the point at or just before 'x'.  Invalid values return -1.
int Simple2DLine::getNearestIndex(double x) const
{
    if (m_X.empty())
    {
        return -1;
    }

    std::vector<double>::const_iterator xBegin(m_X.begin());
    std::vector<double>::const_iterator xEnd(m_X.end());

    // Get an iterator to the first value GREATER than our search value
    std::vector<double>::const_iterator it = upper_bound(xBegin,xEnd,x);

    // If the iterator is at the beginning, all values are greater
    if (it == xBegin)
    {
        return -1;
    }

    // Otherwise, decrement the iterator by 1, and return its' distance from the start.
    return (it - 1) - xBegin;
}

int main(int argc, char** argv)
{
    Simple2DLine tda;

    tda.setValue(0.0,10.0);
    tda.setValue(1.0,15.0);
    tda.setValue(2.0,20.0);
    tda.setValue(3.0,25.0);

    double tmp = tda.getValue(0.5);
    assert(abs(tmp - 12.5) < 0.000001);
    tmp = tda.getValue(1.5);
    assert(abs(tmp - 17.5) < 0.000001);
    tmp = tda.getValue(2.5);
    assert(abs(tmp - 22.5) < 0.000001);

    // Here, the wrong version of the overridden operator is being called.
    tmp = tda[1.5];
    tda[2.5] = 22.5;
}

当我以下列方式访问line对象时,将调用该运算符的正确版本(非const)

tda[2.5] = 22.5;

但是,当我尝试使用const版本时,如下所示:

tmp = tda[1.5];

调用非const版本。我的实施中有错误吗?或者以这种方式访问​​课程是不可能的?

2 个答案:

答案 0 :(得分:7)

在const对象上调用const版本。因此,如果您有一个声明为const Simple2DLine tda的对象,则会调用const重载版operator[]

实际上,您会看到const个对象作为函数参数,如:

void foo(const Simple2DLine& tda)
{
     std::cout<< tda[0];
}

在那里你会注意到被调用的const重载函数。

此外,const重载的operator[]仍然可以返回引用。

答案 1 :(得分:2)

你是否认为必须自动调用const运算符只是因为包含它的表达式出现在等式的右边?这不是它的工作方式。如果你有一个const对象,将调用const版本。

你可以,例如尝试将对象分配给const引用。

Simple2DLine const & tdaconst = tda;
tmp = tdaconst[1.5];

在上面的代码中,将调用const版本。