C++重载操作符的设计方法

  用户定义的类型,如:字符串,日期,复数,联合体以及文件常常重载二元 + 操作符以实现对象的连接,附加或合并机制。但是要正确实现 + 操作符会给设计,实现和性能带来一定的挑战。本文将概要性地介绍如何选择正确的策略来为用户定义类型重载这个操作符。

  考虑如下的表达式: int x=4+2;

  内建的 + 操作符有两个类型相同的操作数,相加并返回右值 6,然后被赋值给 x。我们可以断定内建的 + 是一个二元的,对称的,可交换的操作符。它产生的结果的类型与其操作数类型相同。按照这个规测,当你为某个用户定义类型重载操作符时,也应该遵循相应内建操作符的特征。

  为用户定义类型重载 + 操作符是很常见的编程任务。尽管 C++ 提供了几种实现方法,但是它们容易使人产生设计上的误解,这种误解常常影响代码的正确性,性能以及与标准库组件之间的兼容性。

  下面我们就来分析内建操作符的特征并尝试模仿其相应的重载机制。

  第一步:在成员函数和非成员函数之间选择

  你可以用类成员函数的方式实现二元操作符如:+、- 以及 ==,例如:

  class String

  {

  public:

  bool operator==(const String & s); // 比较 *this 和 s

  };

  这个方法是有问题的。相对于其内建的操作符来说,重载的操作符在这里不具有对称性;它的两个参数一个类型为:const String * const(这个参数是隐含的),另一个类型为:const String &。因此,一些 STL 算法和容器将无法正确处理这样的对象。

  另外一个可选方法是把重载操作符 + 定义为一个外部(extern)函数,该函数带两个类型相同的参数:

  String operator + (const String & s1, const String s2);

  这样一来,类 String 必须将该重载操作符声明为友元:

  class String

  {

  public:

  friend String operator+(const String& s1,const String&s2);

  };

  第二步:返回值的两难选择

  如前所述,内建操作符 + 返回右值,其类型与操作数相同。但是在调用者堆栈里返回一个对象效率很低,处理大型对象时尤其如此。那么能不能返回一个指针或引用呢?答案是不行。因为返回指针破坏参数类型与返回值类型应该相同的规则。更糟的是,链接多个表达式将成为不可能:

  String s1,s2,s3;

  String res;

  res=s1+s2+s3; // 不可能用 String* 作为返回值

  虽然有一个办法可以定义额外的 + 操作符重载版本,但这个办法是我们不希望用的,因为返回的指针必须指向动态分配的对象。这样的话,如果调用者释放(delete)返回的指针失败,那么将导致内存泄漏。显然,返回 String* 不是一个好主意。

  那么返回 String& 好不好呢?返回的引用必须一定要是一个有效的 String。它避免了使用动态对象分配,该方法返回的是一个本地静态对象的引用。静态对象确实解决了内存泄漏问题,但这个方法的可行性仍然值得怀疑。在一个多线程应用中,两个线程可能会并发调用 + 操作符,因此造成 String 对象的混乱。而且,因为静态对象总是保留其调用前的状态,所以有必要针对每次 + 操作符的调用都清除该静态 String 对象。由此看来,在堆栈上返回结果仍然是最安全和最简单的解决方案。

时间: 2024-08-29 03:05:42

C++重载操作符的设计方法的相关文章

C++ 中重载操作符的设计方法

用户定义的类型,如:字符串,日期,复数,联合体以及文件常常重载二元 + 操作符以实现对象的连接,附加或合并机制.但是要正确实现 + 操作符会给设计,实现和性能带来一定的挑战.本文将概要性地介绍如何选择正确的策略来为用户定义类型重载这个操作符. 考虑如下的表达式: int x=4+2; 内建的 + 操作符有两个类型相同的操作数,相加并返回右值 6,然后被赋值给 x.我们可以断定内建的 + 是一个二元的,对称的,可交换的操作符.它产生的结果的类型与其操作数类型相同.按照这个规测,当你为某个用户定义类

C++中重载+操作符的正确方法

摘要:本文概要性地介绍如何选择正确的策略来为用户定义类型重载 + 操作符. 用户定义的类型,如:字符串,日期,复数,联合体以及文件常常重载二元 + 操作符以实现对象的连接,附加或合并机制.但是要正确实现 + 操作符会给设计,实现和性能带来一定的挑战.本文将概要性地介绍如何选择正确的策略来为用户定义类型重载这个操作符. 考虑如下的表达式:int x=4+2; 内建的 + 操作符有两个类型相同的操作数,相加并返回右值 6,然后被赋值给 x.我们可以断定内建的 + 是一个二元的,对称的,可交换的操作符

一种全新的软件界面设计方法(摘)

设计 关键字:COM MySpy IE SetUIHanlder IcustomDoc IDocHostUIHandler GetExternal 前言 作者在解决各种问题的时候喜欢首先使用C++ Builder来尝试,这篇文章也是这样,但这并不影响其他开发工具的使用者阅读,因为这都是微软的开发技术,选择什么工具并不重要,我们理解了他的原理可以使用任何工具实现同样的功能. 正文 使用过VC.Net的朋友可能知道,在VC.Net中全新提供了一种基于Web的界面设计方法,不过可能真正用到的人很少,至

让JavaScript 轻松支持函数重载 (Part 1 - 设计)_javascript技巧

JavaScript支持重载吗? JavaScript支持函数重载吗?可以说不支持,也可以说支持.说不支持,是因为JavaScript不能好像其它原生支持函数重载的语言一样,直接写多个同名函数,让编译器来判断某个调用对应的是哪一个重载.说支持,是因为JavaScript函数对参数列表不作任何限制,可以在函数内部模拟对函数重载的支持. 实际上,在很多著名的开源库当中,我们都可以看到函数内部模拟重载支持的设计.例如说jQuery的jQuery.extend方法,就是通过参数类型判断出可选参数是否存在

草图设计(一):最自由的一项设计方法

"转眼间已经在CDC生活了快两年的时间.从一名电子商务毕业生到一位职业的交互设计师,经历了许多的坎坷.常常会面对各种困难和压力,当发现有太多未知的领域,只有在学习.思考.实践中能够找到答案与自信." 草图设计是这一年来学习.思考.实践.总结的一项设计方法,尝试于产品设计的各个环节.草图设计对于设计师来说并不陌生,在日常工作中都有用到,相信很多设计师跟我都有同样想法,并且希望推广草图设计给同行以及产品经理,作为灵感与实现,需求与设计之间的桥梁.也非常希望感兴趣的同学回复转播此文,留下观点

c++ 重载操作符友元问题

问题描述 c++ 重载操作符友元问题 <c++ primer>里面有一段文字: Salesitem 类也是说明为何有些操作符需要设置为友元的一个好例子.它定义了一个成员操作符,并且有三个非成员操作符.这些非成员操作符需要访问私有数据成员,声明为友元: class Sales_item {friend std::istream& operator>>(std::istream& Sales_item&);friend std::ostream& ope

软件工程之面向过程的软件设计方法

   面向过程,是一种以过程为中心的编程思想,这个过程有人也称之为面向记录,他们不支持丰富的面向对象的特性,比如继承多态等,还有重要的一点是,他们不允许混合持久化状态和域逻辑.   简单的来说,面向过程就是分析解决问题所需要的步骤,然后再用函数把这些步骤一步一步实现,使用的时候一个一个一次调用即可,我想大家都有乘坐动车的经历,比如说,从廊坊站到北京南,面向过程就是动车从廊坊站启动是一个事件,动车到达北京南是另一个事件,在编程序的时候我们关心的是某一个事件,而不是动车本身,我们分别对动车启动和到站

Web App动效设计原则 Web App的设计方法

文章描述:Mobile Web App的设计方法 [编者按]本文作者:邓腾(@千年牛皮糖),百度无线交互设计师 .在本文中,作者将给大家谈谈Mobile Web App的设计方法,内容包括:Web App定义.Web App的特点.发展现状及设计等等.希望对大家有所帮助. Native App与Web App的争论从未停息过,尽管很多人在批判Web App的各种不是,但也阻止不了各种各样的Web App如雨后春笋般出现,尤其是伴随智能手机的普及而受到重视的Mobile Web App.这是一种在

交互设计案例:网页进度条提升等待体验的设计方法

文章描述:从排队等待谈进度条设计. 排队等待是一种日常中常见的现象,例如新年领开工利是.去排队购买首发的苹果产品.每天中午去食堂排队购买午餐.排队等待在我们的生活中无处不在且看似是一个简单的现象.即使是种简单的存在,但也有其复杂的一面,当存在着很多条队列时,确定每条队列是做什么的就变得困难了:在加入队列后,人们会产生:大概要等多久?为什么队伍很久没有往前移动?等诸多疑问.无法解释的等待是令人烦躁的,不公平的等待则可能引发人们的怒火. 经历过领开工利是的同学应该对于当天排队等待的回忆不会很糟,甚至