原题:
狐狸精
描述
反派是三只成精的狐狸:狐母,狐女和狐子阿拐。
狐狸成精后,开始作恶多端。假设有Fox
类,有自己的大小int size
和法力int power
。
狐狸精甲如果和狐狸精乙合体(&&),会变成一只更大的狐狸丙,size
变成原来甲和乙的size
之和,power
会变成原来甲和乙的power
平均值。
狐狸还会飘(~),飘的时候,size会自动变成原来的三分之一。
请参考下面的main
用一个Fox
类来实现这些法力。
int main()
{
int s1, p1, s2, p2;
cin >> s1 >> p1 >> s2 >> p2;
Fox C1(s1, p1);
Fox C2(s2, p2);
C1.show(); // 现身
~(~C1); // 飘2次
C1.show(); // 再现身
Fox C3 = C1 && C2; // 合体
C3.show(); // 现身
return 0;
}
输入
两只狐狸的信息size power
输出
见main
函数输出及输出样例。其中,show函数依次输出size power
,中间以空格分隔,最后换行。
100 50 120 80
输出样例 1
100 50 11 50 131 65
提示
- 仅需提交Fox类代码和相关函数代码。
- 实现相关运算符重载。飘2次的地方注意函数返回值写法。
- 整数计算过程不考虑小数部分。
来源 hlu
问题:
Fox& operator~()
{
size/=3;
return *this;
}
Fox operator~()
{
return Fox(size/3, power);
}
Fox& operator~()
{
return Fox(size / 3, power);
}
为什么这三种写法看起来一样却又不同结果?在这道题中,只有第一种正确,第三中甚至不能正确编译
解决:
在这个问题中,我们需要考虑C++运算符重载的语义和返回类型。对于单目运算符~
,如果我们要实现一个“飘”的功能,通常我们会希望这个操作能够改变当前对象的状态,并且能够链式调用(即连续飘多次)。这就要求我们的重载运算符能够返回一个引用,以便可以连续调用。
- 第一种写法:
Fox& operator~() { size /= 3; return *this; }
这种写法是正确的,因为它返回了当前对象的引用,允许链式调用。例如,~(~C1)
首先对C1
调用一次~
,然后使用结果再次调用~
,因为每次调用都返回了对象的引用。 - 第二种写法:
Fox operator~() { return Fox(size / 3, power); }
这种写法返回了一个新的Fox
对象,而不是引用。这在逻辑上是有问题的,因为如果按照这种写法,~(~C1)
将不会工作,因为第一个~
会返回一个新的Fox
对象,而第二个~
无法在这个新对象上调用来实现链式飘的效果。 - 第三种写法:
Fox& operator~() { return Fox(size / 3, power); }
这种写法试图返回当前对象的引用,但实际上返回的是新创建对象的引用。这是有问题的,因为返回的引用指向的是一个局部的临时对象,一旦函数返回,这个局部对象的生命周期就结束了,导致返回的引用悬空(dangling reference)。这将导致未定义行为,编译器通常也会报错,因为它违反了C++的规则。
总结一下:
为什么这些写法不同?
1. 语义差异
- 第一种写法修改当前对象,适用于需要改变对象状态的场景。
- 第二种写法创建新对象,适用于需要保留原始对象的场景。
- 第三种写法在语义上是混乱的,因为它试图返回一个引用,但实际上返回的是局部对象的引用。
2. 编译问题
- 第一种写法是正确的,因为它遵循了C++的规则。
- 第二种写法虽然逻辑上有问题,但至少可以编译通过。
- 第三种写法违反了C++的规则,因为它试图返回局部对象的引用,这会导致编译错误。
AC源码:
#include<iostream>
using namespace std;
class Fox
{
private:
int size;
int power;
public:
Fox(int s,int p):size(s),power(p)
{
}
void show()
{
cout<<size<<" "<<power<<endl;
}
Fox& operator~()
{
size/=3;
return *this;
}
friend Fox operator&&(Fox & c1,Fox & c2);
};
Fox operator&&(Fox & c1,Fox & c2)
{
return Fox(c1.size+c2.size,(c1.power+c2.power)/2);
}
int main()
{
int s1, p1, s2, p2;
cin >> s1 >> p1 >> s2 >> p2;
Fox C1(s1, p1);
Fox C2(s2, p2);
C1.show(); // 现身
~(~C1); // 飘2次
C1.show(); // 再现身
Fox C3 = C1 && C2; // 合体
C3.show(); // 现身
return 0;
}