<
}
输出:
(3.0,4.0
(6.0,8.0
Distanceis5
友元函数的特点:
1.友元函数是普通函数,不是成员函数。
2.友元函数在调用时可以直接调用,不需要对象表示。
3.说明在类体内,说明时前加关键字friend。
4.定义在类体外,定义方法和普通函数一样。
5.它可以直接引用类中的私有成员。
通过友元的方式,一个普通函数可以访问到封装于某一类中的数据,这相当于给类的封装挖了一个小小的孔,把数据的隐藏掀开了一个小小的角,通过它,可以看到类内部的一些属性。
从这个角度讲,友元是对数据隐藏和封装的破坏。
但是考虑到数据共享的必要性,为了提高程序的效率,很多情况下,这种小的破坏也是必要的。
例5.21
#include
classTime
{public:
Time(inth,intm
{hours=h;minutes=m;}
friendvoidTime12(Timetime;
friendvoidTime24(Timetime;
private:
inthours,minutes;
};
voidTime12(Timetime
{if(time.hours>12
{time.hours-=12;
cout<”:
”<
<<”PM”<
else
cout<”:
”<
<<”AM”<
voidTime24(Timetime
{cout<”:
”<
<
voidmain(
{TimeTime1(20,30,Time2(10,45;
Time12(Time1;
Time24(Time1;
Time12(Time2;
Time24(Time2;
}
输出:
8:
30PM
20:
30
10:
45AM
10:
45
在本例中,友元函数是一个普通函数,同样,这个函数也可以是另外一个类的成员函数。
5.6.2友元类
同函数一样,类也可以声明为另一个类的友元,这时称为友元类。
若A类为B类的友元类,则A类的所有成员都是B类的友元函数,都可以访问B类的私有和保护成员。
例5.22分析下列程序的输出结果:
#include
classX
{friendclassY;//Y类是X类的友元类
public:
voidSet(inti{x=i;}
voidDisplay(
{cout<<”x=”<”,y=”<
private:
intx;
staticinty;
};
classY
{public:
Y(inti,intj
{a.x=i;X:
:
y=j;}
voidDisplay(
{cout<<”x=”<”,y=”<
<
private:
Xa;
};
intX:
:
y=1;
voidmain(
{Xb;
b.Set(5;
b.Display(;
Yc(6,9;
c.Display(;
b.Display(;
}
输出:
x=5,y=1
x=6,y=9
x=5,y=9
说明:
1.一般来说,在一个类的成员函数中,不能引用另一个类的私有成员,但在友元类中可以。
2.X类的y是静态成员,通过Y类的对象c改变了它的值后,将仍然保存其值,在X类的对象b中,y成员的值仍然是改变后的值。
可见,Y类对象与X类对象共用静态成员y。
注意:
1.友元关系不能传递。
B类是A类的友元,C类是B类的友元,C类和A类之间,如果没有声明,就没有任何关系,不能进行数据共享。
2.友元关系是单向的。
B类是A类的友元,B类的成员函数可以访问A类的私有和保护数据,但A类的成员函数却不能访问B类的私有和保护数据。
5.7类的作用域
类的作用域(类域:
类的定义中由一对花括号括起来的部分。
在类域中定义的变量不能使用auto,register和extern等修饰符。
类域包含在文件域中。
5.8局部类和嵌套类
5.8.1局部类
局部类:
在一个函数体内定义的类。
例如:
inta;
voidfun(
{staticints;
classA;
{public:
voidinit(inti{s=i;}
};
Am;
m.init(10;
}
5.8.2嵌套类
嵌套类:
在一个类中定义的类。
例如:
classA
{public:
classB
{public:
…
private:
…
};
voidf(;
private:
inta;
}
5.9对象的生存期
对象的生存期:
指对象从被创建到被释放为止的时间。
按生存期可分:
1.局部对象:
当对象被定义时调用构造函数,当程序退出定义该对象所在的函数体或程序块时,释放对象。
2.静态对象:
当程序第一次执行所定义的静态对象时,该对象被创建,当程序结束时,该对象被释放。
3.全局对象:
当程序开始时,调用构造函数创建对象,当程序结束时,该对象被释放。
局部对象定义在函数体或程序块内。
静态对象定义在一个文件中。
全局对象定义在某个文件中。
例5.23不同对象的生存期
#include
#include
classA
{public:
A(char*st
{strcpy(string,st;
cout<<”Constructorcalledfor”
<
~A(
{cout<<”Destructorcalledfor”
<
private:
charstring[50];
};
voidfun(
{AFunObject(“FunObject”;局部对象
staticAstaticObject(“StaticObject”;
静态对象
cout<<”Infun(.”<
AGlobalObject(“GlobalObject”;全局对象
voidmain(
{AMainObject(“MainObject”;局部对象
cout<<”Inmain(,beforcalledfun\n”;
fun(;
cout<<”Inmain(,aftercalledfun\n”;
}
输出:
ConstructorcalledforGlobalObject
ConstructorcalledforMainObject
Inmain(,beforcalledfun
ConstructorcalledforFunObject
ConstructorcalledforStaticObject
Infun(.
DestructorcalledforFunObject
Inmain(,aftercalledfun
DestructorcalledforMainObject
DestructorcalledforStaticObject
DestructorcalledforGlobalObject
作业:
1.设立一个立方体类Box,在该类定义中包括:
数据成员:
length,width和height。
成员函数:
(1Box(设置盒子的长、宽和高;
(2volume(计算盒子的体积;(3area(计算盒子的表面积;
(4disp(输出盒子的体积和表面积。
在main(中创建对象,求盒子的体积和表面积,输出体积和表面积。
2.定义一个Book类,在该类定义中包括:
数据成员:
bookname,price和number;
成员函数:
(1Book(为对象赋初值。
(2display(显示图书的情况。
3.遍写一个程序,输入N个学生数据,包括学号、姓名、成绩、要求输出这些学生数据并计算平均分。
4.第5章后面的作业题四。
练习:
第5章后面的练习题和作业题一、二、三。