web-dev-qa-db-ja.com

「演算子=非静的メンバーでなければならない」とはどういう意味ですか?

私は二重にリンクされたリストを作成している最中です、リストを別のものに等しくするためにoperator =をオーバーロードしました:

template<class T>
void operator=(const list<T>& lst)
{
    clear();
    copy(lst);
    return;
}

しかし、コンパイルしようとすると、このエラーが発生します。

container_def.h(74) : error C2801: 'operator =' must be a non-static member

また、問題がなければ、74行目が定義の最後の行で、 "}"が付いています。

25
user98188

正確に言うと、演算子のオーバーロードはメンバー関数でなければなりません。 (クラス内で宣言)

template<class T>
void list<T>::operator=(const list<T>& rhs)
{
    ...
}

また、LHSを=から返すことをお勧めします。これにより、チェーンを作成できます(a = b = cなど)-list<T>& list<T>::operator=....にしてください

23
v3.

その演算子をクラス定義内に置きます。 operator=は特別であり、とにかくそれを非メンバーとして書くことによって何かを得ることはないので、それはメンバーでなければなりません。非メンバーオペレーターには、2つの重要な主な利点があります。

  • 右側の暗黙的な変換and演算子呼び出しの左側
  • クラスの内部について知る必要はありません。非会員・非友人として機能を実現できます。

operator=の場合、どちらも使用できません。変換の一時的な結果に割り当てることは意味がなく、ほとんどの場合、operator=は内部にアクセスする必要があります。さらに、特別なoperator=が提供されていない場合は、C++によって自動的に提供されます(いわゆるコピー代入演算子)。非メンバーとしてoperator=をオーバーロードできるようにすると、複雑さが増し、明らかに実用的な効果が得られなくなるため、許可されません。

コードを次のように変更します(これはoperator=notコピー代入演算子であると想定していますが、list<T>から他のものに代入しています。これはあなたの質問から明確に):

class MyClass {
...
    template<class T>
    MyClass& operator=(const list<T>& lst)
    {
        clear();
        copy(lst);
        return *this;
    }
...
};

operator=が再びそれ自体への参照を返すことはかなり標準的です。私はその習慣を守ることをお勧めします。プログラマーにはなじみやすく、突然voidが返された場合に驚きが生じる可能性があります。

演算子をメンバー関数としてオーバーロードする場合は、次のテンプレートを使用する必要があります。

class A {
  A& operator=(const A& other) {
    if (this != &other) {
      ...
    }
    return *this;
  }
}

注意すべき3つの点:

  1. (上記のように)割り当て演算子を使用して自己割り当てを確認します。
  2. 引数はconst参照である必要があります。そして
  3. 演算子のチェーンを可能にするために* thisを返す場合、操作の結果を非const参照として返します。

クラスの外部にある演算子をオーバーロードすることもできます。これは、代入演算子では実行できないため、この例には関係ありませんが、多くの場合、メンバー関数よりも優れているため、注目に値します。典型的な形式は次のとおりです。

class A {
  friend const A& operator+(const A& a, const A& b);
  ...
}
const A& operator+(const A& a, const A& b) {
  A& ret = ...
  return ret;
}

これはconst参照を返すので、これを行うことはできません:

(a + b) = c
6
cletus