C++ Chain Operations

本文详细探讨了C++中的链式操作,包括如何理解其运算顺序、类的链式赋值原理,以及如何通过重载操作符实现输入输出的链式效果。重点讲解了赋值操作符的返回值类型对效率的影响和正确实践。

The order of evaluating chain operators is dependent on the associativity of the operators'

Order of evaluation of any part of any expression, including order of evaluation of function arguments is unspecified (with some exceptions listed below). The compiler can evaluate operands and other subexpressions in any order, and may choose another order when the same expression is evaluated again.

There is no concept of left-to-right or right-to-left evaluation in C++. This is not to be confused with left-to-right and right-to-left associativity of operators: the expression a() + b() + c() is parsed as (a() + b()) + c() due to left-to-right associativity of operator+, but the function call to c may be evaluated first, last, or between a() or b() at run time:

example for chain-assignment: C++的链式赋值_云破林梢添远岫的博客-优快云博客_c++ 链式赋值

from: C++中的链式操作 - yutingliuyl - 博客园

C++中的链式操作

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


1.什么是链式操作

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

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

===> chain assignments are by default right to left

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.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值