当函数/成员函数,返回对象时,有几种返回方式:
①返回指向对象的引用(例如String& operator=(xx,xx));
②返回被const限定的指向对象的引用(例如const String& operator=(xx,xx));
③返回const对象(这个之前没有遇介绍过)。
④返回对象(一般返回的不是类对象,而是类中的某一个数据对象。如果返回类对象的话,会调用复制构造函数——因为创建的是一个副本);
返回指向const对象的引用:
因为指向const对象,因此,对象不能被修改。
①假如调用的是const对象,那么应该在参数列表的括号后,加上const进行限定;
②假如是const对象作为参数,那么参数应该加上const表示限定;
并且,无论是哪种情况,函数名前必须加入const,因为返回值是const对象的引用。只有加了const才能限制返回值不作为左值。
其格式大致如下:
情况①
const String& String::函数名(参数列表)const
{
...
}
第一个const指返回值,第二个const指调用成员函数的对象
情况②
const String& 函数名(const String & 对象)
{
...
}
第一个const指返回值,第二个const指传递对象的引用
如果面向两种都可以用,那么则综合起来:
情况③
const String& 函数名(const String & 对象)const
{
...
}
第一个const指返回值,第二个const指传递对象的引用,第三个const指调用函数的对象。
返回指向非const对象的引用:
两种比较常见的返回非const引用的对象:
①赋值运算符重载(例如 =,但是+-*/ %这五个一般不会返回引用,会返回对象的引用);
②重载与ostream类、istream类一起使用的<<或>>运算符(为了能连续cout<<对象a<<对象b这样,必须返回);
对于①,返回非const对象的引用,可以避免创造一个副本来传递,节约内存,提高效率。
对于②,必须返回其引用(例如ostream&),原因在于只有这样,才能做到连续使用<<运算符来连接多个对象或者其他。
而对于=来说,返回对象的引用,可以进行连续赋值。例如a=b=c。
函数一般为:
Man& Man::operator=(const Man&n) //调用的是被赋值的对象,隐式传递给函数
{
if (this == &n) return *this; //用于自己赋值给自己,判断地址的原因在于对象==对象需要运算符重载
a = n.a; //相等
len = n.len; //自然也相等
delete[]b; //因为已经初始化过了,新的长度不确定,因此要delete[]掉老的再重新申请动态内存
b = new char[len + 1]; //new
strcpy_s(b, len + 1, n.b); //复制
return *this; //返回对象,*this表示当前对象
}
返回对象(函数内对象的副本):
假如返回的是函数内声明的对象,那么在函数结束时,这个对象将被执行析构函数,因此,只能返回其副本。例如Man Man::get(); 使用的是Man而不是Man&,便表示的是返回对象。
返回对象其原理已知,跟普通函数返回基本类型、指针、结构一样。在return时,创建一个副本(调用复制构造函数),然后把副本放在寄存器,再将副本赋值给其。
一般是面对算数运算符(+、-、*、/、%)时使用。在函数内创建一个对象,然后把结果赋值给这个对象的各个成员,再将这个对象返回。
假如对象c=对象a+对象b。那么完成这行代码,
①执行一次返回对象的加法运算符重载函数;
②在运算符重载函数的return语句,调用复制构造函数创建副本;
③再执行一次赋值运算符重载(假如是新对象初始化的话,改为执行复制构造函数)。
函数一般为:
Man Man::operator+(const Man n) //两个对象相加并返回对象
{
Man c; //创建对象c
c.a = a + n.a; //c的a=两个对象a的和
delete[]c.b; //删除c的b(因为之前new过)
c.len = len + n.len; //c的字符串长度等于2个字符串长度之和(因为要将两个字符串拼起来)
c.b = new char[c.len + 1]; //c要new一个比字符串长1的内存(因为要留给空字符一个位置)
strcpy_s(c.b, len + 1, b); //之所以要len+1,应该是要将空字符复制进去,反正用len不行
strcpy_s(c.b + len, n.len+1, n.b); //复制第二段字符
return c; //返回对象c,调用一次复制构造函数
}
main函数:
Man a(1,"abc");
Man b(2,"def");
Man c = a + b; //调用复制构造函数
Man d;
d = b + a; //调用赋值运算符重载
c.show();
d.show();
显示:
3,abcdef,6
3,defabc,6
效果是结果等于相加的两个各个数据成员之和(字符串则是将字符串拼在一起)。
返回const对象:
返回const对象的意义在于,避免让返回值成为左值。
例如,int a、b、c;那么a=b+c是成立的,而a+b=c这样的算术式是不成立的。
然而,假如有Man operator+()这样的类重载函数,那么a+b=c这样的算术式是成立的。原因在于,a+b返回一个临时对象(根据运算符重载的函数定义,并且会调用复制构造函数创建临时对象),此时,是可以将c的值赋值给这个临时对象的(虽然并没有意义)。
因此,可以使用cosnt Man operator+(),这样的话,由于返回值被const限定,因此不能成为左值。于是,a+b=c这样的等式便不能使用了。