C++中的链式操作

代码编译环境:Windows7 32bits+VS2012。


1.什么是链式操作

链式操作是利用运算符进行的连续运算(操作),它的特点是在一条语句中出现两个或者两个以上相同的操作符,如连续的赋值操作、连续的输入操作、连续的输出操作、连续的相加操作等都是链式操作的例子。

链式操一定涉及到结合律的问题,例如链式操作赋值操作满足右结合律,即a=b=c被解释成a=(b=c),而链式输出操作原则满足左结合律,即cout<<a<<b被解释成(cout<<a)<<b,基本数据类型的链式操作都有明确的定义,而涉及到类类型的链式操作则往往需要进行相应操作符的重载。

2.类的链式操作

为了实现类的链式操作,使链式操作能够进行,操作符的重载必须满足一定的要求: (1)操作符重载函数一定不能返回void类型。 因为void类型不能参与任何运算,所以,操作符重载函数返回void类型实际上是阻止了链式操作的可能性。

(2)对赋值操作符进行重载,如果返回的是类的对象,那么链式赋值操作必须借助于拷贝构造函数才能进行。这样不懂那会有较大的运行开销,还要编写正确的拷贝构造函数。考察下面的程序。

#include <iostream>
using namespace std;

class Complex{
    double real;
    double image;
public:
    Complex(double r=0.0,double i=0.0){
        real=r;
        image=i;
    }

    Complex(const Complex& c){
        cout<<"Copy Constructor"<<endl;
        real=c.real;
        image=c.image;
    }

    void Show(){
        cout<<real<<"+"<<image<<"i"<<endl;
    }
    Complex operator=(const Complex&);
};

Complex Complex::operator=(const Complex& c)
{
    real=c.real;
    image=c.image;
    return *this;
}

int main(int argc,char* argv[])
{
    Complex c1(2.3,4.5),c2,c3;
    c1.Show();
    c3=c2=c1;
    c2.Show();
    c3.Show();
    getchar();
}

程序的运行结果是:

可以看到,在连续的两次赋值操作过程中,一共两次调用拷贝构造函数。第一次发生在执行c2=c1的操作中,函数的返回值(临时对象)是由c1构造的,这时发生了一次拷贝构造函数的调用;第二次发生在为c3赋值的时候,赋值运算的返回值仍然是一个Complex类的对象,这时又发生了一次拷贝构造函数的调用。让赋值操作依赖于拷贝构造函数,显然不是一种明智的做法。

思考:Complex& Complex::operator=(Complex& c){…},会有什么结果?

仅仅将赋值运算符重载函数的申明和定义修改如下:

Complex& operator=(const Complex&);
Complex& Complex::operator=(const Complex& c)
{
    real=c.real;
    image=c.image;
    return *this;
}

同样是上面的程序,输出结果为:

也就是说,一次拷贝构造函数都没有调用,原因是赋值操作符函数返回Complex类的引用,不用产生一个新的临时对象,这样大大提高了程序运行效率。所以,赋值运算符重载几乎无一例外地返回引用。


3.实现输入输出的链式操作

输入操作符(>>)和输出操作符(>>)的重载函数必须返回引用,否则链式无法操作无法完成。

一般来说,实现输入操作符重载,一律采用如下函数原型:

istream& operator>>(istream&, className&);

而实现输出操作符重载,一律采用如下函数原型:

ostream& operator<<(ostream&, className&);

如果操作符函数的返回的是istream或ostream类的对象,而不是引用,会出现编译错误。出错的原因以及关于输入输入操作符的重载,敬请期待我的后续blog。


参考文献

[1] ]陈刚.C++高级进阶教程[M].武汉:武汉大学出版社,2008.

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏python3

python for循环

当range执行完之后,代码执行else部分代码。如果遇到break,终止循环,不会走else代码

38510
来自专栏JavaEdge

青铜到王者 ,快速提升你 Go语言的段位! "狗"语言实战(二)- 基础语法1 变量定义

15140
来自专栏WD学习记录

数据结构与算法2016-06-03

一个算法调用自己来完成它的部分工作,在解决某些问题时,一个算法需要调用自身。如果一个算法直接调用自己或间接调用自己,就称这个算法是递归的。根据调用方式的不同,它...

8920
来自专栏JetpropelledSnake

Python入门之迭代器/生成器/yield的表达方式/面向过程编程

 本章内容     迭代器     面向过程编程       一、什么是迭代       二、什么是迭代器       三、迭代器演示和举例       四、生...

31090
来自专栏AI研习社

最常见的 35 个 Python 面试题及答案(2018 版)

作为一个 Python 新手,你必须熟悉基础知识。在本文中我们将讨论一些 Python 面试的基础问题和高级问题以及答案,以帮助你完成面试。包括 Python ...

92930
来自专栏程序生活

Python itertools的使用简介无限迭代器chain方法

用*放在一个可迭代对象前面可以将对象拆分成多个单元素,比如first=[['1','2','3','4','4'],['2','4','2']],如果把*放在f...

8410
来自专栏aCloudDeveloper

C++中引用详解

引用简介   引用就是某一变量(目标)的一个别名,对引用的操作与对变量直接操作完全一样。   引用的声明方法:类型标识符 &引用名=目标变量名;   【...

19650
来自专栏大闲人柴毛毛

稳扎稳打JavaScript(一)——作用域链内存模型

几个概念 在开始之前,先了解几个概念。 1.1. 作用域 作用域是指当前正在执行的代码能够访问到变量的范围; 每个函数都有各自的作用域,存储函数所有的局部变量...

49080
来自专栏吾爱乐享

java学习之数组元素排序,冒泡排序和选择排序

12840
来自专栏java 成神之路

JAVA对象在JVM中内存分配

391120

扫码关注云+社区

领取腾讯云代金券