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 对象 。由此看来,在堆栈上返回 后果 依旧是最安全和最 方便的解决 方案 。 |