游戏开发论坛

 找回密码
 立即注册
搜索
查看: 8687|回复: 6

C++基本功和 Design Pattern系列(4) Operator 上

[复制链接]

27

主题

179

帖子

259

积分

中级会员

Rank: 3Rank: 3

积分
259
发表于 2006-11-13 06:33:00 | 显示全部楼层 |阅读模式
======================================================
大家请把我的文章当参考,详细内容  还请参照 权威书籍
<c++ programming language>如果文中有错误和遗漏,
请指出,Aear会尽力更正, 谢谢!
======================================================

废话不多说,这次讲的是 Operator overload. 关于operator, 在 < The C++ Programing Language > 里的描述,可以用做overload的如下:

+ * / % ^ & | ~ ! = < > += = *= /= %= ^= &= |= << >> >>= <<= == != <=
>= && || ++ >* , > [] () new new[] delete delete[]

先从 operator = 说起。上章中Aear已经提到过,这里再次强调下,只要是在class member中有 pointer的存在,class 就应该提供 copy constructor 和 operator =.

除了 operator =以外,最常用的operator就是 + - * / += -+ *= /= ++ --。 由于四则运算大同小异,我们就拿简单的 + 来举例子说明。让我们看下下面的这段代码有什么问题:

class Test {
private:
    int internalData;
public:
    // constructor and destructor
    Test(int data = 0) : internalData(data) {};
    Test(const Test & Para) : internalData(Para.internalData) {};
    ~Test() {};
  
    // Operator overlording
    Test & operator += (const Test & Para1);
    Test operator + (const Test & Para1);
};

Test & Test:perator += ( const Test & Para1 )
{
    internalData += Para1.internalData;
    return * this;
}

Test Test::operator + (const Test & Para1)
{
    Test result;
    result.internalData = internalData + Para1.internalData;
    return result;
}

首先让我们比较一下 += 和 + 两个operator的效率,我们可以看到,在"+="中,返回的是 *this的reference,而在+中,返回的是一个临时创建的 result,并且 result object在返回的过程中,由于是return by value,因此compiler会掉用copy constructor把result拷贝到返回值中,然后掉用 result.~test()销毁掉这个临时变量。也就是说,使用 + 比 += 要产生更多的overhead。在某些效率第一的情况下,临时变量的constructor和destructor都是非常昂贵的操作。比如:

=============one temporary object=============
Test x1 = x2 + x3;

为了提高效率,我们可以这么写:

=============no temporary object=============
Test x1(x2);
x1 += x3;     

简单一点的表达式有可能会被compiler优化掉,但是复杂的表达式,只能才用手动的形式优化。

让我们再仔细的看下 Test Test::operator + (const Test & Para1) 这个函数。如果考虑程序的具体实现,我们可以看出来 operator += 和 operator +没有本质的却别,但是如果我们需要改动 Test + 的操作,就必须同时更改 operator += 和 operator + 实现,对同一种功能在几处不同的地方进行维护,并不是良好的设计,因此,我们应该对 Test Test::operator + (const Test & Para1) 做如下改动,使得程序更加容易维护:

=============easy to maintain=============
Test Test::operator + (const Test & Para1)
{
    Test result(*this);
    result += Para1;
    return result;
}

可以看到在operator +里调用了 +=的操作,因此,如果我们需要给加法赋予不同的含义,只需要更改 operator += 就足够了。

让我们继续深入的看 Test Test::operator + (const Test & Para1)。值得强调的是,无论如何temporary object是必须存在的,无数大师的经验证明,想用static member, dynamic memory等方法消除掉 temporary object 的 construction 和 destruction,都会产生这样或者那样的逻辑和程序错误。

但是我们仍然可以利用compiler来对这个temporary object进行优化。对于Test Test::operator + (const Test & Para1) 这样的操作,compiler会传递给 operator + 一个 temporary object, 如果 operator +里的代码合适,那么compiler就会用这个temporary object 代替程序里创建的temporary object,从而减少了constructor和destructor的掉用。经过compiler优化后的pseudocode如下:

Test::operator + (Test & Temporary, const Test & Para1)
{
    Temporary.internalData = internalData + Para1.internalData;
    return;
}

这样减少了temporary object 的construction 和 destruction,效率就会提高很多,但是要想使compiler能够进行 return by value的优化,必须满足2个条件:

1. class 必须有 copy constructor
2. 在代码中明确表示,返回的是个temporary object.

因此,出了提供copy constructor外,还必须对 operator + 进行适当的修改,最终代码如下:

==========Final Version for Maintenance and Optimization==========

Test Test::operator + (const Test & Para1)
{
    return Test(*this) += Para1;
}

在这个代码里边,最明显的区别就是没有result这个变量,而是返回一个临时创建的Test object,因此compiler就会知道这个函数可以用临时变量优化。

也许你会感到惊讶,不过这个operator +还不是最快速的。因为我们看到,在Test(*this) += Para1 的过程中,调用了一次constructor 一次 operator +=,但是已经足够了。不过为了效率,我们有更加极端的方法,在如下的代码中,我们舍弃了可读性,可维护性等等,只为了更快的速度:

==========糟糕的风格,不过更快==========
class Test {
    ...   
private:
    // cosntructor for operator +
    Test(int data, const Test & Para1 ) : internalData(data + Para1.internalData) {};
};

Test Test::operator + (const Test & Para1)
{
    return Test(internalData, Para1);
}

如果同时还要定义 operator - * /等操作的constructor,我们可以适当更改constructor的signature,从而可以用constructor实现不同的运算

关于operator第一部分今天就说这么多,大家有空去坐坐 http://blog.sina.com.cn/u/1261532101 下次见。


8

主题

716

帖子

716

积分

高级会员

Rank: 4

积分
716
发表于 2006-11-13 16:31:00 | 显示全部楼层

Re:C++基本功和 Design Pattern系列(4) Operator 上

多谢分享
aear的文章越来越好了

PS,对于"return by value"导致的函数变异,建议去看<<inside the c++ object model>>,或者下面的链接也说得很详细: http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.9

除了最后举的那个例子实在garbage design,看上去像是昆仑派的七伤拳. 去掉就perfect了

35

主题

370

帖子

376

积分

中级会员

Rank: 3Rank: 3

积分
376
发表于 2006-11-14 21:12:00 | 显示全部楼层

Re:C++基本功和 Design Pattern系列(4) Operator 上

初看了下觉的楼主写的和主题 Design Pattern 不一样哦,或许是我没看完全,大多篇幅不在设计模式...,第一篇看到提了个代理

1

主题

18

帖子

18

积分

新手上路

Rank: 1

积分
18
发表于 2006-11-15 14:19:00 | 显示全部楼层

Re:C++基本功和 Design Pattern系列(4) Operator 上

不错不错,坚持

这样的文章收益面很大

模式,慢慢来

2

主题

112

帖子

112

积分

注册会员

Rank: 2

积分
112
发表于 2006-11-15 15:38:00 | 显示全部楼层

Re: Re:C++基本功和 Design Pattern系列(4) Operator 上

smile636: Re:C++基本功和 Design Pattern系列(4) Operator 上

初看了下觉的楼主写的和主题 Design Pattern 不一样哦,或许是我没看完全,大多篇幅不在设计模式...,第一篇看到提了个代理

那是因为楼主的标题是“C++基本功Design Pattern系列”:)

8

主题

130

帖子

156

积分

注册会员

Rank: 2

积分
156
发表于 2006-11-16 10:07:00 | 显示全部楼层

Re: Re:C++基本功和 Design Pattern系列(4) Operator 上

千里马肝: Re:C++基本功和 Design Pattern系列(4) Operator 上

多谢分享
aear的文章越来越好了

PS,对于"return by value"导致的函数变异,建议去看<<...


由于有返回值优化技术(C++标准要求,现在的gcc/vc都支持,我想icc和bc都应该也支持,我一般就试下gcc和vc8),返回对象的情况和C++FAQ的说法已经不同了(最开始是只能优化无具名对象,后来允许分析优化具名对象:就是允许将返回的对象构建在返回值上,不再需要copy constructor和 operator =的调用了,也不存在destructor的开销)。

8

主题

130

帖子

156

积分

注册会员

Rank: 2

积分
156
发表于 2006-11-16 10:09:00 | 显示全部楼层

Re: Re:C++基本功和 Design Pattern系列(4) Operator 上

hljgameres: Re:C++基本功和 Design Pattern系列(4) Operator 上

不错不错,坚持

这样的文章收益面很大

模式,慢慢来

模式本来就是一个经验总结,一个相对比较固定的方式、思路。所以,Operaor重载可以算模式(不过,我猜测作者本意可能和那位兄弟一样,也没有想operator重载是否算模式)。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2026-1-25 20:49

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表