LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
楼主: DoDo

[求助]C++中运算符重载时出错

[复制链接]
发表于 2003-6-23 12:51:24 | 显示全部楼层
对齐一下源码啊
libinary兄的筌名不是写得很清楚吗

太乱了没法看
 楼主| 发表于 2003-6-23 14:03:43 | 显示全部楼层
不好意思,这里重发一下.为什么没有编辑旧帖子的功能呢?

  1. const int BASE=10;
  2. class hInt
  3. {
  4.   private:
  5.     int    sign;
  6.     int    length;
  7.     char * number;

  8.     void new_number(int);
  9.     void check();

  10.     void abs_add(const hInt &,const hInt &);
  11.     void abs_sub(const hInt &,const hInt &);
  12.     int  abs_bes(const hInt &);
  13.   public:
  14.     hInt();
  15.     hInt(char *);
  16.     ~hInt();
  17.     void to_str(char *);

  18.     void operator=(const hInt &);
  19.     void operator=(char *);
  20.     hInt friend & operator+(const hInt &,const hInt &);
  21. };
  22. //private
  23. void hInt::new_number(int i)
  24. {
  25.   delete []number;
  26.   number=new char[i+1]; //note:char[i] is not necessary
  27.   number[i]=0;      //but let char[i]=0 can make it easy to watch
  28. }
  29. void hInt::check()
  30. {
  31.   if(length<0) return; //error, maybe no chance to happen
  32.   if(length==0) { sign=0; return; }
  33.   char * p=number+length-1;
  34.   while((*(p--)==0)&&(length>0)) length--;
  35.   if(length==0) sign=0;
  36. }
  37. void hInt::abs_add(const hInt & ha,const hInt & hb)
  38. {
  39.   //length and number[] will be made up here, but nothing to do with sign
  40.   int l1,l2;
  41.   char * p1, * p2;
  42.   if(ha.length>hb.length)
  43.   { l1=ha.length; l2=hb.length; p1=ha.number; p2=hb.number; }
  44.   else
  45.   { l2=ha.length; l1=hb.length; p2=ha.number; p1=hb.number; }
  46.   length=l1+1;
  47.   new_number(length);
  48.   char * p=number;
  49.   int i;
  50.   char t=0;
  51.   for(i=0;i<l2;i++)
  52.   {
  53.     t+=*(p1++)+*(p2++);
  54.     if(t>=BASE) { *(p++)=t-BASE; t=1; }
  55.     else        { *(p++)=t     ; t=0; }
  56.   }
  57.   for(;i<l1;i++)
  58.   {
  59.     t+=*(p1++);
  60.     if(t>=BASE) { *(p++)=t-BASE; t=1; }
  61.     else        { *(p++)=t     ; t=0; }
  62.   }
  63.   *p=t;
  64. }
  65. void hInt::abs_sub(const hInt & ha,const hInt & hb)
  66. {
  67.   //abs(ha) mustn't be smaller than abs(hb)
  68.   int l1=ha.length, l2=hb.length;
  69.   char * p1=ha.number, * p2=hb.number;
  70.   length=l1;
  71.   new_number(length);
  72.   char * p=number;
  73.   int i;
  74.   char t=0;
  75.   for(i=0;i<l2;i++)
  76.   {
  77.     t+=*(p1++)-*(p2++);
  78.     if(t>=0) { *(p++)=t     ; t= 0; }
  79.     else     { *(p++)=t+BASE; t=-1; }
  80.   }
  81.   for(;i<l1;i++)
  82.   {
  83.     t+=*(p1++);
  84.     if(t>=0) { *(p++)=t     ; t= 0; }
  85.     else     { *(p++)=t+BASE; t=-1; }
  86.   }
  87. }
  88. int hInt::abs_bes(const hInt & h)
  89. {
  90.   if(length>h.length) return 1;
  91.   if(length<h.length) return -1;
  92.   char * p1=number+length-1, * p2=h.number+length-1;
  93.   for(int i=0;i<length;i++)
  94.   {
  95.     if(*p1>*p2) return 1;
  96.     if(*p1<*p2) return -1;
  97.     p1--; p2--;
  98.   }
  99.   return 0;
  100. }
  101. //public
  102. hInt::hInt()
  103. {
  104.   number=new char[1];
  105. }
  106. hInt::hInt(char * s)
  107. {
  108.   number=new char[1];
  109.   *this=s;
  110. }
  111. hInt::~hInt()
  112. {
  113.   delete []number;
  114. }
  115. void hInt::to_str(char * s)
  116. {
  117.   char * p=number+length-1;
  118.   if(sign==-1) *(s++)='-';
  119.   for(int i=0;i<length;i++) *(s++)=*(p--)+'0';
  120.   if(i==0) *(s++)='0';
  121.   *s=0;
  122. }
  123. void hInt::operator=(const hInt & h)
  124. {
  125.   sign=h.sign;
  126.   length=h.length;
  127.   new_number(length);
  128.   char * p1=number;
  129.   char * p2=h.number;
  130.   for(int i=0;i<length;i++) *(p1++)=*(p2++);
  131. }
  132. void hInt::operator=(char * s)
  133. {
  134.   while(*s==' ') s++;
  135.   sign=1;
  136.   if(*s=='-') { sign=-1; s++; }
  137.   if(*s=='+') s++;
  138.   length=0;
  139.   while((s[length]>='0')&&(s[length]<='9')) length++;
  140.   if(length==0) return; //error
  141.   new_number(length);
  142.   for(int i=0;i<length;i++) number[length-i-1]=s[i]-'0';
  143.   check();
  144. }
  145. hInt & operator+(const hInt & ha,const hInt & hb)
  146. {
  147.   hInt * h;
  148.   h=new hInt;
  149.   if(hb.sign==0) { *h=ha; return *h; }
  150.   if(ha.sign==0) { *h=hb; return *h; }
  151.   if(ha.sign==hb.sign)
  152.   {
  153.     h->sign=ha.sign;
  154.     h->abs_add(ha,hb);
  155.     h->check();
  156.     return *h;
  157.   }
  158.   else
  159.   {
  160.     int t=ha.abs_bes(hb);
  161.     if(t==0)
  162.     {
  163.       h->sign=0;
  164.       h->length=1;
  165.       h->new_number(1);
  166.       *h->number=0;
  167.       return *h;
  168.     }
  169.     if(t==1)
  170.     {
  171.       h->sign=ha.sign;
  172.       h->abs_sub(ha,hb);
  173.       h->check();
  174.       return *h;
  175.     }
  176.     h->sign=hb.sign;
  177.     h->abs_sub(hb,ha);
  178.     h->check();
  179.     return *h;
  180.   }
  181. }
  182. //---------------------------------------------------------------------------
  183. #include <iostream.h>
  184. void set_str(char * t,const char * f)
  185. {
  186.   while(*(t++)=*(f++)) ;
  187. }
  188. void main()
  189. {
  190.   cout<<"test begin"<<endl;
  191.   char s[256];
  192.   hInt h1("1"),h2("9"),h3;
  193.   h3=h1+h2;
  194.   h3.to_str(s);
  195.   cout<<s<<endl;
  196.   cout<<"test end"<<endl;
  197. }
  198. //---------------------------------------------------------------------------
复制代码
发表于 2003-6-23 17:59:40 | 显示全部楼层
说一下传参数和返回值类型的时候的复制构造函数,

  1. class A{...};
  2. A func(A a)
  3. {
  4.   return a;
  5. }
  6. int
  7. main(void)
  8. {
  9.   A m, n;
  10.   n = func(m);
  11.   return(0);
  12. }
复制代码

主要说func(),在main中调用n = func(m)时,首先调用复制构造函数把m复制给了a,而返回a的时候实际上返回了一个临时对象,首先调用复制构造函数把a复制给临时对象作为函数的返回,这是返回值的情况,如果返回引用就不会调用复制构造函数,因为实际返回的是地址,如果返回局部变量的引用的话就会遇到你说的变量已经析构的问题,如果返回值的话就可以,不过你的类有内存分配的问题,所以必须提供复制构造函数。
 楼主| 发表于 2003-6-23 19:11:24 | 显示全部楼层
多谢指点.但小弟愚笨,还是有点不太明白:

照版主这么说,如果直接返回值的话,系统会完成临时变量的申请和释放.
我在发现问题之前,程序就是

  1. hInt operator+(const hInt & ha,const hInt & hb)
  2. {
  3.   hInt h;
  4.   if(hb.sign==0) return ha;
  5.   if(ha.sign==0) return hb;
  6.   ......
  7.   return h;
  8. }
复制代码

这样的,直接返回其值,但当后来当计算的值稍大,比如:

  1. void main()
  2. {
  3.   cout<<"test begin"<<endl;
  4.   char s[256];
  5.   hInt h1("1"),h2("9999999999999999999999"),h3;
  6.   h3=h1+h2;
  7.   h3.to_str(s);
  8.   cout<<s<<endl;
  9.   cout<<"test end"<<endl;
  10. }
复制代码

当h3=h1+h2;执行完成后,h2的number地址不变,但内容却不对了,而程序中根本没有改变过h2.同时程序结束在释放h3再释放h2时就"该程序执行了非法操作"(我是在Windows98下的Turbo C++ 3.0环境下).我不知道是怎么回事

至于版主说的"复制构造函数",没听说过,书里也没有.我只知道构造函数.

我高中刚毕业,想提前学一下,所以是看书自学的,知识的掌握显然有很多漏洞,希望并且感谢大家的耐心帮助
发表于 2003-6-23 20:11:10 | 显示全部楼层
operator =什么会是返回void呢
应该是返回指针或是引用
 楼主| 发表于 2003-6-23 20:51:19 | 显示全部楼层
operator=应该是返回void啊,它不是对*this本身进行改变吗?
 楼主| 发表于 2003-6-23 20:56:23 | 显示全部楼层
关于libinary版主的回复我又想了想,是不是这个意思,一个类的实例创建后就不应该再为内部的指针申请内存?那operator=该怎样实现呢?

要不然我还是用这之前写的那个预先规定了最大长度的类得了.
发表于 2003-6-23 21:08:25 | 显示全部楼层
你上面的问题主要就是没有提供复制构造函数,复制构造函数的形式是

  1. class A{
  2. public:
  3.   A(const A &a){...}
  4. ...
  5. }
复制代码

带一个const A&或A&参数,比如对象初始化的时候就要用到复制构造函数:
A a;
A b(a); // 这里用到复制构造函数
如果你不提供复制构造函数的话,编译器就为你生成一个,就是按位拷贝,把b的数据直接拷到a里,你说的h2和h3的问题是因为位拷贝以后number是相同的,而number是一个指针,所以最后h2和h3中的number指向了同一个地址,h2的数据改变就是因为这个,“该程序执行了非法操作”是因为h2和h3析构的时候各自释放了number(delete),当对number第二次delete的时候就出现了非法操作。
 楼主| 发表于 2003-6-23 21:15:54 | 显示全部楼层
是这样的!
我再试试.再次感谢!
发表于 2003-6-23 21:16:51 | 显示全部楼层
类里重要的成员函数有构造函数、析构函数、复制构造函数、赋值运算符,复制构造函数和赋值运算符的作用比较象,但用的场合不同,如果类里有自己管理的指针的话一般这几个成员函数都要提供,否则就会出现错误,当然,如果你很小心的永远不使用初始化和赋值也没有问题,呵呵,实际上这是很难避免的。
再有,复制构造函数一般书里都讲,因为是很重要的成员函数,你再好好看看。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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