c++ - 运算符重载

  显示原文与译文双语对照的内容

C++ 中运算符重载的基本规则和习惯用法?

注意:回答的中给定一个特定的顺序,但由于许多用户排序答案根据时序进行投票,而非时间,这里是一个 指标的答案 顺序与它们进行最为有理有据:

( 注意:这意味着是一个进入堆栈 C++的条目) 。 如果你希望所到过的理念,提供一个常见问题在这里表单,然后帐将元,开始所有这里将是这个地方可以这么做 它的理念。), 回答上面那个问题加以监测,以它的 C++ 聊天室,从它的开始常见问题解答思路所读取的完成,所以你的答案是极有可能在第一个位置来获取那些谁发明

时间:

C+ + 中运算符重载的三个基本规则

谈到 C++ 中的运算符重载,还有 三个基本规则应遵循 。 所有此类规则一样,确实有例外。 有时候人们背离了他们,结果也不是错误的代码,但是这种积极的偏差很少和。 至少,我看到的这些偏差中的99个是不合理的。 但是,它可能也是 999之外的1000. 所以你最好遵循以下规则。

  1. 每当一个操作符并没有被明显的含义清晰,无可置疑,它不应该被重载。 带有 well-chosen name, 相反,提供一个函数关系
    基本上,重载操作符最重要的规则是: 不做 。 这看起来可能很奇怪,因为有很多关于运算符重载的知识,所以很多文章,书籍章节和其他文本处理这些问题。 但是尽管如此看起来明显的证据,仅有一个令人吃惊的几个情况下运算符重载才合适 。 原因是,除非在应用程序域中使用运算符是众所周知且不可预测的,否则很难理解操作符应用背后的语义。 流行的信念相反,这种情况几乎不存在。

  2. 总是坚持运算符语义的著名。
    C++ 对重载运算符的语义没有限制。 编译器将欣然接受实现二进制 + 运算符的代码,以便从它的右操作数中减去。 在这样一个操作符没有上过怀疑表达式 a + b 减但是,用户。 当然,这假设应用程序域中的运算符的语义是不可预测的。

  3. 总是提供一组相关的操作。
    运算符与其他操作相关。 如果你的类型支持 a + b,用户将可以调用 a += b 。 如果它支持前缀增量 ++a,他们会期望 a++ 也能正常工作。 如果他们能检查 a <b,他们肯定会希望能够检查 a> b 。 如果他们能copy-construct的类型,他们期望工作分配也工作。


继续成员和非成员成员之间的判定。

重载 newdelete

注意: 这个仅涉及第 语法 支持中 newdelete,不可与重载 实现的这样重载操作符。 我认为的语义重载 newdelete 全都值得他们自己的常见问题 。运算符重载我永远不能做到公平感的主题内。

基础知识

C++ 中,当你编写一个 新表达式new T(arg) 该表达式求值时出现下面两种情形: 首先 operator new 被调用来获取原始内存,然后适当的构造函数会调用 T的作用是把这个原始内存划分为有效的对象。 同样,删除对象时,首先调用它的析构函数,然后将内存返回到 operator delete
C++ 允许你优化这两个操作: 内存管理和分配的内存中对象的构造/销毁。 后者通过为类编写构造函数和析构函数完成。 Fine-tuning内存管理是通过编写你自己的operator newoperator delete 完成的。

第一个的基本规则的运算符重载- 不做到 –尤其适用于可以重载 newdelete 。 唯一的理由都差不多要重载这些运算符仅 性能问题内存约束 加以验证,并在许多情况下,其他的操作,例如更改来使用,可以提供更多 更高的成本/增益比 并没有尝试调整内存管理过程。

C++ 标准库附带了一组预定义的newdelete 操作符。 最重要的是:


void* operator new(std::size_t) throw(std::bad_alloc); 
void operator delete(void*) throw(); 
void* operator new[](std::size_t) throw(std::bad_alloc); 
void operator delete[](void*) throw(); 

前两个分配/释放对象的内存,后两个为对象数组。 在原则library,如果你提供自己的版本的这些,他们将 不超负荷,但替换 ones.
如果重载 operator new,你应该总是重载匹配的operator delete,即使你从不打算调用它。 原因是,如果一个构造函数在计算新表达式时抛出,run-time系统将把内存返回到 operator delete,该与调用分配内存的operator new 匹配,以创建对象。 如果你不提供匹配的operator delete,那么默认的会被调用,这几乎总是错误的。
如果重载 newdelete,你应该考虑重载数组变量。

放置 new

C++ 允许新的和删除的运算符使用额外的参数。
所谓的放置新允许你在特定地址创建对象,该地址传递到:


class X {/*.. . */};
char buffer[ sizeof(X) ];
void f()
{ 
 X* p = new(buffer) X(/*...*/);
//... 
 p->~X();//call destructor 
} 

标准库附带了新的和删除运算符的适当重载:


void* operator new(std::size_t,void* p) throw(std::bad_alloc); 
void operator delete(void* p,void*) throw(); 
void* operator new[](std::size_t,void* p) throw(std::bad_alloc); 
void operator delete[](void* p,void*) throw(); 

注意,在上面给出的新给出的示例代码中,除非 operator delete的构造函数抛出异常,否则不会调用。

你还可以使用其他参数重载 newdelete 。 放置新参数的附加参数一样,这些参数也在关键字 new 之后的括号中列出。 只是由于历史原因,这种变体通常也被称为放置新的,即使它们的参数不是放置一个对象到一个特定的地址。

Class-specific新建和删除

大多数情况下,你会希望fine-tune的内存管理,因为度量显示了一个特定类或者一组相关类的实例经常被创建和销毁,而run-time系统的默认内存管理在这里特定情况下处理效率低下。 要改进这里选项,你可以为特定类别重载新的和删除的:


class my_class { 
 public: 
//... 
 void* operator new();
 void operator delete(void*,std::size_t);
 void* operator new[](size_t);
 void operator delete[](void*,std::size_t);
//... 
}; 

重载,新的和删除的行为类似静态成员函数。 对于 my_class的对象,std::size_t 参数总是 sizeof(my_class) 。 在这种情况下它有可能要大于that,为动态生成对象的,但是,这些运算符也称为派生类,.

全局新建和删除

要重载全局新的和删除的,只需用我们自己的库替换标准库的pre-defined 。 然而,这很少需要做。

...