注册 登录
编程论坛 C++教室

[求助]运算符重载 运行不正确

cpluslover 发布于 2007-05-03 18:44, 1420 次点击

我又是在书上看的

请看下面例子
对象+double 与double+对象是不一样的;
如果你屏蔽掉那个 RMB(double)构造的话,你会发现都不能运行。必须再定义两个+

但如果按钱能书上说的定义为成员函数的话,就会出现
RMB operator+( RMB& s, double value);
RMB operator+( double value, RMB& s){return s+value;}

参数太多的错误,你若去掉后采用默认参数的话两个的参数又完全一样了,还是会报错。

我于是又改为友元的形式了
如下但还是有个错误不知道是怎么回事啊

源代码如下,请注意我加//部分是屏蔽掉的,不要加上去
//**********************
//** ch18_3.cpp **
//**********************

#include<iostream>
using namespace std;

class RMB
{
public:
RMB(unsigned int d, unsigned int c);
// RMB(double value);
RMB operator+(RMB&);
RMB& operator++();
friend RMB operator+( RMB& s, double value);
firend RMB operator+( double value, RMB& s){return s+value;}
void display(){ cout << (yuan + jf / 100.0) << endl; }
protected:
unsigned int yuan;
unsigned int jf;
};

RMB::RMB(unsigned int d, unsigned int c)
{
yuan = d;
jf = c;
while(jf >=100){
yuan ++;
jf -= 100;
}
}
/*
RMB::RMB(double value)
{
yuan=value;
jf=(value-yuan)*100+0.5;
}
*/
RMB RMB::operator +(RMB& s)
{
unsigned int c = jf + s.jf;
unsigned int d = yuan + s.yuan;
RMB result(d,c);
return result;
}
RMB& RMB::operator++()
{
jf ++;
if(jf >= 100){
jf -= 100;
yuan++;
}
return *this;
}

friend RMB operator+ (RMB& s, double value)
{
s.yuan+=s.value;
s.jf=s.jf;
RMB temp(yuan, jf);
return temp;
}

int main()
{
RMB s (5,8);
s.display();
s=RMB(1,5)+s;
s.display();
s=1+s;
s.display();
s=s+RMB(1,5);
s.display();
s=s+1;
s.display();

return 0;
}

请帮帮忙吧

16 回复
#2
cpluslover2007-05-03 18:48

第二个问题,请看我屏蔽掉的那个构造函数
jf=(value-yuan)*100+0.5;
为什么后面要加个0。5啊,,去了那个0.5后我发现结果确实不太精确

这到底是为什么呢??
#3
aipb20072007-05-03 19:40
你错的很混乱啊!

我看了下你上面的代码,不正确啊,
1,友员函数的定义,不用加关键字了,有个friend拼错了。
2,定义友员重载,没有计算角分的值,temp的参数不对,应该(s.**,s.**)


说实话,还没明白你具体的问题,你描述清楚点,很想帮你!呵呵
#4
aipb20072007-05-03 19:48
对了,我想问问,你是不是不明白为什么缺少了那个单double型参的构造函数,就不能
RMB operator+( RMB& s, double value);
RMB operator+( double value, RMB& s){return s+value;}
这样重载?

是的话,我可以帮你解答!
#5
cpluslover2007-05-03 19:50

这是我拷贝书上的代码,可能 被我弄乱了,
我写了课后第一个题目 遇到的问题是一样的

把我写的代码贴出来给你算了

题目:
定义复数类的加法与减法,使它能够执行下列运算;

Complex a(2,5), b(7,6), c(9,0);
c=a+b;
c=4.1+a;
c=b+5.6;


下面是我写的代码,不能同时实现最后两个要求。4.1+a;b+5.6

#include<iostream>
using namespace std;

class Complex
{
public:
Complex(double, double);
Complex(double value){ a=value;}
Complex operator+(Complex& );

Complex operator+(double value);
friend Complex operator+(double t, Complex& s);//这不用友元没有办法定义啊,会说你参数过多,因为它可以默认一个参数的,你加上了,我的VC++编译器说参数太多
所以我改成了友元,但是还是有个错不知道是怎么回事

void Display();
private:
double a;
double b;
};

Complex:: Complex(double x, double y)
{
a=x;
b=y;
}

Complex Complex::operator+(Complex &s)
{
double A=a+s.a;
double B=b+s.b;
Complex temp(A, B);
return temp;
}

Complex Complex::operator+(double value)
{
double A=a+value;
Complex temp(A, b);
return temp;
}
friend Complex operator+(double t, Complex& s)
{
double A=t+s.a;
Complex temp(A,s.b);
return temp;
}
void Complex::Display()
{
cout<<a<<"+"<<b<<"i"<<endl;
}
int main()
{
Complex a(2,5), b(7, 9), c(0,0);
a.Display();b.Display();c.Display();
c=a+b;
c.Display();
c=4.1+a;
c=b+5.6;
c.Display();

return 0;
}


[此贴子已经被作者于2007-5-3 19:52:39编辑过]

#6
cpluslover2007-05-03 19:57
不是,不过我想问问,难道加上那个构造就可以重载了吗

请你看看我上面写的那个程序更简单点

但遇到的问题是一样的

你让它运行正确也就解决了我的疑问了

谢谢你了
#7
aipb20072007-05-03 20:36

[CODE]#include<iostream>
using namespace std;
class Complex
{
public:
Complex(int, int);
Complex(double value){a=value;b=(value-a)*10;}
friend Complex operator+(Complex,Complex);
// Complex operator+(double value);
//friend Complex operator+(double t, Complex& s);//这不用友元没有办法定义啊,会说你参数过多,因为它可以默认一个参数的,你加上了,我的VC++编译器说参数太多
//所以我改成了友元,但是还是有个错不知道是怎么回事
void Display();
private:
int a;
int b;
};
Complex:: Complex(int x, int y)
{
a=x;
b=y;
}
Complex operator+(Complex s,Complex s2)
{
int A=s.a+s2.a;
int B=s.b+s2.b;
Complex temp(A, B);
return temp;
}
/*
Complex Complex::operator+(double value)
{
double A=a+value;
Complex temp(A, b);
return temp;
}
friend Complex operator+(double t, Complex& s)
{
double A=t+s.a;
Complex temp(A,s.b);
return temp;
}
*/
void Complex::Display()
{
cout<<a<<"+"<<b<<"i"<<endl;
}
int main()
{
Complex a(2,5), b(7, 9), c(0,0);
double m = 4.1,k = 5.6;
a.Display();b.Display();c.Display();
// c=a+b;
// c.Display();
c=m+a;
c.Display();
c=b+k;
c.Display();

getchar();
return 0;
}[/CODE]


#8
aipb20072007-05-03 20:38
其实就是有个隐式类类型转换问题

我上面有个问题也没解决,就是由double计算到两个int!


再想想!
#9
aipb20072007-05-03 20:57

[CODE]#include<iostream>
using namespace std;
class Complex
{
public:
Complex(int, int);
Complex(double);
friend Complex operator+(Complex,Complex);

void Display();
private:
int a;
int b;
};
Complex::Complex(int x, int y)
{
a=x;
b=y;
}
Complex::Complex(double value)
{
a = value;
b = (value - a) * 10 +0.1;
}

Complex operator+(Complex s1,Complex s2)
{
return Complex(s1.a+s2.a,s1.b+s2.b);
}
void Complex::Display()
{
cout<<a<<"+"<<b<<"i"<<endl;
}
int main()
{
Complex a(2,5), b(7, 9), c(0,0);
double m = 4.1,k = 5.6;
a.Display();b.Display();c.Display();
c=a+b;
c.Display();
c=m+a;
c.Display();
c=b+k;
c.Display();

getchar();
return 0;
}[/CODE]

好了,顺便整理了下。
其实你不懂的就是类类型的荫式转换。

在上面的例子中,因为存在一个单型参的构造函数Complex(double),所以在main中用一个double与一个complex相加时,编译器就把这个double对象与单型参函数关联,创建一个临时complex对象执行函数。

若没有定义单型参的构造函数Complex(double),那么这样的操作是不合法的,就需要再定义两个重载+,去匹配complex+double和double+complex。

这样的隐式转换行为是被认可的,但是若不程序员本身不期望这样的隐式转换,就需要在单型参的构造函数Complex(double)前加上关键字 expicit .


还有个问题,就是代码红色部分:b = (value - a) * 10 +0.1;
我想这是个隐式内置类型转换问题,具体是怎样的行为我也弄不明白,还等达人!

#10
cpluslover2007-05-03 21:07

你用的什么编译器啊我用的VC不行啊

出的错误跟我上面的一样的错啊
--------------------Configuration: 18.1 - Win32 Debug--------------------
Compiling...
18.1.cpp
D:\c++程序\xue学习\18.1.cpp(13) : fatal error C1001: INTERNAL COMPILER ERROR
(compiler file 'msc1.cpp', line 1786)
Please choose the Technical Support command on the Visual C++
Help menu, or open the Technical Support help file for more information
Error executing cl.exe.

18.1.obj - 1 error(s), 0 warning(s)

另外,我想你换成int就行了吗,这没有关系吧。 还有这个是复数类的加减,你不用再*10了,

最后再明确一下我所遇到的困惑::::就是不能定义两个运算符重载,但事实上是需要的,如果不用类型转换的话,况且我上面也定义了一个Complex(double)这个也算是个默认的类型转换吧
1:去掉我定义的那个类型转换呢?你怎么定义两个+呢,一个是对象在前,一个是对象在后,它们参数顺序是不一样的,应该可以重载的啊,但是不能,会报错
更不能定义为成员函数,一定义为成员函数,又报错:::too many function parameter

2:你加上那个Complex(double)构造,它也相当于一个把double 转换成 Complex 类的构造吧,按不定义那两个+,也能默认转换对吧,但你试试它不能

请你认真看看我上面说的问题,认真看的话才能发现问题,才能针对我所说的问题进行解决
谢谢了

#11
aipb20072007-05-03 21:23

问题1:去掉单型参的构造函数,可以定义两个+重载,但是必须是友员重载,因为如果是类成员函数的话,需要由对象调用,doubel在前不行。
两个友员重载不会抱错:
friend Complex operator+(const Complex&,const double);
friend Complex operator+(const double d,const Complex &s){return s+d;};

问题2:我试了才会贴上来告诉你,不是我乱掰的,想要的话,我可以给你截图看运行结果。


我认真看了你的问题,不过你确实没怎么描述清楚。

ps:在vc6中友员重载存在一个问题,是编译器问题,不支持标准,在前面的帖子讨论过:
https://bbs.bc-cn.net/viewthread.php?tid=133743&extra=&page=10#112525

还有,看了你的错误信息,似乎不是程序本身的问题吧,应该是编译器哪里冲突,等等,vc++毛病多多!

[此贴子已经被作者于2007-5-3 21:31:58编辑过]

#12
cpluslover2007-05-03 21:31
以下是引用aipb2007在2007-5-3 21:23:11的发言:

问题1:去掉单型参的构造函数,可以定义两个+重载,但是必须是友员重载,因为如果是类成员函数的话,需要由对象调用,doubel在前不行。
两个友员重载不会抱错:
friend Complex operator+(const Complex&,const double);
friend Complex operator+(const double d,const Complex &s){return s+d;};

问题2:我试了才会贴上来告诉你,不是我乱掰的,想要的话,我可以给你截图看运行结果。


我认真看了你的问题,不过你确实没怎么描述清楚。

ps:在vc6中友员重载存在一个问题,是编译器问题,不支持标准,在前面的帖子讨论过:
https://bbs.bc-cn.net/viewthread.php?tid=133743&extra=&page=10#112525

我想我们遇到的问题是不一样的
我看了那个贴子了,我改成了。h了

唯一的区别就是改前编译报告这个错误,
改后编译不报错,但运行报这个错误。

我也不是瞎掰的,在我机器上确实是这样的,,无论是。h还是标准格式。。

#13
aipb20072007-05-03 21:37
那就不知道了,我用的dev-cpp,家里没vc,没办法试。

可能有其他原因吧,呵呵。
#14
yuyunliuhen2007-05-03 21:54
也许是VC++6.0的一个BUG吧,不过还好在VC2005已经修正了。
友员函数在声明的时候需要加上friend,但是在定义的时候就不要加了,暂时还没发现你的那个程序没有其他问题,定义时去掉friend就行了,在VC2005编译运行的图片如下:
只有本站会员才能查看附件,请 登录


再仔细看一下你的程序哈

[此贴子已经被作者于2007-5-3 22:02:14编辑过]

#15
未入流小菜鸟2007-05-03 22:10

//针对5楼的代码,改正如下,红色为修改处。v6中编译通过
#include<iostream>
//using namespace std;//注释掉这句,因为std中也重载了+这个操作符,会与楼主定义的友元+冲突(个人看法,还未证实)。

class Complex
{
public:
Complex(double, double);
Complex(double value){ a=value;}
Complex operator+(Complex& );

Complex operator+ (double value);
friend Complex operator+ (double t, Complex& s);

void Display();
private:
double a;
double b;
};

Complex:: Complex(double x, double y)
{
a=x;
b=y;
}

Complex Complex::operator+(Complex &s)
{
double A=a+s.a;
double B=b+s.b;
Complex temp(A, B);
return temp;
}

Complex Complex::operator+(double value)
{
double A=a+value;
Complex temp(A, b);
return temp;
}
Complex operator+ (double t, Complex& s) //去掉最前面的friend,只需在类中声明为友元,定义处不用
{
double A=t+s.a;
Complex temp(A,s.b);
return temp;
}
void Complex::Display()
{
std::cout<<a<<"+"<<b<<"i"<<std::endl; //加上std
}
int main()
{
Complex a(2,5), b(7, 9), c(0,0);
a.Display();b.Display();c.Display();
c=a+b;
c.Display();
c=4.1+a;
c=b+5.6;
c.Display();

return 0;
}

[此贴子已经被作者于2007-5-3 22:23:02编辑过]

#16
zkkpkk2007-05-03 22:14
到处是人民币......
#17
cpluslover2007-05-03 22:53
以下是引用未入流小菜鸟在2007-5-3 22:10:37的发言:

//针对5楼的代码,改正如下,红色为修改处。v6中编译通过
#include<iostream>
//using namespace std;//注释掉这句,因为std中也重载了+这个操作符,会与楼主定义的友元+冲突(个人看法,还未证实)。

友员函数在声明的时候需要加上friend,但是在定义的时候就不要加了,暂时还没发现你的那个程序没有其他问题,定义时去掉friend就行

我的VC好落后啊

这两个地方全部改过来就对了


谢谢大家了啊  
辛苦了
1