1、二二0一二年三月一二年三月第第3章章 类类与对象与对象o 本章主要介绍类与对象。本章主要介绍类与对象。o 类(类(class)是面向对象程序设计的核心)是面向对象程序设计的核心,是实现数据封装和信息隐藏的工具,是继是实现数据封装和信息隐藏的工具,是继承和多态的基础。承和多态的基础。o 本章是全书的基础与重点本章是全书的基础与重点,也是学习面向,也是学习面向对象程序设计技术的基础。对象程序设计技术的基础。1、C对对C结构的扩展结构的扩展o最初的C+称为“带类的C”,它扩展了C语言结构的功能,结构不仅可以包含数据,而且还可以包含操作这些数据的函数。【例3-1】一个包含了数据和数据操作函数的复数结构
2、。/Eg3-1.cppstruct Complexdouble r;double i;void init(double rr,double ii)r=rr;i=ii;double real()return r;double image()return i;1、引入类的原因、引入类的原因n解除struct的不安全性(struct成员的默认访问权限是public)n区别于struct2、类的定义形式、类的定义形式class 类名类名public:公有成员说明;公有成员说明;protected:保护成员说明;保护成员说明;private:私有成员说明;私有成员说明;;【例例3-2】用用class定义
3、的复数类定义的复数类Complex。/Eg3-2.cpp#include class Complexprivate:double r;double i;public:void init(double rr,double ii)r=rr;i=ii;double real()return r;double image()return i;void main()Complex a;a.init(2,3);couta.real()+“a.image()i“setHour(10);pClock-dispTime();3.4 对象对象4、对象赋值对象名1对象名2;Clock*pa,*pb,aClock,b
4、Clock;bClock=aClock;pa=new Clock;pb=pa;1、两个对象必须、两个对象必须类型相同类型相同2、进行数据成员的、进行数据成员的值拷贝值拷贝,赋值之后,两不相干赋值之后,两不相干3、若对象有、若对象有指针数据成员,指针数据成员,赋值可能产生问题赋值可能产生问题3.4 对象对象3.5 构造函数与析构函数构造函数与析构函数o 构造函数与析构函数是两个极其特殊的函数,它们由系统自动执行系统自动执行,在程序中不可显示地调用它们不可显示地调用它们。理解这两个函数对学好面向对象程序设计技术是大有帮助的。o 构造函数构造函数的主要作用是用于建立对象时对对象的数数据成员进行初始化
5、据成员进行初始化;而析构函数析构函数主要用于对象生命对象生命期结束时回收对象期结束时回收对象。3.5.1 构造构造函数函数1、构造函数的概念、构造函数的概念构造函数(constructor)是与类同名的特殊成员函数,主要用来初始化对象的数据成员。其在类中的定义形式如下:class X X();3.5.1 构造构造函数函数2、构造函数的特点、构造函数的特点n 构造函数与类同名。构造函数与类同名。n 构造函数没有返回类型。构造函数没有返回类型。n 构造函数可以被重载。构造函数可以被重载。n 构造函数由系统自动调用,不允许在程序中显构造函数由系统自动调用,不允许在程序中显式调用。式调用。o 引用构造
6、函数的原因引用构造函数的原因n 自动完成数据成员初始化,减少出错几率3、构造函数的调用n只能在定义对象时,由系统自动调用系统自动调用!n调用形式:类名类名 对象名(参数表);对象名(参数表);o 系统将根据参数表调用某个构造函数系统将根据参数表调用某个构造函数o 若无参数表将调用缺省构造函数。若无参数表将调用缺省构造函数。n不允许不允许程序员在程序中显示调用构造函数的名称,任何时候都不允许!3.5.1 构造构造函数函数3.5.1 构造构造函数函数【例例3-4】一个桌子类的构造函数。一个桌子类的构造函数。/Eg3-4.cpp#include using namespace std;class D
7、eskpublic:Desk(int,int,int,int);/构造函数声明构造函数声明 void setWeight(int w)weight=w;private:int weight,length,width,high;Desk:Desk(int ww,int l,int w,int h)/构造函数定义构造函数定义 weight=ww;high=l;width=w;length=h;coutcall constructor !endl;void main()Desk d1(2,3,3,5);3.5.1 构造构造函数函数4、使用构函数函数应注意的问题、使用构函数函数应注意的问题 构造函数不
8、能有返回类型,即使构造函数不能有返回类型,即使void也不行。也不行。构造函数由系统自动调用,不能在程序中显式调构造函数由系统自动调用,不能在程序中显式调用构造函数。用构造函数。构造函数的调用时机是定义对象之后的第一时间,构造函数的调用时机是定义对象之后的第一时间,即构造函数是对象的第一个被调用函数。即构造函数是对象的第一个被调用函数。定义对象数组或用定义对象数组或用new创建动态对象时,也要调创建动态对象时,也要调用构造函数。但定义数组对象时,必须有不需要用构造函数。但定义数组对象时,必须有不需要参数的构造函数参数的构造函数 构造函数通常应定义为公有成员。构造函数通常应定义为公有成员。1、析
9、构函数的概念、析构函数的概念析构函数(destructor)是与类同名的另一个特殊成员函数,作用与构造函数相反,用于在对象生存期结束时,完成对象的清理工作。2、定义语法、定义语法class XX();3、析构函数特点、析构函数特点o函数名为函数名为加类名加类名o无参数无参数o无返回值无返回值o不能重载:每个类仅有一个析构函数不能重载:每个类仅有一个析构函数3.5.2 析构析构函数函数4 4、析构函数、析构函数调用时机调用时机对象生命期结束时自动调用对象生命期结束时自动调用自动自动/局部对象:定义的语句块结束处局部对象:定义的语句块结束处全局对象:程序结束时全局对象:程序结束时静态对象:程序结束
10、时静态对象:程序结束时3.5.2 析构析构函数函数【例例3-5】析构函数和构造函数的应用。析构函数和构造函数的应用。/Eg3-5.cpp#include using namespace std;class Aprivate:int i;public:A(int x)i=x;coutconstructor:iendl;A()coutdestructor:iendl;void main()A a1(1);A a2(2);A a3(3);A a4(4);3.5.2 析构函数析构函数5、使用析构说明、使用析构说明 若有多个对象同时结束生存期,若有多个对象同时结束生存期,C+将按照将按照与调与调用构造函
11、数相反的次序调用析构函数。用构造函数相反的次序调用析构函数。每个类都应该有一个析构函数,如果没有显式定每个类都应该有一个析构函数,如果没有显式定义析构函数。义析构函数。C+将产生一个最小化的将产生一个最小化的默认析默认析构函数。构函数。构造函数和析构函数都可以是构造函数和析构函数都可以是inline函数函数 在通常情况下,析构函数与构造函数都应该被设在通常情况下,析构函数与构造函数都应该被设置为置为类的公有成员。类的公有成员。3.5.2 析构析构函数函数3.5.2 析构析构函数函数【例3-6】用析构函数释放构造函数分配的自由存储空间。#include using namespace std;c
12、lass Bprivate:int*a;char*pc;public:B(int x)a=new int10;pc=new char;B()delete a;delete pc;void main()B x(1);3.5.2 无参无参构造函数构造函数o 无参数构造函数指在定义对象时,不需要无参数构造函数指在定义对象时,不需要提供参数的构造函数。在一些情况下提供参数的构造函数。在一些情况下,如定如定义数组义数组,必须使用无参构造函数,因此需要必须使用无参构造函数,因此需要引起重视。引起重视。3.5.2 无参无参构造函数构造函数1、系统默认构造函数、系统默认构造函数C+规定,每个类必须有构造函数,
13、如果一个类没有定规定,每个类必须有构造函数,如果一个类没有定义任何构造函数,在义任何构造函数,在需要需要时编译器将会为它生成一个时编译器将会为它生成一个默认构造默认构造函数。函数。class X X()/系统默认构造函数类似于此系统默认构造函数类似于此 在用默认构造函数创建对象时,如果创建的是在用默认构造函数创建对象时,如果创建的是全局对象全局对象或静态对象或静态对象,则对象所有数据成员,则对象所有数据成员初始化为初始化为0;如果;如果创建的是创建的是局部对象局部对象,即,即不进行对象数据成员的初始化不进行对象数据成员的初始化。3.5.2 无参无参构造函数构造函数【例例3-7】point类的默
14、认构造函数。类的默认构造函数。/Eg3-7.cpp#include using namespace std;class pointprivate:int x,y;public:void setpoint(int a,int b)x=a;y=b;int getx()return x;int gety()return y;point p1;/定义全局对象定义全局对象void main()static point p2;/定义静态局部对象定义静态局部对象 point p3;/定义局部对象定义局部对象 coutp1:p1.getx(),p1.gety()endl;coutp2:p2.getx(),p2
15、.gety()endl;coutp3:p3.getx(),p3.gety()endl;o说明:在类没有定义任何构造函数时,系统才会产生默认构造函数。说明:在类没有定义任何构造函数时,系统才会产生默认构造函数。o一旦定义了任何形式的构造函数,系统就不再产生默认构造函数。一旦定义了任何形式的构造函数,系统就不再产生默认构造函数。【例例3-8】未定义无参构造函数引发的错误。未定义无参构造函数引发的错误。#include using namespace std;class pointprivate:int x,y;public:point(int a,int b)x=a;y=b;/;point p1;
16、void main()static point p2;point p3,*p4,a10;p4=new point;2、重定义无参数构造函数、重定义无参数构造函数o 系统生成的默认无参数构造函数,并未对系统生成的默认无参数构造函数,并未对对象的数据成员作什么实际的初始化工作。对象的数据成员作什么实际的初始化工作。o C+允许允许显式定义显式定义无参数的构造函数,这无参数的构造函数,这样就能通过它为对象的数据成员提供初始样就能通过它为对象的数据成员提供初始值。值。o 有时为了让类能够正常工作,必须显示提有时为了让类能够正常工作,必须显示提供无参构造函数,如例供无参构造函数,如例3-8。3.5.2
17、无参构造函数无参构造函数o 注意注意1.在在class没有定义任何构造函数时,系统没有定义任何构造函数时,系统可能动会产生缺省无参构造函数。可能动会产生缺省无参构造函数。2.一旦定义了任意的构造函数。系统就不会一旦定义了任意的构造函数。系统就不会产生缺省的无参构造函数产生缺省的无参构造函数3.5.2 无参无参构造函数构造函数【例例3-9】定义定义Point类的无参数构造函数,将类的无参数构造函数,将point对象的数据成员初始化为对象的数据成员初始化为0。#include using namespace std;class pointprivate:int x,y;public:point(i
18、nt a,int b)x=a;y=b;int getx()return x;int gety()return y;point()x=0;y=0;/显式定义无参构造函数显式定义无参构造函数;point p1(1,1);/调用构造函数调用构造函数point(int,int)void main()static point p2;/调用构造函数调用构造函数point()point p3,a10;/调用构造函数调用构造函数point()point *p4;p4=new point;/调用构造函数调用构造函数point()coutp1:p1.getx(),p1.gety()endl;coutp2:p2.g
19、etx(),p2.gety()endl;coutp3:p3.getx(),p3.gety()endl;coutp4:getx(),gety()endl;3.5.2 定义定义缺省参数构造函数缺省参数构造函数o在数据成员的取值比较固定时,可以通过为构造函数参数提在数据成员的取值比较固定时,可以通过为构造函数参数提供缺省参数初始化它们。供缺省参数初始化它们。o【例3-10】定义point类的缺省参数构造函数。/Eg3-10.cpp#include using namespace std;class pointprivate:int x,y;public:point(int a=0,int b=0)x
20、=a;y=b;/缺省参数构造函数 int getx()return x;int gety()return y;o构造函数可以重载。与普通函数的重载一样,重载的构造函构造函数可以重载。与普通函数的重载一样,重载的构造函数必须具有不同的函数原型数必须具有不同的函数原型o【例【例3-12】有一日期类,重载其构造函数。有一日期类,重载其构造函数。class Tdatepublic:Tdate();Tdate(int d);Tdate(int m,int d);Tdate(int m,int d,int y);/其他公共成员其他公共成员protected:int month;int day;int ye
21、ar;3.5.3 重载重载构造函数构造函数Tdate:Tdate()month=4;day=15;year=1995;cout month/day/year endl;Tdate:Tdate(int d)month=4;day=d;year=1996;cout month/day/year endl;Tdate:Tdate(int m,int d)month=m;day=d;year=1997;cout month/day/year endl;Tdate:Tdate(int m,int d,int y)month=m;day=d;year=y;cout month/day/year endl;
22、3.5.3 重载重载构造函数构造函数void main()Tdate aday;Tdate bday(10);Tdate cday(2,12);Tdate dday(1,2,1998);3.5.3 重载重载构造函数构造函数3.5.4 拷贝构造函数拷贝构造函数1、什么是拷贝构造函数、什么是拷贝构造函数拷贝构造函数是一个特殊的构造函数,用于根据已存在的对象初始化一个建新对象。它的形式如下:class Xpublic:X(const X&);/拷贝构造函数的常见原型3.5.4 拷贝拷贝构造函数构造函数2、默认拷贝构造函数、默认拷贝构造函数n如果没有定义类的拷贝构造函数,在需要的时候,如果没有定义类的
23、拷贝构造函数,在需要的时候,C+将产生一个具有最小功能的默认拷贝构造函数,将产生一个具有最小功能的默认拷贝构造函数,类似于下面的形式:类似于下面的形式:X:X(const X&)n默认拷贝构造函数以成员按位拷贝(bit-by-bit)的方式实现成员的复制。当一个类有指针类型的数据成员时,默认拷贝构造函数常会产生指针悬挂问题指针悬挂问题。3.5.4 拷贝拷贝构造函数构造函数【例例3-13】默认拷贝构造函数引起的指针悬挂问题。默认拷贝构造函数引起的指针悬挂问题。/Eg3-13.cpp#include#includeusing namespace std;class Personprivate:ch
24、ar*name;int age;public:Person(char*Name,int Age);Person();void setAge(int x)age=x;void print();Person:Person(char*Name,int Age)name=new charstrlen(Name)+1;strcpy(name,Name);age=Age;coutconstructor.endl;Person:Person()coutdestructor.ageendl;delete name;void Person:print()coutname t The Address of nam
25、e:nameendl;void main()Person p1(张勇张勇,21);Person p2=p1;/调用默认拷贝构造函数调用默认拷贝构造函数 p1.setAge(1);p2.setAge(2);p1.print();p2.print();3.5.4 拷贝拷贝构造函数构造函数 Person p2=p1 调用默认拷贝构造函数,用调用默认拷贝构造函数,用p1构造构造p2对象。对象。当当p2结束生命期被析构时,结束生命期被析构时,p1的的name成员就指成员就指向了被向了被p2的的delete的存储区域,产生指针悬挂的存储区域,产生指针悬挂问题问题3.5.4 拷贝拷贝构造函数构造函数 3定义
26、拷贝构造函数解决上述问题的方法是为类提供拷贝构造函数解决上述问题的方法是为类提供拷贝构造函数【例例3-14】为例为例3-13的的Person定义拷贝构造函数。定义拷贝构造函数。/Eg3-14.cppclass Personpublic:Person(const Person&p);Person:Person(const Person&p)name=new charstrlen(p.name)+1;strcpy(name,p.name);age=p.age;coutCopy constructor.endl;3.5.4 拷贝拷贝构造函数构造函数 4拷贝构造函数说明(1)拷贝构造函数与一般构造函数
27、相同,与类同名,没有返回类型,可以重载。(2)拷贝构造函数的参数常常是const类型的本类对象的引用。(3)在多数情况下,默认拷贝构造函数能够完成对象的复制创建工作,但当类具有指针类型的数据成员时当类具有指针类型的数据成员时,默认拷贝构造函数就可能产生指针悬挂问题,需要提需要提供显式的拷贝构造函数供显式的拷贝构造函数。(4)对拷贝构造函数的调用常在类的外部进行,应该将它指定为类的公有成员。3.5.4 拷贝拷贝构造函数构造函数(5)调用拷贝构造函数的时机是用已存在的对象初始化同类的新对象。至少以下3种情况种情况会导致拷贝构造函数的调用。class X;X obj1;X obj2=obj1;/情况
28、情况1:调用拷贝构造函数:调用拷贝构造函数X obj3(obj1);/情况情况2:调用拷贝构造函数:调用拷贝构造函数f(X o);/情况情况3:以对象作函数参数:以对象作函数参数时,调用拷贝构造函数时,调用拷贝构造函数3.6 构造函数与初始化列表函数与初始化列表1、什么是初始化列表n 成员初始化列表类似于下面的形式构造函数名构造函数名(参数表参数表):成员:成员1(初始值初始值),成员成员2(初始值初始值),n 介于参数表后面的介于参数表后面的“:”与函数体与函数体之间的之间的内容就是成员初始化列表。其含义是将括号中内容就是成员初始化列表。其含义是将括号中的初始值参数的值赋给该括号前面的成员。
29、的初始值参数的值赋给该括号前面的成员。n 3.6 构造函数与初始化列表函数与初始化列表【例例3-15】用初始化列表初始化用初始化列表初始化Tdate的的month和和day成员。成员。/Eg3-15.cpp#include using namespace std;class Tdatepublic:Tdate(int m,int d,int y);/其他公共成员其他公共成员protected:int month,day,year;Tdate:Tdate(int m,int d,int y):month(m),day(d)year=y;cout month/day/year endl;void
30、main()Tdate bday2(10,1,2003);3.6 构造函数与初始化列表函数与初始化列表2、使用构造函数初始化列表的注意 构造函数初始化列表中的成员初始化次序与初始化次序与它们在类中的声明次序相同,与初始列表中它们在类中的声明次序相同,与初始列表中的次序无关的次序无关。尽管三个构造函数初始化列表中的month、day和year的次序不同,但它们都是按照monthdayyear的次序初始化的,这个次序是其在Tdate中的声明次序。3.6 构造函数与初始化列表函数与初始化列表 构造函数初始化列表先于构造函数体中的先于构造函数体中的语句执行。语句执行。常量成员,引用成员,类对象成员,派
31、生常量成员,引用成员,类对象成员,派生类构造函数对基类构造函数的调用类构造函数对基类构造函数的调用必须采用初始化列表进行初始化【例例3-17】常量和引用成员的初始化。常量和引用成员的初始化。class Xclass X private:private:const const intint icic;intint&irir;intint i;i;public:public:X X():icic(100),ir(i)(100),ir(i)i=300;i=300;3.6 构造函数与初始化列表函数与初始化列表3.7 静态成员o 常规成员常规成员n 每个对象拥有独立的数据成员拷贝每个对象拥有独立的数据成
32、员拷贝n 不能在对象之外存在不能在对象之外存在o 静态数据成员静态数据成员static data membern 被类的所有成员所共享被类的所有成员所共享n 与类关联,而与类关联,而不与特定的对象关联不与特定的对象关联n 即便类没有任何对象时,就已经存在即便类没有任何对象时,就已经存在n 生命期与程序相同生命期与程序相同3.7.1 静态静态数据成员数据成员1静态数据成员的声明声明class Xstatic 类型类型 静态成员名静态成员名;2静态数据成员的定义定义有以下两种定义形式:类型类型 类名类名:静态成员名静态成员名;类型类型 类名类名:静态成员名静态成员名=初始值初始值;注意:注意:在类
33、外定义静态数据成员时,不能加上在类外定义静态数据成员时,不能加上static限定词;限定词;在定义静态数据成员时可以指定它的初始值(第在定义静态数据成员时可以指定它的初始值(第2种定义种定义形式),若定义时没有指定初值,形式),若定义时没有指定初值,系统默认其初值为系统默认其初值为0。3.7.1 静态静态数据成员数据成员3静态数据成员的访问静态成员属于整个类,两种方式访问。通过类名访问(这种访问方式是非静态成员不具有的):类名类名:静态成员名静态成员名;通过对象访问:对象名对象名.静态成员名静态成员名;【例例3-18】设计一个银行类,该类对象是一个个银行账户,统计该类对象的个数。设计一个银行类
34、,该类对象是一个个银行账户,统计该类对象的个数。/Eg3-18.cpp#include using namespace std;class Accountpublic:Account(char*Name,char*Psw);Account()number+;Account()number-;int getNumber()return number;private:char name10;char psw6;static int number;/保存对象个数保存对象个数;Account:Account(char*Name,char*Psw)strcpy(name,Name);strcpy(psw
35、,Psw);number+;int Account:number;/定义定义void main()Account za(tom,123456);coutza.getNumber(),;Account a3;coutza.getNumber(),;Account x,y;coutza.getNumber(),;coutza.getNumber()membero 使用this指针区分二义性class Xint i;f(int i)this-i=i;o 使用this指针返回调用返回调用对象对象class XX&f()return*this;X&g()return*this;X a;a.f();a.g
36、();3.8 this 指针指针4、this指针的两种常见应用3.9 类对象成员类对象成员1、类对象成员的基本知识、类对象成员的基本知识n类的数据成员一般都是基本数据类型,但也可以是结结构、联合、枚举构、联合、枚举之类的自定义数据类型,还可以是其其他类的对象他类的对象。n如果用其他类的对象作为类的成员,则称之为对象成对象成员员。n类对象作成员的形式如下:class X类名类名1 成员名成员名1;类名类名2 成员名成员名2;类名类名n 成员名成员名n;;2、对象数据成员初始化、对象数据成员初始化【例3-22】对象成员的初始化。class StudentIDpublic:StudentID(int
37、 id=0)value=id;cout Assigning student id valueendl;StudentID()cout Destructing id value endl;protected:int value;3.9 类类对象成员对象成员class Studentpublic:Student(char*pName=no name,int ssID=0):id(ssID)cout Constructing student pName endl;strncpy(name,pName,sizeof(name);namesizeof(name)-1=n;protected:char n
38、ame20;StudentID id;void main()Student s(Randy,9818);运行结果是:运行结果是:Assigning student id 9818Constructing student RandyDestructing id 9818这个结果是我们需要的!这个结果是我们需要的!【例例3-23】类成员的构造次序。类成员的构造次序。/Eg3-23.cp#include using namespace std;class A int a;public:A(int i)a=i;coutconstructing A:aendl;class B int b;public:
39、B(int i)b=i;coutconstructing B:b(*指针指针).两种操作符访问其所指对象的成员。两种操作符访问其所指对象的成员。【例3-24】对象数组和对象指针的应用。/Eg3-24.cpp#include using namespace std;class pointprivate:int x,y;public:point()x=1;y=1;point(int a=10,int b=10)x=a;y=b;int getx()return x;int gety()return y;void main()point p1(3,3);/定义单个对象定义单个对象 point p3;/
40、定义对象数组定义对象数组 point*pt;/定义对象指针定义对象指针 /point p2;/产生二义性产生二义性 for(int i=0;i2;i+)cout“p”i“.x=”pi.getx()“t”;coutpi.y=pi.gety()endl;pt=&p1;coutx:getx()endl;pt=p;coutx:getx()endl;pt+;coutx:getx()endl;coutPoint (*pt).x:(*pt).getx()endl;o 对象可以作为参数传递给函数,其方法与传递其他类型的数据相同:n 值传递(对象的一个拷贝)值传递(对象的一个拷贝)n 地址传递地址传递n 引用传
41、递引用传递【例3-25】按传值、传引用、传指针的方式向函数传递参数对象。/Eg3-25.cpp#include using namespace std;class MyClass int val;public:MyClass(int i)val=i;int getval()return val;void setval(int i)val=i;void display(MyClass ob)coutob.getval()setval(100);void main()MyClass a(10);coutValue of a before calling change -;display(a);ch
42、ange1(a);coutValue of a after calling change1()-;display(a);change2(a);coutValue of a after calling change2()-;display(a);change3(&a);coutValue of a after calling change3()-;display(a);分析输出结果分析输出结果3.13 友元友元1、友元函数n一个类的友元函数能够直接访问该类所有成员一个类的友元函数能够直接访问该类所有成员,包括public、protected、private类型的成员。n友元函数的定义形式如下:友
43、元函数的定义形式如下:class X friend T f();/声明声明f为为X类的友元函数类的友元函数 ;T f()/友元不是类成员函数,定义时不能用“X:f”限定函数名3.13 友元友元【例3-27】利用友元函数计算两点之间的距离。/Eg3-27.cpp#include#include using namespace std;class pointprivate:int x,y;friend int dist1(point p1,point p2);/声明dist1为point类的友元public:point(int a=10,int b=10)x=a;y=b;int getx()ret
44、urn x;int gety()return y;3.13 友元友元int dist1(point p1,point p2)double x=(p2.x-p1.x);/友元可以直接访问对象的私有成员 double y=(p2.y-p1.y);return sqrt(x*x+y*y);int dist2(point p1,point p2)/dist2是普通函数是普通函数 double x=p2.getx()-p1.getx();/普通函数只能访问对象的公有成员 double y=p2.gety()-p1.gety();return sqrt(x*x+y*y);void main()point
45、p1(2,5),p2(4,20);coutdist1(p1,p2)endl;coutdist2(p1,p2)endl;3.13 友元友元2、友元类一个类可以是另一个类的友元,友元类的所有成员函数都是另一个类的一个类可以是另一个类的友元,友元类的所有成员函数都是另一个类的友元函数,能够直接访问另一个类的所有成员(包括友元函数,能够直接访问另一个类的所有成员(包括public、private和和protected)。【例3-28】通过友元类的成员函数直接访问对象的私有成员。/Eg3-28.cpp#include using namespace std;class Aprivate:int x,y;
46、public:A(int i,int j)x=i;y=j;int getX()return x;int getY()return y;friend class B;/声明类声明类B是类是类A的友元类的友元类;3.13 友元友元class Bprivate:int z;public:int add(A a)return a.x+a.y+z;/A类对象作参数 int mul(A a)return a.x*a.y*z;/A类对象作参数 B(int i=0)z=i;void main()A a(2,3);B b(4);coutb.add(a)endl;/输出9 coutb.mul(a)endl;/输出24本章结束本章结束