【问题标题】:What does "operator = must be a non-static member" mean?“运算符 = 必须是非静态成员”是什么意思?
【发布时间】:2010-10-26 15:44:14
【问题描述】:

我正在创建一个双链表,并重载了 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 行是定义的最后一行,带有“}”。

【问题讨论】:

  • 这是在什么背景下?在课堂里?在顶层?
  • 实际上不需要问题名称中的语言,因为它也标记为 C++
  • 这个问题具有误导性。问题here 更有趣。尽管最好的措辞是“为什么 operator= 不能是全球性的”。 Johannes Schaub - litb 的回答澄清了这一点。

标签: c++ class operator-overloading non-static


【解决方案1】:

正如它所说的:运算符重载必须是成员函数。 (在类中声明)

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

另外,从 = 返回 LHS 可能是个好主意,这样您就可以将其链接起来(如 a = b = c) - 所以让它 list&lt;T&gt;&amp; list&lt;T&gt;::operator=....

【讨论】:

  • 是的,我刚刚意识到:我在课堂上声明了它,但写的是“void operator=”而不是“void list::operator="
  • 很抱歉,这是错误的。 operator= 必须是成员(如编译器所说)。 operator[] 和 operator() 也是如此,可能还有一些我想念的。基本上所有这些都与修改状态而不是产生值有关。更正您的答案,我将收回-1。 Keand64 的问题是他错过了指定类 (list::),这与这个答案没有太大关系。
  • 哦,哎呀。对不起>
  • 别担心。我们都有自己的段错误:)
  • 您的回答仍然具有误导性。这不是关于带有 1 个参数的运算符重载必须是成员函数这一事实,而是赋值运算符没有两个参数版本。
【解决方案2】:

将该运算符放在您的类定义中。它必须是成员,因为operator= 是特殊的,无论如何您都不会通过将其写为非成员来获得任何东西。非会员运营商有两个重要的主要好处:

  • 运算符调用右侧左侧的隐式转换
  • 无需了解类的内部结构。功能可以实现为非会员非好友。

对于operator=,两者都不可用。分配给转换的临时结果没有意义,operator= 在大多数情况下需要访问内部。此外,如果您不提供一个特殊的operator=,C++ 会自动提供一个operator=(所谓的复制赋值运算符)。使operator= 作为非成员重载成为可能会引入额外的复杂性,显然没有实际收益,因此这是不允许的。

所以更改您的代码,使其看起来像这样(这假设 operator= 不是 复制赋值运算符,而是从 list&lt;T&gt; 分配给其他东西。这不是从你的问题中清除):

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

operator= 再次返回对自身的引用是相当标准的。我建议你坚持这种做法。它对程序员来说看起来很熟悉,如果它突然返回 void 可能会引起意外。

【讨论】:

    【解决方案3】:

    如果将运算符重载为成员函数,则应使用此模板:

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

    注意三点:

    1. 使用赋值运算符检查自赋值(如上);
    2. 参数应该是一个常量引用;和
    3. 将运算结果作为非常量引用返回,您可以在其中返回 *this 以允许链接运算符。

    您还可以重载类外部的运算符。这与此示例无关,因为您不能使用赋值运算符来执行此操作,但值得注意的是,因为在许多情况下它优于成员函数。典型的形式是:

    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;
    }
    

    这个返回一个常量引用,所以你不能这样做:

    (a + b) = c
    

    【讨论】:

    • 真的必须是静态的吗?在 g++ 中没有任何静态对我有用。
    • 很抱歉让我的电线交叉了。默认情况下,不在类中的函数是静态的。你可以把 static 关键字放进去,但这不是必需的,所以没有区别,所以我把它去掉了。
    • operator= 必须是成员(对于 operator[] 也是如此)。我会用另一个例子来展示非会员方式。
    【解决方案4】:

    来自 C++ 标准,“二元运算符”:

    "二元运算符要么由一个参数的非静态成员函数实现,要么由一个有两个参数的非成员函数实现"

    它希望你在一个类中定义 this,作为一个成员,或者使它成为一个静态方法(在这种情况下它应该有两个参数(对于 lval 和 rval)。

    【讨论】:

    • 最初的问题是关于operator =,它不是(根据 C++ 标准)“二元运算符”。您引用了第 13.5.2.1 段。但是,赋值运算符在第 13.5.3 节中讨论:“赋值运算符应由只有一个参数的非静态成员函数实现。......”
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-03
    • 2012-10-02
    • 1970-01-01
    • 2019-02-06
    • 2013-05-07
    • 2011-08-31
    相关资源
    最近更新 更多