2

クラスを std::vector から継承しました。ここで、[] 演算子をオーバーロードしたいと思います。
ベクトルに新しい値を割り当てようとすると、たとえばv[0]=5,、メッセージを受け取る必要がありますOK

これは私のコードです(私は知っています、それは意味がありません、私はただ遊んでいます):

#include<vector>
#include<iostream>
class Vec : public std::vector<int> {
public:
    int operator[](int);
};

int Vec::operator[](int i) {
    (*this)[i] = i;
    std::cout << "OK";
    return 123;
}

int main() {
    Vec v;
    v[0]=5;
}

残念ながら、次のエラーが表示されます。

In member function ‘int Vec::operator[](int)’:
error: lvalue required as left operand of assignmen
In function ‘int main()’:
error: lvalue required as left operand of assignment
4

3 に答える 3

7

この特定のエラーはlvalue、通常、 などの割り当ての左側に表示できるものとして定義される を返さないために発生しますv[0] = 5;。他の回答で指摘されているように、さらに問題がありますが、これはそのエラーメッセージ(a)で直面する特定の問題です。

インデックス演算子をオーバーロードするための正しい仕様は次のとおりです。

int& operator[] (const int nIndex);

として扱いたい場合は、アイテムへの参照を返す必要があります (変更できるようにするため) lvalue。次のコードは修正を示していますが、この単純化されたケースでは明らかにすべての配列インデックスが同じ値にマップされます。

#include <vector>
#include <iostream>

class Vec : public std::vector<int> {
    public:
        int& operator[] (int);    // <-- note the '&'
    private:
        int xyzzy;
};

int& Vec::operator[] (int idx) {  // <-- note the '&'
    std::cout << "OK\n";
    return xyzzy;
}

int main () {
    Vec v;
    v[0] = 5;
    v[1] = 6;
    std::cout << v[22] << '\n';
    return 0;
}

これの出力は次のとおりです。

OK
OK
OK
6

実際には、すべてのインデックスを同じ値にマップすることはありません。上記のコードは、正しい関数シグネチャを示すためのものです。非仮想デストラクタを使用してクラスをサブクラス化すると、通常、自明でないコードで問題が発生するため、より完全な例を示す必要はありません(b)


(a)デストラクタは仮想ではないため、通常、サブクラスstd::vector化することはお勧めできません。そのため、オブジェクトをポリモーフィックに破棄しようとすると問題が発生する可能性があります。

おそらく、リレーションシップ (継承する場所) よりもリレーションシップ (has-aクラスにベクトルが含まれる場所)を使用する方がよいでしょう。is-a

残念ながら、クラスから基礎となるベクターへの多くのパススルー メソッドを作成する必要があるかもしれませんが (必要なものだけですが)、デストラクタの問題は解決されます。


(b) (a)参照:-)

于 2013-05-21T00:59:12.633 に答える
5

要素への参照を返す必要がありますが、たとえそうしたとしても、無限の再帰に遭遇することに注意してください - あなたoperator[]自身の呼び出し。

いずれにせよ、から継承することstd::vectorはお勧めできません。代わりにコンポジションを使用してください。

于 2013-05-21T00:50:25.907 に答える
3

以下のコードoperator[]は、基本クラスからを呼び出す方法を示してvectorいます....

#include <iostream>
#include <vector>

struct Vec : std::vector<int>
{
    int& operator[](int n)
    {
        std::cout << "operator[](" << n << ")\n";
        return std::vector<int>::operator[](n);
    }
};

int main()
{
    Vec v;
    v.push_back(10);
    v.push_back(20);
    v[0] += 5;
    std::cout << v[0] << ' ' << v[1] << '\n';
}

実行時の出力:

operator[](0)
operator[](1)
operator[](0)
15 20

「 std ::vector から継承しない」というこの話すべてを真剣に受け止めないでください。std::vector<int>*データメンバーを追加した場合にのみ、おそらくあなたを噛むでしょう。これらのリスクを理解していることを確認してから、独自の評価を行う必要がありますが、小さなユーティリティプログラムなどでは、そのようなクラスから継承することが生産的です....

于 2013-05-21T01:14:50.257 に答える