|
蓝森林 http://www.lslnet.com 2006年6月6日 10:18
c++函数重载问题讨论!!
下面的“=”函数重载是错的,但只要把[color=red]string operator=(const string s )[/color]改成[color=red]string &operator=(const string &s )[/color]就对了。想不通为什么非要加&。
#include <iostream.h>;
#include <string.h>;
// using namespace std;
class string
{
char *ptr;
public:
string(char *s)
{
ptr=new char[strlen(s)+1];
strcpy(ptr,s);
}
~string()
{
delete ptr;
}
void print()
{
cout<<ptr<<endl;
}
[color=red]string operator=(const string s )[/color]
{
if (this==&s) return *this;
delete ptr;
ptr=new char[strlen(s.ptr)+1];
strcpy(ptr,s.ptr);
return *this;
}
};
void main()
{
string p1("chen");
{
string p2(" ");
p2=p1;
cout<<"p2:"<<endl;
p2.print();
}
cout<<"p1:"<<endl;
p1.print();
} |
c++函数重载问题讨论!!
另外对于别的运算符重载是就不用加&,举例来说吧:
[code]#include <iostream.h>;
class over
{
int i1;
public:
over()
{
i1=12;
}
void get(int j)
{
i1=j;
}
over operator ++()
{
i1++;
return *this;
}
void print()
{
cout<<i1<<endl;
}
};
void main()
{
over o1,o2;
int j;
j=33;
o2.get(j);
o1.print();
o2.print();
o2++;
o1.print();
o2.print();
}[/code]
就可以正确执行,另外将[color=red]over operator ++()[/color]改为[color=red]over &operator ++()[/color]也是对的,为什么?? |
c++函数重载问题讨论!!
这个应该在书上有讲到的。
“=”和“[]”这两个运算符,其返回值都必须是对对象的引用。因为他们的运算结果可能──而且必须保证可以──作为左值。比方说“+”重载,根本不会有
a+b=c;
这样的赋值语句出现,但是=呢?就有可能:
(a=b)++;
或
a[2]=b;
这样都是允许的。
一时讲不明白,看看书吧 |
c++函数重载问题讨论!!
-->如果不清楚呢就不要讲得让别人以为是真的一样.在哪里看到说=,[]这两个运算符其返回值都必须是对象的引用?
楼主可以把你的编译器,环境写出来,编译错误帖出来,在我的dev-cpp4.9.9下没有问题,只是你的程序不是标准的程序给了两个警告,当然main的返回值我改掉了(这是一个错误)参数为引用还是值类型都不是问题.关键的关键应该是你的string和std::string可能出现重复(我不知道带.h的头文件形式那个C++ string类与C标准头文件string.h是怎么处理的,所以我不确定是否一定是这个问题,所以请给出编译错误).我不喜欢这种非标准的程序:
我改为如下:
[code]#include <iostream>;
#include <cstring>;
using std::cout;
using std::endl;
using std::strlen;
using std::strcpy;
using std::system;
class string
{
char *ptr;
public:
string(char *s)
{
ptr=new char[strlen(s)+1];
strcpy(ptr,s);
}
~string()
{
delete ptr;
}
void print()
{
cout<<ptr<<endl;
}
string operator=(const string s )
{
if (this==&s) return *this;
delete ptr;
ptr=new char[strlen(s.ptr)+1];
strcpy(ptr,s.ptr);
return *this;
}
};
int main()
{
string p1("chen");
{
string p2(" ");
p2=p1;
cout<<"p2:"<<endl;
p2.print();
}
cout<<"p1:"<<endl;
p1.print();
system("PAUSE");
} [/code] |
c++函数重载问题讨论!!
-->
可我的确是从书上这么看来的啊。看的是一本叫做《C++语言程序设计》的书,清华出版社,郑莉著,第二版,第九章《群体类》,第272页 |
c++函数重载问题讨论!!
| c++函数重载问题讨论!!
书上这么说的:
-->
又说:
-->
我觉得这段话说的非常精彩。当然,倘若你的重载运算符所在的表达式(指的是赋值表达式或者使用下标随即访问的表达式)并没有在程序中作为左值出现,那么,在语法上也还是可以通过的;所以,所谓“必须返回引用”并不是语法上的强制,而是逻辑上的必须。 |
c++函数重载问题讨论!!
-->
厉害!那书上的的意思就是:“必须”是逻辑上的,不是语法上的。
老实说,楼主的代码我没有看,但看他说重载+可以而=不可以,又是引用的问题,自然就想到了这个。 |
c++函数重载问题讨论!!
-->从你给出的话来看我没有发现书上讲的是错的而是你自己加上去的"一定".作者只是说了"实现这个愿望的办法是..."而非"一定"要这么做.也就是讲:
"在需要改变运算符重载返回值的时候你就一般得用引用,而在不需要改变时也可以用传值方式".如果我写一个类不允许你通过operator[]来改变返回值又如何呢?就像const A &operator[]()const;它不允许改变返回值,也就可以写成const A operator[]()const;只不过是前者效率更高而矣. |
c++函数重载问题讨论!!
我在VC6.0中编译了你的程序,错出在p2.print()。在你的类中加上有内存重新分配的拷贝构造函数试试。当退出operator=()之后,s被析构,即p2.ptr被删除了,其内容是不确定的。因此在调用p2.print()时出错。另外,正如楼上说的那样,你的类和标准string类有歧义。 |
c++函数重载问题讨论!!
问题出在这个函数的参数上:
[code]string operator=(const string s )
{
if (this==&s) return *this;
delete ptr;
ptr=new char[strlen(s.ptr)+1];
strcpy(ptr,s.ptr);
return *this;
} [/code]
这个函数的参数使用的是值传递方式,所以在后面的代码:
[code]p2=p1;[/code]
赋值操作时,系统会将p1作为参数以值传递的方式投递进去,这个时候,会自动调用string类的拷贝构造函数,而在你的类定义中并没有定义该方法,所以,该函数获得的s参数并不是p1对象,而是一个p1对象的拷贝,由于你没有拷贝函数,系统会直接拷贝对象所有成员,也就说,只拷贝了指针,而没有复制指针指向的内存块,这样,s参数的ptr指针和p1的ptr指向的是同一个内存块,s和p1会重复delete同一块内存块,引起delete内存错误。
修改建议:
1、将=函数定义为引用传递:
[code]string operator=(const string &s )
{
if (this==&s) return *this;
delete ptr;
ptr=new char[strlen(s.ptr)+1];
strcpy(ptr,s.ptr);
return *this;
} [/code]
2、或者增加拷贝函数:
[code]string(const string &s) {
ptr = new char[strlen(s.ptr)+1];
strcpy(ptr, s.ptr);
}[/code]
以上更改在gcc 3.3.3下编译、运行通过。
另外几个建议:
1、使用标准c++头文件:
#include <iostream>;
#include <string>;
using namespace std;
2、不要使用与标准类库存在冲突的名称,比如你代码中的string类名称;
3、如果发现问题,请先检查,另外添加足够的调试信息,比如可以在构造函数、析构函数中添加消息。
4、不要跳过c/c++基础直接跳到高层的OO编程。 |
c++函数重载问题讨论!!
&是为了让被重载的运算符看上去更像他的爸爸 |
c++函数重载问题讨论!!
| c++函数重载问题讨论!!
增加最终修改的正常运行代码(添加拷贝构造函数版本):
[code]#include <iostream>;
//#include <string>;
using namespace std;
class stringS
{
char *ptr;
public:
stringS(char *s)
{
ptr=new char[strlen(s)+1];
strcpy(ptr,s);
}
~stringS()
{
if (ptr) {
delete ptr;
}
}
void print()
{
cout<<ptr<<endl;
}
stringS(const stringS &s) {
ptr = new char[strlen(s.ptr)+1];
strcpy(ptr, s.ptr);
}
stringS &operator=(const stringS s )
{
if (this==&s) return *this;
delete ptr;
ptr=new char[strlen(s.ptr)+1];
strcpy(ptr,s.ptr);
return *this;
}
};
int main()
{
stringS p1("chen");
{
stringS p2(" ");
p2=p1;
cout<<"p2:"<<endl;
p2.print();
}
cout<<"p1:"<<endl;
p1.print();
return 0;
}[/code] |
c++函数重载问题讨论!!
谢谢大家,不过还是有点不明白。我按骑士说的第一种方法 改怎么 还是不行?
string operator=(const string &s )
{
if (this==&s) return *this;
delete ptr;
ptr=new char[strlen(s.ptr)+1];
strcpy(ptr,s.ptr);
return *this;
} |
c++函数重载问题讨论!!
还有个问题,我跟踪了一下骑士修改后的程序,为什么在p1=p2时,程序先调用拷贝函数而不是运算符重载函数? |
c++函数重载问题讨论!!
-->
需要将返回值也修改成引用方式,否则还是会调用拷贝构造函数。
[code]stringS operator=(const stringS &s )
{
if (this==&s) return *this;
delete ptr;
ptr=new char[strlen(s.ptr)+1];
strcpy(ptr,s.ptr);
return *this;
} [/code] |
c++函数重载问题讨论!!
| c++函数重载问题讨论!!
to 骑士:
你说的第二种方法我明白了,不过第一种还是调不出来,我用vc6。0调的如下:
#include <iostream>;
//#include <string>;
using namespace std;
class stringS
{
char *ptr;
public:
stringS(char *s)
{
ptr=new char[strlen(s)+1];
strcpy(ptr,s);
}
~stringS()
{
if (ptr) {
delete ptr;
}
}
void print()
{
cout<<ptr<<endl;
}
/*
stringS(const stringS &s) {
ptr = new char[strlen(s.ptr)+1];
strcpy(ptr, s.ptr);
}
*/
stringS operator=(const stringS &s )
{
if (this==&s) return *this;
delete ptr;
ptr=new char[strlen(s.ptr)+1];
strcpy(ptr,s.ptr);
return *this;
}
};
int main()
{
stringS p1("chen");
//{
stringS p2(" ");
//stringS p3=&p1;
p2=p1;
cout<<"p2:"<<endl;
p2.print();
//}
cout<<"p1:"<<endl;
p1.print();
return 0;
} |
c++函数重载问题讨论!!
不知道是不是你说的意思!本人初学又比较笨,多谢你指教!
第一种方法会不会调用默认的拷贝构造函数?如果调用的话,怎么能够找到跟踪调用地址?听你的意思好像是不会调用拷贝构造函数!我跟踪这个程序好几遍还是搞不懂vc是怎么在内部操作的!
再次感谢高手指教! |
| |