第11章 友元与运算符重载 ·275·
第11章 友元与运算符重载
通过本章的学习,应理解友元的概念,掌握将普通函数、成员函数定义为类友元函数的方法,学会友元函数的使用方法。理解运算符重载的概念,掌握运算符重载函数的定义方法、调用过程及实际应用。掌握多态性技术的概念及实现方法。了解虚函数与纯虚函数的概念、定义格式及使用方法。
11.1 友元函数
为了数据的安全,通常将类中数据成员的访问权限定义为私有或保护,使数据成员只能在类或其子类中访问。若要在类外访问,则必须通过该类的公有成员函数才能访问这些数据成员。这种做法虽然保证了数据的安全性,但也给使用带来许多不便,为此,在C++中提供了友元函数,允许在类外访问类中的任何成员。
友元函数可以是普通函数,也可以是某个类的成员函数,甚至可以将某个类说明成另一个类的友元。下面就这三种友元进行讨论。
11.1.1定义普通函数为友元函数
在定义一个类时,若在类中用关键词friend修饰普通函数,则该普通函数就成为该类的友元函数,它可以访问该类中所有的成员。定义普通友元函数的格式为:
friend <类型> <友元函数名> (形参表); 即:只要将用关键词friend修饰的普通函数原型说明写在类中,则该普通函数可以使用类的所有成员。下面用例题进行说明。
【例11.1】 用友元函数的方法求长方体的体积。
分析:先定义一个描述长方体的类Cuboid,其私有数据成员为长方体的长(Length)、宽(Width)、高(High),通过构造函数对长方体的数据成员进行初始化,见下列程序A行处。再定义一个求长方体体积的普通函数Volume():
float Volume(Cuboid &c)
{return c.Length*c.Width*c.High;}
为了计算长方体对象c的体积,该函数的形参必须是长方体类的对象c,并用该长方体对象c的长、宽、高计算长方体的体积。由于Volume()为普通函数,因此在其函数体内不能使用长方体类Cuboid的私有数据成员c.Length、c.Width、c.High,因而上述函数在编译时会发生错误。解决问题方法之一就是将计算长方体体积的普通函数Volume()定义为长方体类的友元函数,即在长方体类Cuboid中增加一条将普通函数Volume()定义成友元函数的语句:
friend float Volume(Cuboid &);
则在普通函数Volume()内就可使用长方体类Cuboid的私有数据成员c.Length、c.Width、c.High。用友元函数方法求长方体体积的程序如下:
第11章 友元与运算符重载
# include
class Cuboid //A { private:
float Length,Width,High; public:
Cuboid(float l,float w,float h) { Length=l;Width=w; High=h;}
friend float Volume(Cuboid &); //B };
float Volume(Cuboid &c) //C { return c.Length*c.Width*c.High;} void main (void)
{ Cuboid c(10,20,30);
cout<<\长方体积=\olume(c)< 程序执行后输出: 长方体积=6000 ·276· 在程序中,计算长方体体积的函数Volume()是返回类型为float的普通函数。由于在类Cuboid中B行,用关键词friend将Volume()说明为Cuboid类的友元函数。因此,在Volume()函数中可以使用类中的私有数据成员Length、Width、High来计算长方体的体积。又因为Volume()不是Cuboid类的成员函数,它不带有this指针。所以必须用对象名或对象的引用(Cuboid &c)作为友元函数的形参,并在函数体内使用运算符“.”来访问对象的成员,如c.Length、c.Width与c.High。对友元函数需说明如下: (1)友元函数并不是类的成员函数,它不带有this指针。所以必须用对象名或对象的引用作为友元函数的形参,并在函数体内使用运算符“.”来访问对象的成员。 (2)友元函数必须在类内进行函数的原型说明,其函数的定义部分应写在类外。 (3)友元函数与一般函数的区别 友元函数可访问类内的任一数据成员或成员函数,如:矩形类的私有数据Length、Width与High。而一般函数只能访问类的公有数据成员或公有成员函数。 (4)由于友元函数不是类的成员函数,所以类的访问权限对友元函数不起作用。即友元函数的原型说明写在类的任一位置对其访问权限没有影响。 (5)由于友元函数可使用类内的所有成员,破坏了数据的安全性,所以使用友元函数必须谨慎,不要通过友元函数对数据成员进行危险的操作。 11.1.2定义成员函数为友元函数 下面通过例子来说明将成员函数定义为友元函数的方法。 【例11.2】将长方体类中计算长方体体积的成员函数定义为矩形类的友元函数,以便在长方体中使用矩形类中的私有数据成员计算长方体体积。 分析:先定义描述矩形的类Rectangle,其私有数据成员为矩形的长(Length)与宽(Width), 第11章 友元与运算符重载 ·277· 通过构造函数对矩形的数据成员长与宽初始化,如下列程序中D行所示。再定义描述长方体的类Cubiod,其私有数据成员为长方体的高Hing。如下列程序中B行所示。再定义计算长方体体积的成员函数Volume()如下: float Cuboid::Volume(Rectangle &r) { return r.Length*r.Width*High;} 在该函数内使用矩形对象r的私有数据成员Length与Width来计算长方体体积。由于矩形对象r的私有数据成员不能在矩形类外使用,所以编译时会产生错误。解决问题的方法之一就是将长方体类的成员函数Volume()定义为矩形类的友元函数,即在矩形类中增加一条将成员函数Volume()定义为友元函数的语句: friend float Cuboid::Volume(Rectangle &); //如程序中E行所示 则在成员函数Volume()内就可使用矩形类Rectangle的私有数据成员r.Length、r.Width。用友元函数方法求长方体体积的程序如下: # include class Rectangle; class Cuboid { private: float High; public: Cuboid(float h) { High=h;} float Volume(Rectangle &r); }; class Rectangle { private: float Length,Width; public: Rectangle(float l,float w) { Length=l;Width=w;} friend float Cuboid::Volume(Rectangle &); }; float Cuboid::Volume(Rectangle &r) { return r.Length*r.Width*High;} void main(void) { Rectangle r(10,20); Cuboid c(30); cout<<\长方体积=\olume(r)< 执行程序后输出: 长方体积=6000 //A //B //C //D //E 第11章 友元与运算符重载 ·278· 主函数执行时,先定义矩形对象r,系统自动调用构造函数初始化矩形对象r后,矩形r的长r.Legnth=10、宽r.Width=20。然后再定义长方体对象c,系统自动调用构造函数初始化长方体对象c后,长方体c的高High=30。最后调用计算长方体体积的函数Volume(),由于Volume()是矩形类的友元函数,所以可使用矩形类中私有数据成员 r.Legnth、r.Width作为长方体的长与宽,计算长方体的体积。 关于成员函数定义为友元的几点说明: (1)因为矩形类Rectangle定义在长方体类Cuboid之后,而长方体类Cuboid中要用到矩形类Rectangle的引用,如C行所示,所以在A行给出对矩形类Rectangle的引用性说明。 (2)E行将长方体类Cuboid中的成员函数Volume()说明为类Rectangle中的友元函数,因此在其函数体内可以使用类Rectangle中的私有成员r.Length、r.Width。 (3)将类Cuboid的成员函数Volume()定义为类Rectangle的友元函数时,在C行只能给出函数的原型说明,不能给出函数体,因为类Rectangle还没有定义。 从上例可以看出,将类C的一个成员函数说明成另一个类D的友元函数的一般格式: class D; class C { ? public: <类型> <成员函数>(D &); }; class D { ? public: friend <类型> C:: <成员函数>(D &); //B //A }; <类型> C:: <成员函数>(D &d); //E {?}; 上述定义格式中,在B行定义成员函数为友元函数,E行开始定义成员函数。定义为友元的成员函数参数必须是类D的引用、类D的对象或指向类D的指针。 综上所述,一个类可以定义若干个友元函数,可以将一个类的任一个成员函数说明为另一个类的友元函数,以便通过该类成员访问另一个类中的成员,亦可将一个类中的所有成员函数都说明为另一个的友元函数。将一个类中的所有成员函数都说明为另一个的友元函数的最好方法是将这个类定义为另一个类友元。 11.1.3一个类定义成另一个类的友元 要将一个类中所有的成员函数定义成另一个类的友元函数,只要将一个类说明成另一个的友元即可,而不必将该类每一个成员函数说明成另一个类的友元函数。 将类M说明成类N的友元的格式: class N { ? 第11章 友元与运算符重载 friend class M; ? ·279· }; 经上述定义后,在M类中可使用N类的所有成员。 【例11.3】在例11.2中将定义成员函数为友元函数的语句(即E行)改为将长方体类定义为矩形类的友元的语句:friend class Cuboid; 以便在长方体中使用矩形类中的私有数据成员计算长方体体积。 # include float High; public: Cuboid(float h) { High=h;} float Volume(Rectangle &r); }; class Rectangle { private: float Length,Width; public: Rectangle(float l,float w) { Length=l;Width=w;} friend class Cuboid; }; float Cuboid::Volume(Rectangle &r) { return r.Length*r.Width*High;} void main(void) { Rectangle r(10,20); Cuboid c(30); cout<<\长方体积=\olume(r)< 执行程序后输出: 长方体积=6000 在上面的程序中,由于将长方体类定义为矩形类的友元,所以在长方体中,可以使用矩形类中的私有数据成员计算长方体体积。 11.1.4友元注意事项 (1)友元关系是不传递的