我们如何区分使用重载[]运算符来获取和设置?

时间:2016-08-27 18:47:24

标签: c++ operator-overloading

我正在写一个要求我实现自己的(基本)矢量类的作业。一个不寻常的要求是,我们必须提供一个函数,该函数给出向量中所有元素的总和。此函数应缓存总和,因此如果向量未更改,则可以在固定时间内回答后续调用。

我遇到的问题是发生变化时想出来。

#include <iostream>

class MyVector {
    int* v;
    int size;
    int totalSum;
    bool upToDate;
public:
    MyVector(int size) : size{size}, totalSum{0}, upToDate{false} {
        v = new int[size];
        for(int i = 0; i < size; i++) {
            v[i] = 0;
        }
    }

    // Set - should only be called as an lvalue
    int& operator[](unsigned int i) {
        upToDate = false;
        std::cerr << "Set\n";
        return v[i];
    }

    // Get - should only be called as an rvalue
    int operator[](unsigned int i) const {
        std::cerr << "Get\n";
        return v[i];
    }

    // Get sum of array -- result is cached for performance
    int sum() {
        if(!upToDate) {
            upToDate = true;
            totalSum = 0;
            for(int i = 0; i < size; i++) {
                totalSum += v[i];
            }
        }
        return totalSum;
    }
};

int main() {
    MyVector mv(3);
    mv[0] = 1;
    mv[1] = 2;
    mv[2] = 3;
    std::cout << "Sum " << mv.sum() << "\n";

    int first = mv[0];
    std::cout << "First element is " << first << "\n";

    std::cout << "Sum " << mv.sum() << "\n";
}

我提供了[]运算符的两个重载版本 - 一个用于获取,一个用于设置。无论何时调用运算符的设置版本,我都假设正在更改向量。

# Output
Set
Set
Set
Sum 6
Set
First element is 1
Sum 6

但是,似乎操作符的设置版本总是被调用,即使它被用作右值。

如何正确地重载[]运算符以区分其用于获取和设置?

1 个答案:

答案 0 :(得分:2)

您可以返回围绕该引用的瘦代理包装器,而不是直接返回对存储的int的引用,该引用可以监视更改。在大多数情况下,编译器应该内联并优化它(您可以尝试对其进行基准测试并进行比较)。

包装类:

class Item {
    int &value;
    MyVector &myVector;

public:
    Item(int &value, MyVector &myVector) : value(value), myVector(myVector) {}

    Item& operator=(int newvalue) {
        std::cerr << "Set\n";
        value = newvalue;
        myVector.upToDate = false;
        return *this;
    }

    // TODO: Reimplement also operators like +=, -=, etc
    // You can use boost helpers for that.

    operator int() const {
        std::cerr << "Get\n";
        return value;
    }
};

对MyVector的更改:

class MyVector {
    // ...

    Item operator[](unsigned int i) {
        return Item(v[i], *this);
    }

    const int operator[](unsigned int i) const {
        std::cerr << "Const Get\n";
        return v[i];
    }

// ...
}

它可以完全相同的方式使用:

int main() {
    MyVector mv(3);
    mv[0] = 1;
    mv[1] = 2;
    mv[2] = 3;
    std::cout << "Sum " << mv.sum() << "\n";

    int first = mv[0];
    std::cout << "First element is " << first << "\n";

    std::cout << "Sum " << mv.sum() << "\n";
}