//string2.h
#define STRING2_H
#include <iostream.h>
class String{
friend ostream &operator < <(ostream &,const String &);
public:
String(const char * ="" );
~String();
String operator+(const String &);
const String &operator=(const String &);
private:
int length;
char *sptr;
void setString(const char *);
};
#endif
//string2.cpp
#include <iostream.h>
#include <iomanip.h>
#include <string.h>
#include <assert.h>
#include"string2.h"
String::String(const char *s):length(strlen(s))
{
cout < <"conversion constructor: " < <s < <" a\n";
setString(s);
}
String::~String()
{
cout < <"destructor: " < <sptr < <'\n';
delete [] sptr;
}
void String::setString(const char *string2)
{
sptr=new char[length+1];
assert(sptr!=0);
strcpy(sptr,string2);
}
String String::operator +(const String &right)
{
char *tempptr;
length+=right.length;
tempptr=new char[length+1];
strcpy(tempptr,sptr);
strcat(tempptr,right.sptr);
cout < <" b\n";
return tempptr;
}
const String &String::operator =(const String &right)
{
cout < <"operator=called\n";
if(&right!=this){
delete [] sptr;
length=right.length;
setString(right.sptr);
}
else
cout < <"attempted assingnement of a string to itself\n";
return *this;
}
ostream &operator < <(ostream &output,const String &s)
{
output < <s.sptr;
return output;
}
//main().cpp
#include <iostream.h>
#include"string2.h"
int main()
{
String s1("happy"),s2(" birthday"),s3(" to you.");
//这程序的目的是在输出s1=s2+s3时不改变s2和s3(书本上的例子是重载+=),
//我在原来operator +=(const String &right)的基础上修改出了现在的operator +(const String &right)
//下面是原来的operator +=(const String &right)
//const String &String::operator +=(const String &right)
//{
// char *tempptr=sptr;
// length+=right.length;
// sptr=new char[length+1];
// assert(sptr!=0);
// strcpy(sptr,tempptr);
// strcat(sptr,right.sptr);
// delete [] tempptr;
// return *this;
//}
//看了输出,上面的调用3次构造函数,表示理解,但是在输出"s1 is "前居然4次调用operator +(const String &right)
//而且还多调用了4次构造函数和1次operator =(const String &right),这些是我想不明白的。
//麻烦各位高手说下如何重载“+”才正确。
cout < <"s1 is " < <s1
< <"\ns2 is " < <s2
< <"\ns3 is " < <s3//还没到s3=s1+s2就帮我提前修改了s3,想不通为什么。
< <"\ns1+s2 is " < <s1+s2
< <"\ns1+s2+s3 is " < <s1+s2+s3
< <"\ns3=s1+s2 is " < <(s3=s1+s2) < <endl;
return 0;
}
37 个解决方案
#1
String operator+(const String &);
是这样写的.
是这样写的.
#2
一般来说, +重载为友元更好.
friend String operator+(const String &str1, const String &str2) {
char *result = new char[strlen(str1.size()) + strlen(str2.size()) + 1];
strcpy(result, str1.pstr);
strcat(result, str2.pstr);
String rs(result);
delete result;
return rs;
}
friend String operator+(const String &str1, const String &str2) {
char *result = new char[strlen(str1.size()) + strlen(str2.size()) + 1];
strcpy(result, str1.pstr);
strcat(result, str2.pstr);
String rs(result);
delete result;
return rs;
}
#3
String String::operator +(const String &right1, const String &right2)
+是双目运算
+是双目运算
#4
String String::operator +(const String &right)
{
char *tempptr;
length+=right.length;
tempptr=new char[length+1];
strcpy(tempptr,sptr);
strcat(tempptr,right.sptr);
cout < <" b\n";
return tempptr;
}
不能返回局部变量的指针,局部变量在函数的尾部就被删除了,返回局部变量的指针是没有意义的。
{
char *tempptr;
length+=right.length;
tempptr=new char[length+1];
strcpy(tempptr,sptr);
strcat(tempptr,right.sptr);
cout < <" b\n";
return tempptr;
}
不能返回局部变量的指针,局部变量在函数的尾部就被删除了,返回局部变量的指针是没有意义的。
#5
回2楼,我按照你说的改了。程序可以运行。但是达不到想要的效果。
回3楼,厄~我看书上说对于双目运算符有2种重载:
1是只有1个参数的类成员函数。试用于2个对象都是类对象。
2是有2个参数。试用于有1个对象不是类对象。就像重载<<.
如果String String::operator +(const String &right1, const String &right2)行
麻烦你可以发发代码怎么实现吗?
我想学习学习,顺便解决我的问题。
最后,希望各位高手帮帮忙~
回3楼,厄~我看书上说对于双目运算符有2种重载:
1是只有1个参数的类成员函数。试用于2个对象都是类对象。
2是有2个参数。试用于有1个对象不是类对象。就像重载<<.
如果String String::operator +(const String &right1, const String &right2)行
麻烦你可以发发代码怎么实现吗?
我想学习学习,顺便解决我的问题。
最后,希望各位高手帮帮忙~
#6
+是双目运算,但成员函数隐式传递this指针,所以可以这样定义:
String operator+(const String &);
String operator+(const String &);
#7
好久没看C++代码,现在一看真是有点熟悉而又一些陌生。
#8
回4楼,我把char *tempptr声明为private了,还是不行,而且跟原来的输出没什么区别。
可以说清楚点不?
可以说清楚点不?
#9
s1+s2要产生一个临时对象,所以也要调用构造函数,当输出s1+s2后,就调用析构函数删除临时对象
s1+s2+s3要产生两个临时对象,一个是s1+s2,一个是s1+s2+s3。
//string2.h
#ifndef STRING2_H
#define STRING2_H
#include <iostream.h>
class String{
friend ostream &operator <<(ostream &,const String &);
public:
String(const char * ="" );
~String();
String operator+(const String &);
const String &operator=(const String &);
private:
int length;
char *sptr;
void setString(const char *);
char *tempptr;
};
#endif
#include <iostream.h>
#include <iomanip.h>
#include <string.h>
#include <assert.h>
#include "string2.h"
String::String(const char *s):length(strlen(s))
{
cout <<"conversion constructor: " <<s <<" a\n";
setString(s);
}
String::~String()
{
cout <<"destructor: " <<sptr <<'\n';
delete [] sptr;
}
void String::setString(const char *string2)
{
sptr=new char[length+1];
assert(sptr!=0);
strcpy(sptr,string2);
}
String String::operator +(const String &right)
{
length+=right.length;
tempptr=new char[length+1];
strcpy(tempptr,sptr);
strcat(tempptr,right.sptr);
cout <<" b\n";
return tempptr;
}
const String &String::operator =(const String &right)
{
cout <<"operator=called\n";
if(&right!=this){
delete [] sptr;
length=right.length;
setString(right.sptr);
}
else
cout <<"attempted assingnement of a string to itself\n";
return *this;
}
ostream &operator <<(ostream &output,const String &s)
{
output <<s.sptr;
return output;
}
int main()
{
String s1("happy"),s2(" birthday"),s3(" to you.");
//String s=s1+s2;
cout <<"s1 is "<<s1<<endl;
cout<<"\ns2 is "<<s2<<endl;
cout<<"\ns3 is "<<s3<<endl;//还没到s3=s1+s2就帮我提前修改了s3,想不通为什么。
cout<<"\ns1 add s2 is "<<s1+s2<<endl;
cout<<"\ns1 add s2 add s3 is "<<s1+s2+s3<<endl;
cout<<"\ns3=s1+s2 is "<<(s3=s1+s2)<<endl;
return 0;
}
输出结果为:
conversion constructor: happy a
conversion constructor: birthday a
conversion constructor: to you. a
s1 is happy
s2 is birthday
s3 is to you.
b
conversion constructor: happy birthday a
s1 add s2 is happy birthday
destructor: happy birthday
b
conversion constructor: happy birthday a
b
conversion constructor: happy birthday to you. a
s1 add s2 add s3 is happy birthday to you.
destructor: happy birthday to you.
destructor: happy birthday
b
conversion constructor: happy birthday a
operator=called
s3=s1+s2 is happy birthday
destructor: happy birthday
destructor: happy birthday
destructor: birthday
destructor: happy
Press any key to continue
s1+s2+s3要产生两个临时对象,一个是s1+s2,一个是s1+s2+s3。
//string2.h
#ifndef STRING2_H
#define STRING2_H
#include <iostream.h>
class String{
friend ostream &operator <<(ostream &,const String &);
public:
String(const char * ="" );
~String();
String operator+(const String &);
const String &operator=(const String &);
private:
int length;
char *sptr;
void setString(const char *);
char *tempptr;
};
#endif
#include <iostream.h>
#include <iomanip.h>
#include <string.h>
#include <assert.h>
#include "string2.h"
String::String(const char *s):length(strlen(s))
{
cout <<"conversion constructor: " <<s <<" a\n";
setString(s);
}
String::~String()
{
cout <<"destructor: " <<sptr <<'\n';
delete [] sptr;
}
void String::setString(const char *string2)
{
sptr=new char[length+1];
assert(sptr!=0);
strcpy(sptr,string2);
}
String String::operator +(const String &right)
{
length+=right.length;
tempptr=new char[length+1];
strcpy(tempptr,sptr);
strcat(tempptr,right.sptr);
cout <<" b\n";
return tempptr;
}
const String &String::operator =(const String &right)
{
cout <<"operator=called\n";
if(&right!=this){
delete [] sptr;
length=right.length;
setString(right.sptr);
}
else
cout <<"attempted assingnement of a string to itself\n";
return *this;
}
ostream &operator <<(ostream &output,const String &s)
{
output <<s.sptr;
return output;
}
int main()
{
String s1("happy"),s2(" birthday"),s3(" to you.");
//String s=s1+s2;
cout <<"s1 is "<<s1<<endl;
cout<<"\ns2 is "<<s2<<endl;
cout<<"\ns3 is "<<s3<<endl;//还没到s3=s1+s2就帮我提前修改了s3,想不通为什么。
cout<<"\ns1 add s2 is "<<s1+s2<<endl;
cout<<"\ns1 add s2 add s3 is "<<s1+s2+s3<<endl;
cout<<"\ns3=s1+s2 is "<<(s3=s1+s2)<<endl;
return 0;
}
输出结果为:
conversion constructor: happy a
conversion constructor: birthday a
conversion constructor: to you. a
s1 is happy
s2 is birthday
s3 is to you.
b
conversion constructor: happy birthday a
s1 add s2 is happy birthday
destructor: happy birthday
b
conversion constructor: happy birthday a
b
conversion constructor: happy birthday to you. a
s1 add s2 add s3 is happy birthday to you.
destructor: happy birthday to you.
destructor: happy birthday
b
conversion constructor: happy birthday a
operator=called
s3=s1+s2 is happy birthday
destructor: happy birthday
destructor: happy birthday
destructor: birthday
destructor: happy
Press any key to continue
#10
String String::operator +(const String &right)
{
static char *tempptr;
length+=right.length;
tempptr=new char[length+1];
strcpy(tempptr,sptr);
strcat(tempptr,right.sptr);
cout < <" b\n";
return tempptr;
}
这样试试~
{
static char *tempptr;
length+=right.length;
tempptr=new char[length+1];
strcpy(tempptr,sptr);
strcat(tempptr,right.sptr);
cout < <" b\n";
return tempptr;
}
这样试试~
#11
正确的应该是
String operator+(const String &)const;
String operator+(const String &)const;
#12
这种东西没有任何理由重载为友元,为什么它是友元更好?
一般来说,友元只有在第一个参数不是自己类型时才用如
friend String operator+(LPCTSTR str1, const String& str2);
对于第一个参数是同一个类的引用时,友元没有任何好处
一般来说,友元只有在第一个参数不是自己类型时才用如
friend String operator+(LPCTSTR str1, const String& str2);
对于第一个参数是同一个类的引用时,友元没有任何好处
#13
不知道你怎么会达不到效果,下面代码很容易做到
String String::operator+(const String & str)const
{
String res;
res.length = length + str.length;
res.sptr = new char[res.length+1];
strcpy(res.sptr,sptr);
strcat(res.sptr,str.sptr);
return res;
}
#14
这个不是返回局部变量指针,只要它有正确的拷贝构造函数和operator=即可
因为这个函数返回的对象必然是临时的,因此接收此返回值的表达式必须有clone这个对象的能力,这就必须实现拷贝构造和operator=
因为这个函数返回的对象必然是临时的,因此接收此返回值的表达式必须有clone这个对象的能力,这就必须实现拷贝构造和operator=
#15
String operator+(const String &)const;
后面的const是使this的指针变为const
调用该函数的对象是只读的,不能改变它.
所以想调用s1+s2不变,应该在后面加const
后面的const是使this的指针变为const
调用该函数的对象是只读的,不能改变它.
所以想调用s1+s2不变,应该在后面加const
#16
回13楼,真的不行。弹出一个对话框,有 终止 重试 取消 之类的。就想运行非法一样。
#17
下面这个函数是很不对的
这个函数总是假定length已经提前设置好了,这个把一个类的各个属性分开设置的方法违背了“consistency”的原则
应该这样设计才对
void String::setString(const char *string2)
{
sptr=new char[length+1];
assert(sptr!=0);
strcpy(sptr,string2);
}
这个函数总是假定length已经提前设置好了,这个把一个类的各个属性分开设置的方法违背了“consistency”的原则
应该这样设计才对
void String::setString(const char *string2)
{
length = strlen(string2);
sptr=new char[length+1];
strcpy(sptr,string2);
}
#18
那不是这个函数的原因,而是你没有实现拷贝构造
考虑这样的一个式子
String s1("abc");
String s2("def");
String s3 = s1+s2;
由于s1+s2返回一个String对象(注意它是临时对象),当S3接收这个值时,由于你没有实现拷贝构造,系统会非常傻的替你实现一个逐字节拷贝的拷贝构造函数
假定临时对象是_s3,其sptr指向某个new出来的地址,拷贝后,_s3和s3的sptr都指向它
当_s3和s3分别析构,问题就出来了。由于s3, _s3分别通过~String调用delete[]sptr,这必然delete同一个指针两次,从而导致问题。
考虑这样的一个式子
String s1("abc");
String s2("def");
String s3 = s1+s2;
由于s1+s2返回一个String对象(注意它是临时对象),当S3接收这个值时,由于你没有实现拷贝构造,系统会非常傻的替你实现一个逐字节拷贝的拷贝构造函数
假定临时对象是_s3,其sptr指向某个new出来的地址,拷贝后,_s3和s3的sptr都指向它
当_s3和s3分别析构,问题就出来了。由于s3, _s3分别通过~String调用delete[]sptr,这必然delete同一个指针两次,从而导致问题。
#19
搞不懂你干吗要单独实现一个setString,而又不把length的赋值操作放在里面干吗?
#20
mark 一个
#21
把String String::operator+(const String & str)const
{
String res;
res.length = length + str.length;
res.sptr = new char[res.length+1];
strcpy(res.sptr,sptr);
strcat(res.sptr,str.sptr);
return res;
}加进来的确可以,不过要加如下面的构造函数
String::String(const String ©):length(copy.length)
{
cout<<"copy constructor: "<<copy.sptr<<'\n';
setString(copy.sptr);
}
书上说这是一个复制构造函数,它通过复制已存在的String对象来初始化另一对象。
其实我对这2个构造函数也不是完全理解:
String::String(const char *s):length(strlen(s))
说可以把char *转换为类对象。
String::String(const String ©):length(copy.length)
说通过复制已存在的String对象来初始化另一对象。
有高手可以说下怎么理解不?要不明天我另外开贴~
{
String res;
res.length = length + str.length;
res.sptr = new char[res.length+1];
strcpy(res.sptr,sptr);
strcat(res.sptr,str.sptr);
return res;
}加进来的确可以,不过要加如下面的构造函数
String::String(const String ©):length(copy.length)
{
cout<<"copy constructor: "<<copy.sptr<<'\n';
setString(copy.sptr);
}
书上说这是一个复制构造函数,它通过复制已存在的String对象来初始化另一对象。
其实我对这2个构造函数也不是完全理解:
String::String(const char *s):length(strlen(s))
说可以把char *转换为类对象。
String::String(const String ©):length(copy.length)
说通过复制已存在的String对象来初始化另一对象。
有高手可以说下怎么理解不?要不明天我另外开贴~
#22
回19楼,这是受了书上例子的影响。
你有更好的实现方法吗?不建立setString,
让我学习学习,非常感谢~
你有更好的实现方法吗?不建立setString,
让我学习学习,非常感谢~
#23
楼主,我先回答你第一个问题:
以上原因是因为流是从右向左逐一运算的,所以当你显示s3的时候已经运行完毕s3=s1+s2这个操作了.
加号运算符
另外如何重载运算符,一定要服从著名的BIG THREE原则,即:需要定义析构函数,复制构造函数和复制运算符中任意一个的时候,一定要定义另外两个,你程序中的
所以说+运算符重载,也需要考虑到其他问题.
我改好的代码如下:
cout <<"s1 is " <<s1
<<"\ns2 is " <<s2
<<"\ns3 is " <<s3//还没到s3=s1+s2就帮我提前修改了s3,想不通为什么。
<<"\ns1+s2 is " <<s1+s2
<<"\ns1+s2+s3 is " <<s1+s2+s3
<<"\ns3=s1+s2 is " <<(s3=s1+s2) <<endl;
以上原因是因为流是从右向左逐一运算的,所以当你显示s3的时候已经运行完毕s3=s1+s2这个操作了.
加号运算符
另外如何重载运算符,一定要服从著名的BIG THREE原则,即:需要定义析构函数,复制构造函数和复制运算符中任意一个的时候,一定要定义另外两个,你程序中的
<<"\ns1+s2 is " <<s1+s2 //这部分需要复制构造函数
所以说+运算符重载,也需要考虑到其他问题.
我改好的代码如下:
//string2.h
#include <iostream.h>
class String{
friend ostream &operator <<(ostream &,const String &);
public:
String(const char * ="" );
String(const String & tempStr);
~String();
String operator+(const String &);
const String &operator=(const String &);
private:
int length;
char *sptr;
void setString(const char *);
};
//string2.cpp
#include <iostream.h>
#include <iomanip.h>
#include <string.h>
#include <assert.h>
#include"string2.h"
String::String(const char *s):length(strlen(s))
{
cout <<"conversion constructor: " <<s <<" a\n";
setString(s);
}
String::~String()
{
cout <<"destructor: " <<sptr <<'\n';
delete [] sptr;
}
void String::setString(const char *string2)
{
sptr=new char[strlen(string2)+1];
assert(sptr!=0);
strcpy(sptr,string2);
}
String String::operator +(const String &right)
{
char *tempptr=new char[length+right.length+1];
strcpy(tempptr,sptr);
strcat(tempptr,right.sptr);
cout <<" b\n";
String tempStr(tempptr);
return tempStr;
}
const String &String::operator =(const String &right)
{
cout <<"operator=called\n";
if(&right!=this){
delete [] sptr;
length=right.length;
setString(right.sptr);
}
else
cout <<"attempted assingnement of a string to itself\n";
return *this;
}
ostream& operator <<(ostream &output,const String &s)
{
output << s.sptr;
return output;
}
String::String(const String & tempStr)
{
length=tempStr.length;
setString(tempStr.sptr);
}
//main().cpp
#include <iostream.h>
#include"string2.h"
int main()
{
String s1("happy"),s2(" birthday"),s3(" to you.");
cout <<"s1 is " <<s1<<endl ;
cout<<"\ns2 is " <<s2 <<endl ;
cout<<"\ns3 is " <<s3<<endl;
cout<<"\ns1+s2 is " <<s1+s2 <<endl ;
cout<<"\ns1+s2+s3 is " <<s1+s2+s3<<endl ;
cout<<"\ns3=s1+s2 is " <<(s3=s1+s2) <<endl;
return 0;
}
#24
写一个私有的setString也不是不可以,但是你需要把length的赋值也放到里面去,否则可能会造成对象自身的不一致
假如你写了这个类2年之后,你又加了一个函数如下:
注意:这里没有设置length,这个函数必然会导致一些潜在的问题。而这种情况在设计大项目情况下很可能出现,因此每个函数必须有责任保证自己操作过后对象是完整的,而setString恰恰不能保证完整性。
假如你写了这个类2年之后,你又加了一个函数如下:
void String::foo()
{
setString("hahaha");
}
注意:这里没有设置length,这个函数必然会导致一些潜在的问题。而这种情况在设计大项目情况下很可能出现,因此每个函数必须有责任保证自己操作过后对象是完整的,而setString恰恰不能保证完整性。
#25
String s1="abcd"; //调用String(const char*)构造
String s2=s1; //调用String(const String&)构造
String s3;
s3 = s1; //调用operator=
String s2=s1; //调用String(const String&)构造
String s3;
s3 = s1; //调用operator=
#26
回23楼,改了后是可以了,但是还是有些小问题。
就是<<s3输出的是happy birthday而不是 to you。而且我加了书上的复制构造函数也是出可以的结果。
回24楼,现在清楚了,以后会养成这样的习惯的。
再次麻烦你帮看看,为什么输出s3时是happy birthday而不是 to you?要怎么改?
就是<<s3输出的是happy birthday而不是 to you。而且我加了书上的复制构造函数也是出可以的结果。
回24楼,现在清楚了,以后会养成这样的习惯的。
再次麻烦你帮看看,为什么输出s3时是happy birthday而不是 to you?要怎么改?
#27
按照下面顺序理论上应该先出现
s1 is happy
s2 is birthday
s3 is to you
s1+s2 is happybirthday
s1+s2+s3 is happybirthdayto you
s3=s1+s2 is happybirthday
如果不是这样,估计这和ios的缓存有关,建议你把所有的\n都换成endl,强迫ios刷新缓存
cout < <"s1 is " < <s1
< <"\ns2 is " < <s2
< <"\ns3 is " < <s3//还没到s3=s1+s2就帮我提前修改了s3,想不通为什么。
< <"\ns1+s2 is " < <s1+s2
< <"\ns1+s2+s3 is " < <s1+s2+s3
< <"\ns3=s1+s2 is " < <(s3=s1+s2) < <endl;
s1 is happy
s2 is birthday
s3 is to you
s1+s2 is happybirthday
s1+s2+s3 is happybirthdayto you
s3=s1+s2 is happybirthday
如果不是这样,估计这和ios的缓存有关,建议你把所有的\n都换成endl,强迫ios刷新缓存
cout < <"s1 is " < <s1
< <"\ns2 is " < <s2
< <"\ns3 is " < <s3//还没到s3=s1+s2就帮我提前修改了s3,想不通为什么。
< <"\ns1+s2 is " < <s1+s2
< <"\ns1+s2+s3 is " < <s1+s2+s3
< <"\ns3=s1+s2 is " < <(s3=s1+s2) < <endl;
#28
非常非常感谢啊~
的确行了,看来endl才是万能的。
啊哈哈哈~~~
的确行了,看来endl才是万能的。
啊哈哈哈~~~
#29
它也就多调用一次flush而已
#30
今天一定能睡个好觉!
#31
#32
mark
#33
mark2
#34
好复杂。。。。。
#35
确实
,有点复杂
,有点复杂
#36
LZ的代码看上去有点乱,密密麻麻的....
#37
有点乱
#1
String operator+(const String &);
是这样写的.
是这样写的.
#2
一般来说, +重载为友元更好.
friend String operator+(const String &str1, const String &str2) {
char *result = new char[strlen(str1.size()) + strlen(str2.size()) + 1];
strcpy(result, str1.pstr);
strcat(result, str2.pstr);
String rs(result);
delete result;
return rs;
}
friend String operator+(const String &str1, const String &str2) {
char *result = new char[strlen(str1.size()) + strlen(str2.size()) + 1];
strcpy(result, str1.pstr);
strcat(result, str2.pstr);
String rs(result);
delete result;
return rs;
}
#3
String String::operator +(const String &right1, const String &right2)
+是双目运算
+是双目运算
#4
String String::operator +(const String &right)
{
char *tempptr;
length+=right.length;
tempptr=new char[length+1];
strcpy(tempptr,sptr);
strcat(tempptr,right.sptr);
cout < <" b\n";
return tempptr;
}
不能返回局部变量的指针,局部变量在函数的尾部就被删除了,返回局部变量的指针是没有意义的。
{
char *tempptr;
length+=right.length;
tempptr=new char[length+1];
strcpy(tempptr,sptr);
strcat(tempptr,right.sptr);
cout < <" b\n";
return tempptr;
}
不能返回局部变量的指针,局部变量在函数的尾部就被删除了,返回局部变量的指针是没有意义的。
#5
回2楼,我按照你说的改了。程序可以运行。但是达不到想要的效果。
回3楼,厄~我看书上说对于双目运算符有2种重载:
1是只有1个参数的类成员函数。试用于2个对象都是类对象。
2是有2个参数。试用于有1个对象不是类对象。就像重载<<.
如果String String::operator +(const String &right1, const String &right2)行
麻烦你可以发发代码怎么实现吗?
我想学习学习,顺便解决我的问题。
最后,希望各位高手帮帮忙~
回3楼,厄~我看书上说对于双目运算符有2种重载:
1是只有1个参数的类成员函数。试用于2个对象都是类对象。
2是有2个参数。试用于有1个对象不是类对象。就像重载<<.
如果String String::operator +(const String &right1, const String &right2)行
麻烦你可以发发代码怎么实现吗?
我想学习学习,顺便解决我的问题。
最后,希望各位高手帮帮忙~
#6
+是双目运算,但成员函数隐式传递this指针,所以可以这样定义:
String operator+(const String &);
String operator+(const String &);
#7
好久没看C++代码,现在一看真是有点熟悉而又一些陌生。
#8
回4楼,我把char *tempptr声明为private了,还是不行,而且跟原来的输出没什么区别。
可以说清楚点不?
可以说清楚点不?
#9
s1+s2要产生一个临时对象,所以也要调用构造函数,当输出s1+s2后,就调用析构函数删除临时对象
s1+s2+s3要产生两个临时对象,一个是s1+s2,一个是s1+s2+s3。
//string2.h
#ifndef STRING2_H
#define STRING2_H
#include <iostream.h>
class String{
friend ostream &operator <<(ostream &,const String &);
public:
String(const char * ="" );
~String();
String operator+(const String &);
const String &operator=(const String &);
private:
int length;
char *sptr;
void setString(const char *);
char *tempptr;
};
#endif
#include <iostream.h>
#include <iomanip.h>
#include <string.h>
#include <assert.h>
#include "string2.h"
String::String(const char *s):length(strlen(s))
{
cout <<"conversion constructor: " <<s <<" a\n";
setString(s);
}
String::~String()
{
cout <<"destructor: " <<sptr <<'\n';
delete [] sptr;
}
void String::setString(const char *string2)
{
sptr=new char[length+1];
assert(sptr!=0);
strcpy(sptr,string2);
}
String String::operator +(const String &right)
{
length+=right.length;
tempptr=new char[length+1];
strcpy(tempptr,sptr);
strcat(tempptr,right.sptr);
cout <<" b\n";
return tempptr;
}
const String &String::operator =(const String &right)
{
cout <<"operator=called\n";
if(&right!=this){
delete [] sptr;
length=right.length;
setString(right.sptr);
}
else
cout <<"attempted assingnement of a string to itself\n";
return *this;
}
ostream &operator <<(ostream &output,const String &s)
{
output <<s.sptr;
return output;
}
int main()
{
String s1("happy"),s2(" birthday"),s3(" to you.");
//String s=s1+s2;
cout <<"s1 is "<<s1<<endl;
cout<<"\ns2 is "<<s2<<endl;
cout<<"\ns3 is "<<s3<<endl;//还没到s3=s1+s2就帮我提前修改了s3,想不通为什么。
cout<<"\ns1 add s2 is "<<s1+s2<<endl;
cout<<"\ns1 add s2 add s3 is "<<s1+s2+s3<<endl;
cout<<"\ns3=s1+s2 is "<<(s3=s1+s2)<<endl;
return 0;
}
输出结果为:
conversion constructor: happy a
conversion constructor: birthday a
conversion constructor: to you. a
s1 is happy
s2 is birthday
s3 is to you.
b
conversion constructor: happy birthday a
s1 add s2 is happy birthday
destructor: happy birthday
b
conversion constructor: happy birthday a
b
conversion constructor: happy birthday to you. a
s1 add s2 add s3 is happy birthday to you.
destructor: happy birthday to you.
destructor: happy birthday
b
conversion constructor: happy birthday a
operator=called
s3=s1+s2 is happy birthday
destructor: happy birthday
destructor: happy birthday
destructor: birthday
destructor: happy
Press any key to continue
s1+s2+s3要产生两个临时对象,一个是s1+s2,一个是s1+s2+s3。
//string2.h
#ifndef STRING2_H
#define STRING2_H
#include <iostream.h>
class String{
friend ostream &operator <<(ostream &,const String &);
public:
String(const char * ="" );
~String();
String operator+(const String &);
const String &operator=(const String &);
private:
int length;
char *sptr;
void setString(const char *);
char *tempptr;
};
#endif
#include <iostream.h>
#include <iomanip.h>
#include <string.h>
#include <assert.h>
#include "string2.h"
String::String(const char *s):length(strlen(s))
{
cout <<"conversion constructor: " <<s <<" a\n";
setString(s);
}
String::~String()
{
cout <<"destructor: " <<sptr <<'\n';
delete [] sptr;
}
void String::setString(const char *string2)
{
sptr=new char[length+1];
assert(sptr!=0);
strcpy(sptr,string2);
}
String String::operator +(const String &right)
{
length+=right.length;
tempptr=new char[length+1];
strcpy(tempptr,sptr);
strcat(tempptr,right.sptr);
cout <<" b\n";
return tempptr;
}
const String &String::operator =(const String &right)
{
cout <<"operator=called\n";
if(&right!=this){
delete [] sptr;
length=right.length;
setString(right.sptr);
}
else
cout <<"attempted assingnement of a string to itself\n";
return *this;
}
ostream &operator <<(ostream &output,const String &s)
{
output <<s.sptr;
return output;
}
int main()
{
String s1("happy"),s2(" birthday"),s3(" to you.");
//String s=s1+s2;
cout <<"s1 is "<<s1<<endl;
cout<<"\ns2 is "<<s2<<endl;
cout<<"\ns3 is "<<s3<<endl;//还没到s3=s1+s2就帮我提前修改了s3,想不通为什么。
cout<<"\ns1 add s2 is "<<s1+s2<<endl;
cout<<"\ns1 add s2 add s3 is "<<s1+s2+s3<<endl;
cout<<"\ns3=s1+s2 is "<<(s3=s1+s2)<<endl;
return 0;
}
输出结果为:
conversion constructor: happy a
conversion constructor: birthday a
conversion constructor: to you. a
s1 is happy
s2 is birthday
s3 is to you.
b
conversion constructor: happy birthday a
s1 add s2 is happy birthday
destructor: happy birthday
b
conversion constructor: happy birthday a
b
conversion constructor: happy birthday to you. a
s1 add s2 add s3 is happy birthday to you.
destructor: happy birthday to you.
destructor: happy birthday
b
conversion constructor: happy birthday a
operator=called
s3=s1+s2 is happy birthday
destructor: happy birthday
destructor: happy birthday
destructor: birthday
destructor: happy
Press any key to continue
#10
String String::operator +(const String &right)
{
static char *tempptr;
length+=right.length;
tempptr=new char[length+1];
strcpy(tempptr,sptr);
strcat(tempptr,right.sptr);
cout < <" b\n";
return tempptr;
}
这样试试~
{
static char *tempptr;
length+=right.length;
tempptr=new char[length+1];
strcpy(tempptr,sptr);
strcat(tempptr,right.sptr);
cout < <" b\n";
return tempptr;
}
这样试试~
#11
正确的应该是
String operator+(const String &)const;
String operator+(const String &)const;
#12
这种东西没有任何理由重载为友元,为什么它是友元更好?
一般来说,友元只有在第一个参数不是自己类型时才用如
friend String operator+(LPCTSTR str1, const String& str2);
对于第一个参数是同一个类的引用时,友元没有任何好处
一般来说,友元只有在第一个参数不是自己类型时才用如
friend String operator+(LPCTSTR str1, const String& str2);
对于第一个参数是同一个类的引用时,友元没有任何好处
#13
不知道你怎么会达不到效果,下面代码很容易做到
String String::operator+(const String & str)const
{
String res;
res.length = length + str.length;
res.sptr = new char[res.length+1];
strcpy(res.sptr,sptr);
strcat(res.sptr,str.sptr);
return res;
}
#14
这个不是返回局部变量指针,只要它有正确的拷贝构造函数和operator=即可
因为这个函数返回的对象必然是临时的,因此接收此返回值的表达式必须有clone这个对象的能力,这就必须实现拷贝构造和operator=
因为这个函数返回的对象必然是临时的,因此接收此返回值的表达式必须有clone这个对象的能力,这就必须实现拷贝构造和operator=
#15
String operator+(const String &)const;
后面的const是使this的指针变为const
调用该函数的对象是只读的,不能改变它.
所以想调用s1+s2不变,应该在后面加const
后面的const是使this的指针变为const
调用该函数的对象是只读的,不能改变它.
所以想调用s1+s2不变,应该在后面加const
#16
回13楼,真的不行。弹出一个对话框,有 终止 重试 取消 之类的。就想运行非法一样。
#17
下面这个函数是很不对的
这个函数总是假定length已经提前设置好了,这个把一个类的各个属性分开设置的方法违背了“consistency”的原则
应该这样设计才对
void String::setString(const char *string2)
{
sptr=new char[length+1];
assert(sptr!=0);
strcpy(sptr,string2);
}
这个函数总是假定length已经提前设置好了,这个把一个类的各个属性分开设置的方法违背了“consistency”的原则
应该这样设计才对
void String::setString(const char *string2)
{
length = strlen(string2);
sptr=new char[length+1];
strcpy(sptr,string2);
}
#18
那不是这个函数的原因,而是你没有实现拷贝构造
考虑这样的一个式子
String s1("abc");
String s2("def");
String s3 = s1+s2;
由于s1+s2返回一个String对象(注意它是临时对象),当S3接收这个值时,由于你没有实现拷贝构造,系统会非常傻的替你实现一个逐字节拷贝的拷贝构造函数
假定临时对象是_s3,其sptr指向某个new出来的地址,拷贝后,_s3和s3的sptr都指向它
当_s3和s3分别析构,问题就出来了。由于s3, _s3分别通过~String调用delete[]sptr,这必然delete同一个指针两次,从而导致问题。
考虑这样的一个式子
String s1("abc");
String s2("def");
String s3 = s1+s2;
由于s1+s2返回一个String对象(注意它是临时对象),当S3接收这个值时,由于你没有实现拷贝构造,系统会非常傻的替你实现一个逐字节拷贝的拷贝构造函数
假定临时对象是_s3,其sptr指向某个new出来的地址,拷贝后,_s3和s3的sptr都指向它
当_s3和s3分别析构,问题就出来了。由于s3, _s3分别通过~String调用delete[]sptr,这必然delete同一个指针两次,从而导致问题。
#19
搞不懂你干吗要单独实现一个setString,而又不把length的赋值操作放在里面干吗?
#20
mark 一个
#21
把String String::operator+(const String & str)const
{
String res;
res.length = length + str.length;
res.sptr = new char[res.length+1];
strcpy(res.sptr,sptr);
strcat(res.sptr,str.sptr);
return res;
}加进来的确可以,不过要加如下面的构造函数
String::String(const String ©):length(copy.length)
{
cout<<"copy constructor: "<<copy.sptr<<'\n';
setString(copy.sptr);
}
书上说这是一个复制构造函数,它通过复制已存在的String对象来初始化另一对象。
其实我对这2个构造函数也不是完全理解:
String::String(const char *s):length(strlen(s))
说可以把char *转换为类对象。
String::String(const String ©):length(copy.length)
说通过复制已存在的String对象来初始化另一对象。
有高手可以说下怎么理解不?要不明天我另外开贴~
{
String res;
res.length = length + str.length;
res.sptr = new char[res.length+1];
strcpy(res.sptr,sptr);
strcat(res.sptr,str.sptr);
return res;
}加进来的确可以,不过要加如下面的构造函数
String::String(const String ©):length(copy.length)
{
cout<<"copy constructor: "<<copy.sptr<<'\n';
setString(copy.sptr);
}
书上说这是一个复制构造函数,它通过复制已存在的String对象来初始化另一对象。
其实我对这2个构造函数也不是完全理解:
String::String(const char *s):length(strlen(s))
说可以把char *转换为类对象。
String::String(const String ©):length(copy.length)
说通过复制已存在的String对象来初始化另一对象。
有高手可以说下怎么理解不?要不明天我另外开贴~
#22
回19楼,这是受了书上例子的影响。
你有更好的实现方法吗?不建立setString,
让我学习学习,非常感谢~
你有更好的实现方法吗?不建立setString,
让我学习学习,非常感谢~
#23
楼主,我先回答你第一个问题:
以上原因是因为流是从右向左逐一运算的,所以当你显示s3的时候已经运行完毕s3=s1+s2这个操作了.
加号运算符
另外如何重载运算符,一定要服从著名的BIG THREE原则,即:需要定义析构函数,复制构造函数和复制运算符中任意一个的时候,一定要定义另外两个,你程序中的
所以说+运算符重载,也需要考虑到其他问题.
我改好的代码如下:
cout <<"s1 is " <<s1
<<"\ns2 is " <<s2
<<"\ns3 is " <<s3//还没到s3=s1+s2就帮我提前修改了s3,想不通为什么。
<<"\ns1+s2 is " <<s1+s2
<<"\ns1+s2+s3 is " <<s1+s2+s3
<<"\ns3=s1+s2 is " <<(s3=s1+s2) <<endl;
以上原因是因为流是从右向左逐一运算的,所以当你显示s3的时候已经运行完毕s3=s1+s2这个操作了.
加号运算符
另外如何重载运算符,一定要服从著名的BIG THREE原则,即:需要定义析构函数,复制构造函数和复制运算符中任意一个的时候,一定要定义另外两个,你程序中的
<<"\ns1+s2 is " <<s1+s2 //这部分需要复制构造函数
所以说+运算符重载,也需要考虑到其他问题.
我改好的代码如下:
//string2.h
#include <iostream.h>
class String{
friend ostream &operator <<(ostream &,const String &);
public:
String(const char * ="" );
String(const String & tempStr);
~String();
String operator+(const String &);
const String &operator=(const String &);
private:
int length;
char *sptr;
void setString(const char *);
};
//string2.cpp
#include <iostream.h>
#include <iomanip.h>
#include <string.h>
#include <assert.h>
#include"string2.h"
String::String(const char *s):length(strlen(s))
{
cout <<"conversion constructor: " <<s <<" a\n";
setString(s);
}
String::~String()
{
cout <<"destructor: " <<sptr <<'\n';
delete [] sptr;
}
void String::setString(const char *string2)
{
sptr=new char[strlen(string2)+1];
assert(sptr!=0);
strcpy(sptr,string2);
}
String String::operator +(const String &right)
{
char *tempptr=new char[length+right.length+1];
strcpy(tempptr,sptr);
strcat(tempptr,right.sptr);
cout <<" b\n";
String tempStr(tempptr);
return tempStr;
}
const String &String::operator =(const String &right)
{
cout <<"operator=called\n";
if(&right!=this){
delete [] sptr;
length=right.length;
setString(right.sptr);
}
else
cout <<"attempted assingnement of a string to itself\n";
return *this;
}
ostream& operator <<(ostream &output,const String &s)
{
output << s.sptr;
return output;
}
String::String(const String & tempStr)
{
length=tempStr.length;
setString(tempStr.sptr);
}
//main().cpp
#include <iostream.h>
#include"string2.h"
int main()
{
String s1("happy"),s2(" birthday"),s3(" to you.");
cout <<"s1 is " <<s1<<endl ;
cout<<"\ns2 is " <<s2 <<endl ;
cout<<"\ns3 is " <<s3<<endl;
cout<<"\ns1+s2 is " <<s1+s2 <<endl ;
cout<<"\ns1+s2+s3 is " <<s1+s2+s3<<endl ;
cout<<"\ns3=s1+s2 is " <<(s3=s1+s2) <<endl;
return 0;
}
#24
写一个私有的setString也不是不可以,但是你需要把length的赋值也放到里面去,否则可能会造成对象自身的不一致
假如你写了这个类2年之后,你又加了一个函数如下:
注意:这里没有设置length,这个函数必然会导致一些潜在的问题。而这种情况在设计大项目情况下很可能出现,因此每个函数必须有责任保证自己操作过后对象是完整的,而setString恰恰不能保证完整性。
假如你写了这个类2年之后,你又加了一个函数如下:
void String::foo()
{
setString("hahaha");
}
注意:这里没有设置length,这个函数必然会导致一些潜在的问题。而这种情况在设计大项目情况下很可能出现,因此每个函数必须有责任保证自己操作过后对象是完整的,而setString恰恰不能保证完整性。
#25
String s1="abcd"; //调用String(const char*)构造
String s2=s1; //调用String(const String&)构造
String s3;
s3 = s1; //调用operator=
String s2=s1; //调用String(const String&)构造
String s3;
s3 = s1; //调用operator=
#26
回23楼,改了后是可以了,但是还是有些小问题。
就是<<s3输出的是happy birthday而不是 to you。而且我加了书上的复制构造函数也是出可以的结果。
回24楼,现在清楚了,以后会养成这样的习惯的。
再次麻烦你帮看看,为什么输出s3时是happy birthday而不是 to you?要怎么改?
就是<<s3输出的是happy birthday而不是 to you。而且我加了书上的复制构造函数也是出可以的结果。
回24楼,现在清楚了,以后会养成这样的习惯的。
再次麻烦你帮看看,为什么输出s3时是happy birthday而不是 to you?要怎么改?
#27
按照下面顺序理论上应该先出现
s1 is happy
s2 is birthday
s3 is to you
s1+s2 is happybirthday
s1+s2+s3 is happybirthdayto you
s3=s1+s2 is happybirthday
如果不是这样,估计这和ios的缓存有关,建议你把所有的\n都换成endl,强迫ios刷新缓存
cout < <"s1 is " < <s1
< <"\ns2 is " < <s2
< <"\ns3 is " < <s3//还没到s3=s1+s2就帮我提前修改了s3,想不通为什么。
< <"\ns1+s2 is " < <s1+s2
< <"\ns1+s2+s3 is " < <s1+s2+s3
< <"\ns3=s1+s2 is " < <(s3=s1+s2) < <endl;
s1 is happy
s2 is birthday
s3 is to you
s1+s2 is happybirthday
s1+s2+s3 is happybirthdayto you
s3=s1+s2 is happybirthday
如果不是这样,估计这和ios的缓存有关,建议你把所有的\n都换成endl,强迫ios刷新缓存
cout < <"s1 is " < <s1
< <"\ns2 is " < <s2
< <"\ns3 is " < <s3//还没到s3=s1+s2就帮我提前修改了s3,想不通为什么。
< <"\ns1+s2 is " < <s1+s2
< <"\ns1+s2+s3 is " < <s1+s2+s3
< <"\ns3=s1+s2 is " < <(s3=s1+s2) < <endl;
#28
非常非常感谢啊~
的确行了,看来endl才是万能的。
啊哈哈哈~~~
的确行了,看来endl才是万能的。
啊哈哈哈~~~
#29
它也就多调用一次flush而已
#30
今天一定能睡个好觉!
#31
#32
mark
#33
mark2
#34
好复杂。。。。。
#35
确实
,有点复杂
,有点复杂
#36
LZ的代码看上去有点乱,密密麻麻的....
#37
有点乱