我正在学习c ++。我正在研究运算符重载,我能够理解加法和减法运算符重载。但I / O运算符的过载有点令人困惑。 我已经为复数创建了一个类,现在我正在重载运算符。
Complex.h中的函数原型
friend ostream& operator<<(ostream&, const Complex&);
Complex.cpp的功能
ostream& operator<<(ostream& os, const Complex& value){
os << "(" << value.r <<", "
<< value.i << ")" ;
return os;
}
答案 0 :(得分:3)
你没有拥有使流媒体运营商成为朋友。它必须在外部声明 ,因为Complex对象位于运算符的右侧。
但是,如果您的Complex类有办法访问所需的成员(可能通过getter),您可以让流操作符使用它们。说:
std::ostream& operator<<( std::ostream& os, Complex const& cpx )
{
return os << cpx.getReal() << ',' << cpx.getImaginary();
}
您的operator/
重载可以作为内部函数完成,但实际上也可以更好地实现为具有两个const&amp;的外部函数。参数。如果它是一个成员函数,它需要是一个const成员。你的不是。
您可以根据operator /=
Complex operator/ ( Complex const& lhs, Complex const& rhs )
{
Complex res( lhs );
res /= rhs; // or just put return in front of this line
return res;
}
答案 1 :(得分:2)
friend ostream& operator<<(ostream&,const Complex&);
:
因为您在此处声明了一个自由函数,并希望它能够访问Complex
个对象的内部(私有/受保护)。拥有&#34;朋友免费功能是非常普遍的。对于那些超载,但肯定不是强制性的。
因为流是不可复制的(没有意义,请参阅this post),传递值需要复制。按值传递Complex
也需要无用的副本。
因为那些输出操作符不应该修改它们正在处理的对象(显然是输入操作符),所以添加const
以确保它。
答案 2 :(得分:1)
任何人都可以解释(在基本层面上)为什么我们必须在这里使用友元函数声明吗?
如果你声明一个类friend of
另一个类,那么你就是说友人类可以访问你班级的私有和受保护的属性和功能。
在您的情况下,您将ostream& operator<<
声明为friend,这意味着在该函数的主体内,ostream类将能够访问复杂类的私有和受保护函数和属性。
为什么我们必须通过引用传递所有参数和运算符的返回类型?
因为它是这样写的,以避免制作ostream对象的副本。因此,每次使用时,<<
重载都将使用相同的对象而不进行复制。
函数之后的这个函数在不使用const的情况下工作正常,但为什么我们在这里使用const?将Complex作为常量引用传递的优点是什么?
const
意味着你没有改变类的任何属性,你不这样做。
我认为这是正确的,我希望它有所帮助,但如果有人想发表意见,请随意。
答案 3 :(得分:0)
friend ostream& operator<<(ostream&, const Complex&);
此处函数需要是朋友,因为您可能需要能够访问复杂的私有成员。
当您为<<
类重载Complex
时,您可能需要在重载函数中访问Complex
类的数据成员,并且数据成员可能是私有的。如果它们是私有的,要访问operator <<
中的数据成员,您需要使其成为complex
类的成员,这是不可能的,因为运算符的左侧对象是ostream
类类型所以只有选项是使用全局范围函数使其成为Complex
的朋友并覆盖<<
。
现在通过引用返回对象,以避免创建其他人告诉的对象的多个副本。并且必须返回该对象,因为当运算符用于级联写入时它将支持`cout&lt;
参数作为const
传递,因为如果不在函数旁边更改对象,那么接收对象const
始终是一个好习惯。这使它适用于const
个对象。
答案 4 :(得分:0)
1.任何人都可以解释(在基本层面上)为什么我们必须在这里使用朋友功能?
如果您需要访问Complex
中的operator<<
的私人成员。
2.为什么我们必须通过引用传递操作符?
为了提高效率。通过const引用传递比通常用户定义类型的值传递更快。
3.这个函数在不使用const的情况下工作正常,但为什么我们在这里使用const?将Complex作为常量对象传递的优点是什么?
如果您不这样做,则无法输出const对象,例如:
const Complex c;
std::cout << c;
答案 5 :(得分:0)
对于非朋友成员函数运算符,只有一个参数,即运算符的右侧。因此,对于使用除法运算符的示例,您可以这样做:
Complex a = ...;
Complex b = ...;
Complex c = a / b;
并且编译器实际上会将最后一个视为
Complex c = a.operator/(b);
这意味着例如输出操作符,如果它是普通成员函数,则“输出”到类的实例。换句话说,它将像
一样使用Complex a = ...;
Complex b = ...;
a << b; // Really a.operator<<(b);
显然,当实现应输出到流的运算符时,这不是所需的。因此,我们需要使用非成员函数,它可以使用两个不同的参数。
对于第二点,请记住传递参数的默认方法是按值,这意味着值是复制。对于较小的类而言并不重要,但如果有大量数据,或者类具有复杂的复制构造函数,则可能会产生相当大的性能损失。此外,某些类型和类无法被复制,例如std::istream
,因此您有通过引用传递它们。
对于最后一点,通过创建一些参数const
,您告诉编译器和函数的用户它不会更改参数。除了让函数用户更容易知道调用函数不会产生任何副作用外,它还允许编译器进行一些优化。
通常关于运算符重载,您可能需要阅读this reference on the subject。
答案 6 :(得分:0)
有谁可以解释为什么我们必须在这里使用朋友功能?
类的friend
可以从指定为private
的类中访问protected
或friend
个变量/函数。如果需要访问任何私有功能,则必须使I / O运算符为friend
类Complex
。如果没有,可以简单地在类之外定义函数而不将其声明为这样。
为什么我们必须通过引用传递操作符?
我不确定你的意思。运算符是我们定义的函数,而不是在任何地方传递的参数。你指的是它需要的参数吗?好吧,std::ostream
被视为引用类型,因为按值获取它会导致副本,这是流类不允许的。试试看,你会遇到编译错误。我将谈谈为什么Complex
被视为下面的参考类型。
此函数在不使用
const
的情况下正常工作,但为什么我们在这里使用const
?将Complex
作为常量对象传递的好处是什么?
首先,为什么不使用const
? const
类型修饰符是编译器的明确声明,我们不会以任何方式更改对象。它还使维护者清楚了解您的代码。此外,写出对象通常需要值,这意味着不需要对对象进行任何修改。
使用对const
的引用还允许您将rvalues或tempoaries传递给函数,这对于 non - const
的引用是不可能的,左值。例如:
struct S { };
void f(S&);
void h(S const&);
int main()
{
S s;
f(s); // OK
f(S()); // ERROR!
h(s); // OK
h(S()); // OK
}