红皮书(P109-P118)
2016.3.23
关于友元(friend)
一个类的公有成员可以让其它类访问
一个类的私有成员只能让本类成员访问
要想类的私有成员被其他类访问,则:
把要访问的类声明为自己的友元,这就是友元的作用
友元函数
#include <iostream>
using namespace std;
class Date; //对类的提前引用的说明,这句话不能少
class Time
{
public:
Time(int,int ,int );
friend void display(Time &);//声明display函数为Time的友元函数,同时&是引用参数的,不是必须存在的
void display_t(Date &);//display_t是成员函数,但是它的形参是Date类的,且调用的是Date的私有成员,所以需要Date声明这个函数为自己的友元函数。
private:
int hour;
int sec;
int min;
};
class Date
{
public:
Date(int ,int, int );
friend void Time :: display_t(Date & );//将Time类的display_t函数声明成自己的友元函数以便这个类可以访问自己的私有变量
private:
int year;
int mon;
int day;
};
void Time :: display_t(Date & d)
{
cout << d.year<< "." << d.mon << "." << d.day << endl;//引用的变量不是这个类的因此要指明属于那哪个对象的
cout<<hour<<":"<<min<<";"<<sec<<endl;
//这些变量都是此类中的成员,因此直接用,不需加变量名也可以
}
Time::Time(int h, int s, int m)
{
hour = h;
sec = s;
min = m;
}
Date:: Date(int y,int m ,int d)
{
year = y;
mon = m;
day = d;
}
void display(Time &t)
{
cout << t.hour <<":"<< t.min<<":" << t.sec << endl;//这地方依然显示红色的错误
}
int main()
{
Time time(12, 32, 54);
Date date(2016, 3, 23);
display(time);
time.display_t(date);
system("pause");
return 0;
}
上面的程序:
- diaplay函数不是类中的函数
- 如果不把display函数声明为友元,则函数display不能访问Time的私有成员
- 引用类中的成员时,必须加上对象名,指明是那个对象的,因为display函数不是类成员,因此不存在this指针,不能自动的指明是哪个对象的,所以要显式的表示
friend函数不止可以是非成员函数还可以是另一个类的成员函数
见上面的Date类的表示。
上面程序显示红色的波浪线,主要是提示不能引用Date的私有变量,即使是声明为友元函数,但是可以运行,运行结果是正确的。
time.display_t(date);
注意这句话在display_t前面要加上对象名
cout << d.year<< “.” << d.mon << “.” << d.day << endl;
注意这句话在Time的display_t里引用Date类的私有成员要加其对象名
class Date;
是对Date的提前引用,即使把两个类的声明调换位置也不行,因为Date里面的第四行也用到了Time类,所以还是要提前引用。
关于提前引用:
1、可以提前引用类名,但是不能提前引用对象,因为对象时必须在有类的实体之后才给分配存储空间,提前引用不能确定分配多大的存储空间。
2、但是可以利用提前引的类的名字去引用该类的对象指针和对象的引用。
3、display_t之前必须把Date类定义好,否则会报错。因为这个函数要用到Date类的成员,如果没有声明会找不到这样的对象而报错。
二、友元类
友元不仅可以是函数,也可以是整个类
声明:
friend 类名;
class A
{
friend B; //B是A的友元类。即B可以访问A的所有成员
}
场面声明Time是Date的友元类,则Time就可以访问Date的所有成员,即:
class Date
{
friend Time;
}
说明:
1、友元的关系是单向的,B是A的友元不代表A是B的友元(习惯上并不把整个类声明为友元类,因为是对封装原则的小破坏,但利于数据的共享,提高程序的效率)
2、友元关系不能传递
关于类模板
之前一直没能好好地理解,现在又再一次地理解一下。
作用:针对功能相同但是数据类型不同的函数的简化。
用类模板定义类:
#include <iostream>
using namespace std;
template <class numtype>//不可少,末尾无分号
class Compare
{
public:
Compare(numtype ,numtype);
numtype max();
numtype min( );
private:
numtype a, b;
};
template < class numtype >
numtype Compare <numtype> ::max( )
{
return (a > b) ? a : b;
}
template < class numtype>
Compare < numtype >::Compare(numtype aa, numtype bb)
{
a = aa;
b = bb;
}
template < class numtype>
numtype Compare <numtype>::min( )
{
return (a < b) ? a : b;
}
int main()
{
Compare <int> cmp1 (3,7);
Compare <float> cmp2(2.5, 3.5);
cout << "较大值:" << cmp1.max() << "," << "较小值:" << cmp1.min() << endl;
cout << "较大值:" << cmp2.max() << "," << "较小值:" << cmp2.min() << endl;
system("pause");
return 0;
}
这里的numtype是自己的定义的类型,是个虚拟名称而已
注意:
1、成员函数在类外声明:
template < class numtype> //要先声明类模板
numtype Compare ::min( )
返回值类型 类名 <参数类型>(这是带参的类)::成员函数(这是带参的类)
**2、定义在类内的话和普通的规则没区别
规则:
3、定义类:
template
4、定义类对象:
类名 <对象的参数类型> 对象名 (初始化);
Compare cmp1 (3,7);
5、类模板可以有层次,可以派生出子类
6、模版的作用域在这个文件,产出这个文件就不再起作用了。
后记:第三章基本讲了这些,还没看习题,抽空把习题做了,就进入第四章了。