请教一个很弱智的问题——新手过来帮忙,不好意思麻烦高手。

mituzhishi 2003-12-29 05:39:12
最近读到一本有关C++编程的课外书,上面花了一章的篇幅介绍了“重载运算符”的问题,比如:重载赋值运算符,重载加减运算符......
我的问题是:为什么要重载运算符呢?重载运算符有什么好处呢?是不是只会使问题更加复杂化?重载运算符主要在什么情况下运用呢?
问题十分弱智,请勿见笑!
...全文
38 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
cloudtarget 2004-01-02
  • 打赏
  • 举报
回复
不要重载overload &&, ||, or ,.

与C一样,C++使用布尔表达式简化求值法(short-circuit evaluation)。这表示一旦确定了布尔表达式的真假值,即使还有部分表达式没有被测试,布尔表达式也停止运算。例如:

char *p;

...

if ((p != 0) && (strlen(p) > 10)) ...

这里不用担心当p为空时strlen无法正确运行,因为如果p不等于0的测试失败,strlen不会被调用。同样:

int rangeCheck(int index)

{

if ((index < lowerBound) || (index > upperBound)) ...

...

}

如果index小于lowerBound,它不会与upperBound进行比较。

很早以前上述行为特性就被反复灌输给C和C++的程序员,所以他们都知道该特性。而且他们也依赖于简短求值法来写程序。例如在上述第一个代码中,当p为空指针时确保strlen不会被调用是很重要的,因为C++标准说(正如C标准所说)用空指针调用strlen,结果不确定。

C++允许根据用户定义的类型,来定制&&和||操作符。方法是重载函数operator&& 和operator||,你能在全局重载或每个类里重载。然而如果你想使用这种方法,你必须知道你正在极大地改变游戏规则。因为你以函数调用法替代了简短计算法。也就是说如果你重载了操作符&&,对于你来说代码是这样的:

if (expression1 && expression2) ...

对于编译器来说,等同于下面代码之一:

if (expression1.operator&&(expression2)) ...

// when operator&& is a

// member function

if (operator&&(expression1, expression2)) ...

// when operator&& is a

// global function

这好像没有什么不同,但是函数调用法与简短求值法是绝对不同的。首先当函数被调用时,需要运算其所有参数,所以调用函数functions operator&& 和 operator||时,两个参数都需要计算,换言之,没有采用简短计算法。第二是C++语言规范没有定义函数参数的计算顺序,所以没有办法知道表达式1与表达式2哪一个先计算。完全与具有从左参数到右参数计算顺序的简短计算法相反。

因此如果你重载&&或||,就没有办法提供给程序员他们所期望和使用的行为特性,所以不要重载&&和||。

同样的理由也适用于括号操作符,但是在我们深入研究它之前,我还是暂停一下,让你不要太惊讶,“逗号操作符?哪有逗号操作符?”确实存在。

逗号操作符用于组成表达式,你经常在for循环的更新部分(update part)里遇见它。例如下面来源于Kernighan's and Ritchie's 经典书籍The C Programming Language 第二版(Prentice-Hall, 1988)的函数:

// reverse string s in place

void reverse(char s[])

{

for (int i = 0, j = strlen(s)-1;

i < j;

++i, --j) // 啊! 逗号操作符!

{

int c = s[i];

s[i] = s[j];

s[j] = c;

}

}

在for循环的最后一个部分里,i被增加同时j被减少。在这里使用逗号很方便,因为在最后一个部分里只能使用一个表达式,分开表达式来改变i和j的值是不合法的。

对于内建类型&&和||,C++有一些规则来定义它们如何运算。与此相同,也有规则来定义逗号操作符的计算方法。一个包含逗号的表达式首先计算逗号左边的表达式,然后计算逗号右边的表达式;整个表达式的结果是逗号右边表达式的值。所以在上述循环的最后部分里,编译器首先计算++i,然后是—j,逗号表达式的结果是--j。

也许你想为什么你需要知道这些内容呢?因为你需要模仿这个行为特性,如果你想大胆地写自己的逗号操作符函数。不幸的是你无法模仿。

如果你写一个非成员函数operator,你不能保证左边的表达式先于右边的表达式计算,因为函数(operator)调用时两个表达式做为参数被传递出去。但是你不能控制函数参数的计算顺序。所以非成员函数的方法绝对不行。

剩下的只有写成员函数operator的可能性了。即使这里你也不能依靠于逗号左边表达式先被计算的行为特性,因为编译器不一定必须按此方法去计算。因此你不能重载逗号操作符,保证它的行为特性与其被料想的一样。重载它是完全轻率的行为。

你可能正在想这个重载恶梦究竟有没有完。毕竟如果你能重载逗号操作符,你还有什么不能重载的呢?正如显示的,存在一些限制,你不能重载下面的操作符:

. .* :: ?:

new delete sizeof typeid

static_cast dynamic_cast const_cast reinterpret_cast

你能重载:

operator new operator delete

operator new[] operator delete[]

+ - * / % ^ & | ~

! = < > += -= *= /= %=

^= &= |= << >> >>= <<= == !=

<= >= && || ++ -- , ->* ->

() []

(有关new和delete还有operator new, operator delete, operator new[], and operator delete[]的信息参见条款8)

当然能重载这些操作符不是去重载的理由。操作符重载的目的是使程序更容易阅读,书写和理解,而不是用你的知识去迷惑其他人。如果你没有一个好理由重载操作符,就不要重载。在遇到&&, ||, 和 ,时,找到一个好理由是困难的,因为无论你怎么努力,也不能让它们的行为特性与所期望的一样。
碧蓝右耳 2004-01-01
  • 打赏
  • 举报
回复
举例来说,数学里的矩阵本身是没有加法和乘法的,
但我们可以定义他的乘法和加法
变量,复数,多项式,函数都可以定义乘法和加法
针对不同的对象,加法的意义和运算方法都不同
这种定义过程就是运算符重载,其实是借用已有的符号来表示一种运算而已
shuishuangyu 2004-01-01
  • 打赏
  • 举报
回复
举例:如基本数据类型中的加法可以直接做,整数加整数

类对象就不能了,这个时候如果重载运算符就可以像基本数据类型那样了
glacierrr 2004-01-01
  • 打赏
  • 举报
回复
这个问题很好回答,重载运算符就是为了人们理解的方便,如同
int a, b, c;
c = a + b;一样

MyClass a1, b1, c1;
c1 = a1 + b1;也可以运行

MyClass(自定义类型)和int(内建类型)都是我们使用的类型,那么使用方式就应该一样,而自定义类型只能用函数MyClass sum(MyClass, MyClass),显然就违背了一点。

面向对象的本质就是使用人们在日常生活中积累的经验和习惯的思维方式来看问题。
Inkick 2004-01-01
  • 打赏
  • 举报
回复
同意风之子和皮皮的看法

operator overload是指对+ - * / [] >> <<等操作符进行的重新定义,作用就是告知编译器,如何根据操作符的操作数的类型,确定执行的操作

比如说我们有一个MyString的类,作用是保存任意长度的字符串,我们可以定义+操作符,使得+操作对于两个MyString类相连~

  • 打赏
  • 举报
回复
robin97(smile) :当然了。
上面我已经说过,运算符是作为类的特殊成员函数或友元函数来重载的。
而在类外,运算符就是运算符,你怎么“重新定义它”?
robin97 2004-01-01
  • 打赏
  • 举报
回复
只能用于类?
soyan 2003-12-29
  • 打赏
  • 举报
回复
怎么可能使问题复杂化.
看来还是要深入了解面向对象
datablader 2003-12-29
  • 打赏
  • 举报
回复
比如+,我们知道4+5 =9,那么A+B等于什么呢?没有+号的法则定义,每个人都有一种结果。但是,如果我告诉你+的方法是ASCII进行相加,那么大家都知道都知道怎么去处理A+B了。所以,运算符重载就是告诉你两个类用运算符连接在一起之后该怎么处理。
redhat_xu 2003-12-29
  • 打赏
  • 举报
回复
重载当然有它的好处,首先它是面向对象编程的一个重要特点,

另外运算符重载也有它的好处,比如:一般函数都是这种类型:数据类型 函数名(参数表)
使用该函数是:函数名(参数一,参数二);
然而使用运算符重载后,声明部分同普通函数一样,只是多了一个关键字operator,然而它的使用却是:参数一(运算符)参数二,非常符合我们做运算的习惯.

最后是运算符重载它表现的是类与类进行直接运算,而不是基本数据类型进行运算,不然,就会是这样:
类名::类数据成员(运算符)类名::类数据成员
如果类数据成员是私有或保护类型,将会变得更复杂.
  • 打赏
  • 举报
回复
sorry , “重载运算符”是用于“类”的,且只能用于类。而函数重载用于成员函数和外部函数均可。
  • 打赏
  • 举报
回复
“重载”是用于“类”的,对于“类”来讲,运算符就是一种特殊的成员函数。

你对“类”对象使用运算符,而编译器却不知道如何运算,因为“类”不是基本数据类型嘛。
因此需要对运算符重新进行定义。
qhu 2003-12-29
  • 打赏
  • 举报
回复
我也是新手,我的看法是:
运算符两边的类型不同,就得调用不同的函数处理,而重载把选择函数的任务交给编译器,既减少了人脑出错的机会,也使代码可读性更高。


65,208

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧