【问题标题】:Overloading Operator = as a member function重载运算符 = 作为成员函数
【发布时间】:2012-02-01 19:58:55
【问题描述】:

C++ 允许将= 运算符重载为成员函数,而不是全局函数。

Bruce Eckel 说 if it was possible to define operator= globally, then you might attempt to redefine the built-in = sign. 并且由于这个原因,您只能将 = 运算符重载为成员函数。

如果 C++ 已经定义了 = 运算符,那么为什么 C++ 没有定义像 + - 等其他运算符,因为它们可以作为非成员函数重载。 ?

【问题讨论】:

  • = 的语义(通常)很明显。其他人的语义不是 - - 会为例如做什么std::string?
  • 这个有很多重复的,让我找一个...
  • 这意味着只有运算符 = 是由 C++ 预定义的……是这样吗?
  • copy 赋值运算符会在编译器需要时自动声明和定义。
  • 这个理由似乎是错误的(或者至少非常模棱两可)。是的,通常使用运算符重载,您可以尝试重新定义内置运算符,只是编译器不允许您这样做。

标签: c++ operators operator-overloading


【解决方案1】:

= 运算符(用作初始化时)与构造函数密切相关;当您编写SomeClass a = b; 代码时,会调用SomeClass 的某个构造函数。

【讨论】:

  • 怎么样?初始化和赋值是两个完全不同的东西。
  • 我同意,但是当您编码 SomeClass a = b; 时,会涉及到构造函数(并且语法没有显示)。
  • 我认为最好说“一个等号”,因为SomeClass a = b; 没有使用赋值运算符,尽管你使用了等号
  • 同意。相应地编辑了我的答案。
  • @Basile :您的编辑是倒退的——= 当用作 initialization 时与构造函数密切相关;当用作作业时,它不是。
【解决方案2】:

因为赋值对任何类型都有明确的含义,所以其他运算符没有。

【讨论】:

    【解决方案3】:

    如果不参考具体实现和私有成员,从类外部实现 operator=() 似乎真的很难。

    但是,像“+”这样的运算符有时必须在全局级别定义。考虑一个复数类。我可以从我的类内部定义 complex::operator+(float),但我必须从外部定义 operator+(float, complex),因为第一个操作数没有我的类的类型。 p>

    编辑:我还应该提到,通过使用类中定义的其他运算符来定义像 operator+ 这样的全局运算符通常很容易,而无需参考特定的实现细节。例如:

    complex operator+(float lhs, complex rhs) {return complex(lhs, 0)+rhs;}
    

    【讨论】:

    • 实现它的常用方法是复制和交换习语。无需特殊访问权限。
    • 而全局 operator+ 通常以成员 += 的形式实现 :) complex operator+(complex a, const complex& b) { return a += b; }
    • 这里最大的不同是operator+ 生成一个你喜欢的任何类型的临时文件,与lhs 的类型无关。 = 是赋值(或初始化),返回对写入字段的引用,并且 lhs 的等价物必须与返回值具有相同的基本类型,否则您将不正确地取消引用返回。到那时,你可以用类定义的类型转换运算符和operator= 无法完成的= 的全局重载做什么?
    【解决方案4】:

    编译器为所有没有定义自己的类生成一个默认的复制赋值运算符 (operator=)。这意味着在任何情况下都不会选择全局重载。

    【讨论】:

      【解决方案5】:

      扩展@ildjarn的评论,全局内置=的语义是通用设置的;它在使用某种右值初始化类的新实例时调用,并调用适当的构造函数(基于右值的编译时类型),这是提供 c 样式初始化而不是严格的好方法要求通过显式调用构造函数来初始化所有变量。重载全局运算符会改变语言的太多底层语义,同时几乎不知道真正的好处——你将从根本上改变构造函数的调用方式、调用方式和是否调用,如果你觉得你有理由通过重载全局 = 来做到这一点,很有可能你错了。

      类成员operator= 是可重载的,因为它在其类的已经存在和初始化的左值上运行,并且在明显的情况下,您希望在修改预先存在的对象时使用自定义行为(比如只复制某些成员从右值中重新计算其他人并让其他人独自一人,或正确处置指针持有的资源以持有新资源而不会泄漏内存)。

      成员operator= 处理一个完整的左值对象,而内置函数则从一个适当大小的内存块和一个右值开始。 所有形状和形式的构造函数都是语言提供的接口,用于修改内置 = 的行为,而不会将语义本身的控制权拱手让给您。我很想看看您的想法感觉你需要通过重载全局 = 来完成,而这是构造函数无法完成的。

      【讨论】:

      • 初始化和赋值是两个完全不同的东西。
      • 何时将全局= 运算符以现有对象作为左值调用?我想不出一个不会通过成员operator= 进行赋值的情况,无论它是用户定义的还是编译器合成的?编辑:好吧,内置类型调用内置=,但同样,您对该操作的接口是类型转换运算符,如operator int()。您无需修改​​整数赋值,您只需描述如何将新类型合并为 int
      • 并且该接口适用于对您未定义的类型的任何分配。如果您有权访问要将新类型分配给的类型,则可以编写 ExistingType::operator=(NewType&) 方法。如果你不这样做,你可以写一个NewType::operator ExistingType() 方法。什么会改变全局内置= 重载这些成员方法中的一个或两个不能做到?无论哪种方式,你最终都会存储一个ExistingType,我看不出改变这个语义会有什么意义。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-06-05
      • 2017-07-16
      • 1970-01-01
      • 2010-12-26
      • 1970-01-01
      • 2013-11-29
      相关资源
      最近更新 更多