//Student.h
class Student
{
private:
int mId;
float height;
int score;
public:
Student(int id = 0, float h = 0, int s = 0) :height(h), mId(id), score(s)
{
}
ostream &operator<<(ostream &out, Student &s1){
out << s1.mId << " " << s1.height << " " << s1.score << endl;
return out;
}
//********************************
};
乍一看,没什么问题!
但是!
这时候cout 一个对象的时候编译会报错!
那问题出在哪呢???
后来
我将重载函数在类内改成了如下所示。前面加了一个friend
friend ostream &operator<<(ostream &out, Student &s1){
out << s1.mId << " " << s1.height << " " << s1.score << endl;
return out;
}
编译通过了!
此时能正常cout对象!
但奇怪的是,friend不是用于把非成员函数的声明为友元函数的吗?为什么直接在类内实现了呢?
难道不应该是这样吗?
class Student
{
private:
int mId;
float height;
int score;
public:
Student(int id = 0, float h = 0, int s = 0) :height(h), mId(id), score(s)
{
}
friend ostream &operator<<(ostream &out, Student &s1);
};
ostream &operator<<(ostream &out, Student &s1){
out << s1.mId << " " << s1.height << " " << s1.score << endl;
return out;
}
注意,这种方法当然也可以。
但像之前的那种写法同样适用。
个人认为是ostream类是c++标准输出流的一个基类,是c++库中的类,
friend可能是把C++库中的ostream当成一个友元,相当于该类中friend友了一个C++库中的东西,并在类内实现了。
而如果不加friend,这个类内的ostream重载,程序并不认得,于是编译就会出问题。
此处追加一个很有意思的问题。
friend ostream &operator<<(ostream &out,const Student &s1){
out << s1.mId << " " << s1.height << " " << s1.score << endl;
return out;
}
为什么最好再Student &s1 前加一个const呢??
不加const行不行呢?
这里涉及到临时变量的问题
: 临时变量.、
再看下面一个例子
#include <iostream>
using namespace std;
class Point{
public:
Point(int a, int b):x(a),y(b){}
Point operator=(const Point &p);
ostream& operator<<(ostream &out);
private:
int x,y;
};
ostream& Point::operator<<(ostream &out)
{
out << '(' << x << ',' << y << ')' << endl;
return out;
}
Point Point::operator=(const Point &p){
x = p.x;
y = p.y;
return Point(x,y);
}
int main(){
Point a(1,2),b(3,4),c(5,6);
a << cout; //居然编译成功,cout << a;编译失败!
return 0;
}
a << cout; //居然编译成功,cout << a;编译失败!
为啥呢???
在类内的成员函数中,非静态成员函数参数隐藏着this参数,而且是第一个参数。
ostream& operator<<(ostream& out)
实际上是
ostream& operator<<(Point *this, ostream& out)
这样的。
我们都知道
运算符的重载实际上是函数重载。
那么在调用该函数时,this 就默认传递了对象的地址。
在输出时,<<运算符要严格的按照参数的顺序进行书写,即先写this后写out。
所以是 a << cout;
但我们希望是 cout << a;这样输出。
所以,通常重载的输出操作符是写在类外的,或者声明为友元函数,不会将其写为成员函数。