按照你这样的后++方式,就不是自增的含义了,正确的方式是:
Complex Complex::::operator++(int)
{
Complexc = this;
++(this);//调用前++ (this)operator++()
return c;
}
myint++的返回值是一个const限定的右值,想要传引用的话在函数定义参数那行MyInteger前面加上一个const。
不加引用符号是按值传递,那么即便不打限定符const,改变传入参数的值也不会影响到原来的值,所以不加引用不会出错。
后缀++的原则是先取值,再自加,需要用中间值保存this对象原始值,自加完毕后,再返回这个中间值
const numCal numCal::operator++(int){
numCal temp(this);
for(int i(0);i<size;i++)arr[i]++;
return temp;
}
前面类体中的原型也改一改,返回值前加上const,避免像主函数中的后缀前缀一起用
重载的“=”有漏洞,也有内存泄漏,应该这样:
numCal&numCal::operator=(const numCal&num){
if (this != &num)
{
delete [] arr;
size=numsize;
arr=new int[size];
for(int i(0);i<numsize;i++)
arr[i]=numarr[i];
}
return this;
}
还有,主函数中的:
for(int i(0);i<6;i++)cout<<numarr[i]<<" ";这个arr是私有成员
for(int i(0);i<10;i++)cout<<numarr[i]<<" ";同上,这个i<10要改为i<9
num=++num3++;先后缀之后得到的是值,不能再前缀自加了,去掉前缀
C语言中,运算符除了常见的三大类,算术运算符、关系运算符与逻辑运算符之外,还有一些用于完成特殊任务的运算符。
运算符的运算优先级共分为15 级,1 级最高,15 级最低。 在表达式中,优先级较高的先于优先级较低的进行运算。而在一个运算量两侧的运算符 优先级相同时,则按运算符的结合性所规定的结合方向处理。
一级运算符:标识,常量,字符串文字量,优先级提升表达式最优先执行。
二级运算符:数组下标运算(expression)、函数调用(argument-expression-list)、成员访问(identifier、 -> identifier)、后缀自增(i++)、后缀自减(i--)、 复合初始化(initializer-list)。
三级运算符:前缀自增(++i)、前缀自减(--i)、单目转型表式式(取地址& ,提领 , 正号+ ,负号-、 位反~ 逻辑否!)、求类型长度(sizeof unary-expression)。
四级运算符:强制表达式成为type-name指定的类型( type-name ) cast-expression。
五级运算符:“ ” 乘法运算符。
六级运算符:“ + ”加法运算符。
七级运算符:<< 左移运算符;>> 右移运算符。
八级运算符:<、<=、>、>=关系运算符。
九级运算符:“ == ”等于运算符;“ != ”不等于运算符。
十级运算符:“ & ”按位与运算符。
十一级运算符:“ ∧ ”按位异或运算符。
十二级运算符:“ | ”按位或运算符。
十三级运算符:“&&”逻辑与运算符。
十四级运算符:“ || ”逻辑或运算符。
十五级运算符: :条件运算符。
扩展资料
C语言中各运算符的结合性:
1、左结合性(自左至右):
例如算术运算符的结合性是自左至右,即先左后右。如有表达式x-y+z 则y 应先与“-”号结合,执行x-y 运算,然后再执行+z 的运算。这种自左至右的结合方向就称为“左结合性”。
2、右结合性(自右至左)
自右至左的结合方向称为“右结合性”。最典型的右结合 性运算符是赋值运算符。如x=y=z,由于“=”的右结合性,应先执行y=z 再执行x=(y=z)运算。C语言运算符中有不少为右结合性,应注意区别,以避免理解错误。
——C语言运算符
我知道问题出在哪,但是这个BUG逻辑,我确实没算出来。。。是因为实在太难了。。
输出错误的原理在于,++,--和<<的优先级上。
C++的符号优先级是C语言的优先级一样的,所以<<虽然被cout用于重载输出用,但是实际上还是左移运算符的优先级,然而<<左移运算符的优先级比++,--的优先级都低,所以先做++,--,然后才输出,因为输出有多个<< 这样的左移运算符,所以输出是按从做到右的顺序做的,然而输出前的++,--确实先做的,而且++,--优先级高,然后最大的BUG就出现了,因为++,--的运算,是右边的先做,然后在做左边的,所以第一个输出3。
因为输出第一个d++的时候,是先从最右边的--d开始的,然后做d--,再做++d,最后才是输出第一个d++,这时候,先输出d,所以这个时候的值是3,然后自增的,所以第二个就是4,至于后面两个,就触发BUG了,d到底是多少啊?按道理,后面的两个d--,--d的运算早就做了,输出的时候应该是直接输出d的值的,然而也不是,已经搞不清楚编译器面对这样的BUG是怎么处理的了。。只能判断出前两个,第一个是3没错,做完直接++了,所以第二个输出4,因为第二个++d,根本不做++了,++早就在输出第一个值之前做完了,应该直接输出第一个运算之后的d的值,同理第三,第四,也应该是同一个值,但是却不是。。。已经搞不清楚编译器是怎么处理的了。。。
解决方法:你的本意就是从左向右一个一个输出,但是<<运算符的优先级太低了,所以只要一个一个的加上括号,保证每个d++,--d这样的运算做完,马上保证<<输出运算符的优先级,即可不会触发这个BUG,即应该改成((((cout<<d++)<<++d)<<d--)<<--d)<<endl;
即可保证输出都是正确的,每次都是先做第一个++,--操作后,马上<<进行输出,结果之间不会干扰。
这样的BUG,就像C语言里的C=C+C++,这样的BUG,C语言里,这样的程序也是会出BUG的,因为C+C++这样的运算,又要用到变量C的值,却又对变量C的值进行了更改,结果是很危险的。。。你这里的BUG和C语言里这样的BUG是同一个原理。。。。
运算符重载,虽然是重定义运算符函数;
但是不能违背运算符原来的基本性质;
而++是一元操作符,即隐含的this指针;
而多出的Int只是为了区分前自增和后自增,并没有其他用处。
a=a+3i; //使用了系统合成的赋值操作符
赋值操作符、copy构造函数、析构函数被称为类的复制控制。当类中存在指针数据成员时,通常
必须重定义类的复制控制,而不能使用系统合成的复制控制;除非,你不使用复制控制。很显然
在上面的语句中,你运用了系统合成的赋值操作符
分析a=a+3i; 这句代码。
首先,调用+操作符的重载函数,在集合a中添加了3i这个元素;
然后,调用合成赋值操作符函数Set& operator = (const Set &);a自己给自己赋值。
函数返回对a的引用,即返回a自己。
分析
Set& Set::operator |(Set &s) //并集
{
Set temp(Size+sSize);
……
return temp;
}
你返回了temp这个局部变量的引用,这是错误的,因为在该函数执行完毕以后,temp就被撤销
了(即系统自动调用了temp的析构函数)。所以你只要在程序中写了析构函数,你的程序就会
出错。那应该怎么办呢?返回Set类型就可以了,这就意味着使用a|b这句代码地方,系统会定
义一个没有名字的临时变量(假设它的名字为T),并且用返回值temp来初始化这个临时变量。
即相当于调用了你定义的copy构造函数T(a|b);
分析
d=a|b;这句代码。
首先:
同样使用a|b这句代码地方,系统会定义一个没有
名字的临时变量(假设它的名字为T),并且用返回值temp来初始化这个临时变量。即相当于调
用了你定义的copy构造函数T(a|b);
然后:
调用了系统合成的赋值操作符函数,其实合成的构造函数就是下面的这个函数:
Set& operator = ( const Set &r )
{
Size = rSize;
Elems = rElems;
Num = rNum;
}
调用上面函数的结果是把T这个临时变量的Elems(它是一个指针)的值直接赋给了d的Elems成
员变量,然后系统就会撤销T这个临时变量(即调用T的析构函数),这样d的Elems将成为一个
悬垂指针。悬垂指针指向曾经存放对象的内存,但是该对象已经不再存在了。悬垂指针往往导致
程序错误,而且很难检测出来。
可以看出,你的程序必须定义自己的赋值操作符函数。这样才能正确执行d=a|b;这句代码。
下面是赋值操作符函数:
Set& Set::operator= ( const Set &r )
{
Size = rSize;
Num = rNum;
if ( this != &r )
{
Elems = new int[Size];
}
else
{
return this;
}
for ( int i = 0; i < Num; i++ )
{
Elems[i] = rElems[i];
}
return this;
}
花了我好长时间,你应该请我吃饭阿
欢迎分享,转载请注明来源:浪漫分享网
评论列表(0条)