class Date
{
public:
Date (int year,int _month, int _day)
:_year(year)
,_month(month)
,_day(day)
{}
void print()
{
cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2021,7,15);
d1.print();
return 0;
}
对象可以通过上述方式进行打印,但是代码可读性低不直观;
对于内置类型的打印,我们之间用<<操作符输出;但是用<<操作符输出对象却会报错:
int a=10;
cout<<a<<endl;
Date d1(2021,7,15);
cout<<d1<<endl;//出错
所以要对<<操作符进行重载,操作符有两个操作数,一个是cout,一个是对象
cout是另外一个类创建出来的对象
void operator<<(ostream& _cout)//_cout:是cout的别名,类型是输出流对象
{
_cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
}
Date d1(2021,7,15);
d1.operator<<(cout);//所以将cout作为参数传递
//省略后d1<
被重载成类的成员函数,成员函数要用对象调用
d1.operator<<(cout);
被重载成类的成员函数,第一个参数是隐藏的this指针
d1<与常使用的cout<<...
相反
class Date
{
int getyear()const
{
return _year
}
int getmonth()const
{
return _month;
}
int getday()const
{
return _day
}
};
ostream& operator<<(ostream& _cout, const Date& d)
{
_cout<<d.getyear()<<"-"<<d.getmonth()<<"-"<<d.getday()<<endl;
return _cout;
}
有返回值的原因:
cout<
cout<这就是一个函数调用,该函数就有一个返回值,否则就不能连续输出
类中提供get函数的原因:
通过友元
class Date
{
public:
friend ostream& operator<<(ostream& _cout, const Date& d)
//声明友元函数,也可以在类中实现
}
ostream& operator<<(ostream& _cout, const Date& d)
{
_cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
return _cout;
}
在类中将运算符重载为类的友元函数(之前的重载函数都是将运算符重载为类的成员函数)
友元函数不属于类的成员函数,所以可以放在类中的任意位置声明
类之间只允许通过公有的外部接口访问,不允许其它类程序代码访问自己的私有(或保护)成员。
也就是说,封装的两个类之间除了公有的接口外,没有其他的进入渠道,说类A是类B的友元,就像类B自己给类A开了一扇小窗,通过这扇窗,类A可以访问类B的私有信息
友元分友元类、友元成员函数和友元函数3种:
class B
{
friend class A;
}
在类B中声明类A是自己的友元,则称类A是类B的友元类,类A中所有成员函数都可访问类B的所有权限的成员(记忆时,类A在类B中定义,将A等同于B中的成员,A访问B的成员);
class B
{
friend void A::F();
}
类B中 定义类A的某个成员函数是自己的友元,则称该成员函数是类B的友元成员函数;
某成员函数是类B的友元成员函数,则该成员函数可以访问类B的所有成员
代码为:对<<操作符的重载
若类B定义某个函数是自己的友元,则称该函数是类B的友元函数。
某函数是类B的友元函数,则该函数可以访问类B的所有成员。
可以看出,友元为严密封装的类提供了方便快捷的访问途径,但友元也在某种程度上破坏了类的封装性。所以,程序中是否使用友元方法要权衡利弊,综合考虑。
一个类定义在另一个类的内部,这个内部类就叫做内部类
class B
{
class A
{
};
};
与友元类的相同点:
不同点:
内部类特性: