第7章 类和对象.ppt
1 1C+程序设计程序设计第第7 7章章类和对象类和对象2 2面向对象程序设计面向对象程序设计 类的定义类的定义对象的定义对象的定义 对象的初始化对象的初始化 成员函数的特性成员函数的特性 对象数组对象数组对象指针对象指针 静态成员静态成员 常对象常对象子对象子对象 友元函数与友元类友元函数与友元类主主 要要 内内 容容3 31 1、面向对象程序设计面向对象程序设计1 1 1 1、面向对象的基本概念、面向对象的基本概念、面向对象的基本概念、面向对象的基本概念类是对某一类对象的抽象,而对象是某一种类的实例。因此,类和对象是密切相关的。没有脱离对象的类,当然也没有不依赖于类的对象,类是对现实世界的抽象得到的。当我们把现实世界分解为一个个的对象,解决现实世界问题的计算机程序也与此相对应,由一个个对象组成,这些程序就称为面向对象的程序,编写面向对象程序的过程就称为面向对象的程序设计(Object-Oriented Programming,简称为OOP)。4 42 2 2 2、面向对象程序设计的特点、面向对象程序设计的特点、面向对象程序设计的特点、面向对象程序设计的特点 面向对象程序设计面对的是一个个对象。其中每一组数据都是有特定的用途的,是某种操作的对象。也就是说,一组操作调用一组数据。程序设计者的任务包括:一是设计所需的各种类和对象,即决定把哪些数据和操作封装在一起;二是考虑怎样向有关对象发送消息,以完成所需的任务。对一个大型任务来说,面向对象程序设计方法是十分有效的,它能大大降低程序设计人员的工作难度,减少出错机会。5 5)封装与信息隐蔽封装与信息隐蔽封装与信息隐蔽封装与信息隐蔽 对一个对象进行封装处理,把它的一部分属性和功能对外界屏蔽,也就是说从外界是看不到的,甚至是不可知的。其好处是大大降低了操作对象的复杂程度。封装:封装:封装:封装:一是将有关的数据和操作代码封装在一个对象中,形成一个基本单位,各个对象之间相对独立,互不干扰。二是将对象中某些部分对外隐蔽,即隐蔽其内部细节,只留下少量接口,以便与外界联系,接收外界的消息。6 6 这种对外界隐蔽的做法称为信息隐蔽(information hiding)。信息隐蔽还有利于数据安全,防止无关的人了解和修改数据。对程序设计而言,封装性使对象内部的实现与外界隔离,提供了更理想的模块化机制,减少了程序间的相互干扰。7 7 )继承与重用继承与重用继承与重用继承与重用类具有层次性,即一个类的上层有父类,下层有子类,一个类继承了父类的某些特性,这种继承具有传递性。继承是一种连接类与类的层次模型,利用现有的类派生出新的类的过程称为类的继承,新类(子类)拥有原有类(父类)的特性,又增加了自身新的特性。设计程序时只需对新增的内容或对原内容修改设计代码,除了共享机制外,继承还有传递机制,即下层的子类可以继承各层父类的全部特性。8 8)多态性多态性多态性多态性如果有几个相似而不完全相同的对象,有时人们要求在向它们发出同一个消息时,它们的反应各不相同,分别执行不同的操作,这就是多态现象。(在Windows下,用鼠标双击一个文件对象(这就是向对象传送一个消息),如果对象是一个可执行文件,则会执行此程序,如果对象是一个文本文件,则启动文本编辑器并打开该文件。)多态性多态性(polymorphism)是指:由继承而产生的相关的不同的类,其对象对同一消息会作出不同的响应。多态性是面向对象程序设计的一个重要特征,能增加程序的灵活性。9 9面向对象的程序设计是以类和对象为基础的,程序的操作是围绕对象进行的,在此基础上利用了继承机制和多态性等。面向过程的结构化程序设计中,常用以下公式来表述程序:程序程序=算法数据结构算法数据结构面向对象程序设计就是把一个算法和一组数据结构封装在一个对象中。因此就形成了新的观念:对象=算法 数据结构程序=(对象+对象+对象+)+消息 或:程序=对象s+消息面向对象程序设计的特点面向对象程序设计的特点1010类是面向对象程序设计的核心。类是对某一类对象的抽象,而对象是某一种类的实例。在现实中,类是对一组客观对象的抽象,它将该组对象所具有的共同特征(包括属性和服务)封装起来,以说明该组对象的能力和性质。在系统中,类(class)是一种用户自定义的数据类型。通过类使得现实中的抽象实体在程序中直接表示为一个标识符,并可以进行引用和操作。这使得程序中的概念与应用中的概念相互比较一致和对应。2 2、类的定义类的定义 11111 1、类的定义格式、类的定义格式 类的定义格式一般地分为说明部分和实现部分。说明部分是用来说明该类中的成员,包含数据成员的说明和成员函数的说明。实现部分是用来对成员函数的定义。概括说来,说明部分将告诉使用者“干什么”,而实现部分是告诉使用者“怎么干”。1212类的一般定义格式如下:类的一般定义格式如下:class public:private:protected:;1313【例7.1】定义一个Clock时钟类 classClockpublic:voidinit();/初始化时间voidupdate();/当改变时间时刷新时间数据 voiddisplay();/显示时间private:inthour,minute,second;/时,分,秒;/别忘了“”后面的“;”!14142 2、定义类时应注意的事项、定义类时应注意的事项 在说明部分中,class是定义类类型的关键字,Clock是类名,通常用大写字母开始的字符串作为类名。花括号内是类的说明部分,说明该类包含哪些数据成员和哪些成员函数。类中的数据成员的类型可以是任意的,包含整型、浮点型、字符型、整型、浮点型、字符型、数组、指针和引用数组、指针和引用等。同时另一个类的对象,可以作该类的成员。当一个类的对象作为这个类的成员时,如果另一个类的定义在后面,需要提前说明。在类体中不允许对所定义的数据成员进行初始化,因为类的定义只是在创造一个类型而已,而不是在说明“变量”。相当于先设计好一个模具(类),之后才可用模具来生产产品(对象)。15153 3、类成员函数的实现、类成员函数的实现 类的成员函数是对类内中数据的操作,同时作为外部数据成员的接口,代表了类的对象的行为。这些函数可以定义在类的内部,也可以定义在类体的外部。在类的内部定义的成员函数叫内联函数,在类的外部定义的成员函数叫外联函数。在类的外部定义的成员函数需要在函数名的前面加Clock:,称为成员名限定。其中“:”称为作用域运算符。1616 在类体外定义成员函数的格式如下:在类体外定义成员函数的格式如下:返回值的类型返回值的类型 :(参数表)(参数表)函数体函数体 如:voidClock:display()couthour:minute:secondendl;17173 3、对象的定义对象的定义对象的定义格式对象的定义格式对象成员的表示方法对象成员的表示方法1818对象的定义格式如下对象的定义格式如下:例如:给上述时钟类定义对象:ClockclockA,clockB;/定义两个对象Clock*pclockA;/定义对象指针ClockclockD5;/定义对象数组 其中,是对象所属的类的名字,即所定义的对象是该类类型的对象。中可以有一个或多个对象名,多个对象名时用逗号分隔。中,可以是一般的对象名,还可以是指向对象的指针名或引用名,也可以是对象数组名。本例定义了2个对象、1个对象指针、一个对象数组。1919对象成员的表示方法对象成员的表示方法对象对象是广义“变量”,一个对象的成员就是该对象所属类所定义的成员。由于封装性,对象只能访问其中的公有成员,包括公有数据成员和公有成员函数。用运算符“.”来访问其中公有成员。对象名对象名.公有数据成员名公有数据成员名或者或者对象名对象名.公有成员函数名公有成员函数名(参数表参数表)例如:例如:clockA.cnt;/正确,访问数据成员正确,访问数据成员clockA.minute;/错误,错误,minute是私有成员,不能访问!是私有成员,不能访问!clockA.init();/正确,访问成员函数正确,访问成员函数此处的此处的“.”运算符,功能是表示对象的成员。运算符,功能是表示对象的成员。2020【例例7.4】写出以下程序的执行结果写出以下程序的执行结果:#includeclassRectangleintx1,y1,x2,y2;public:voidsetRectangle(inta1,intb1,inta2,intb2)x1=a1;y1=b1;x2=a2;y2=b2;voiddispRectangle()coutRectangle:x1=x1,y1=y1endl;coutx2=x2,y2=y2setRectangle(10,10,20,20);Rect2-dispRectangle();程序执行结果如下:程序执行结果如下:Rectangle:x1=0,y1=0 x2=10,y2=10Rectangle:x1=10,y1=10 x2=20,y2=20注意:如果类中的成员没有指明权限的,默认为私有。所以注意:如果类中的成员没有指明权限的,默认为私有。所以x1,y1,x2,y2的权限是的权限是private。22224 4、对象的初始化对象的初始化 简单简单构造函数和析构函数构造函数和析构函数 缺省构造函数和缺省析构函数缺省构造函数和缺省析构函数 拷贝构造函数拷贝构造函数2323构造函数和析构函数构造函数和析构函数构构造造函函数数和和析析构构函函数数是是在在类类体体中中说说明明的的两两种种特特殊殊的的成员函数。成员函数。构构造造函函数数的的功功能能是是在在创创建建对对象象时时给给对对象象分分配配内内存存空空间间 ,并可使用给定值来,并可使用给定值来初始化初始化对象。对象。析析构构函函数数的的功功能能是是用用来来释释放放一一个个对对象象的的已已分分配配空空间间。并可在对象被清除前,完成一些并可在对象被清除前,完成一些清理清理工作。工作。构造函数与析构函数的功能正好是构造函数与析构函数的功能正好是对应对应的。的。2424构造函数有以下特点:构造函数有以下特点:1)构造函数是类的一个成员函数,但有其特殊性;2)构造函数的函数名与类名相同,它不能有返回值,即使是void也不行。3)构造函数可以有参数,也可以没有参数,换句话说,构造函数可以重载;4)程序一般不直接调用构造函数,在创建对象时会自动调用构造函数,以完成对象的初始化工作。2525而析构函数有以下特点:而析构函数有以下特点:1)析构函数是类的一个特殊成员函数,一个类中只能有一个析构函数;2)析构函数的函数名与类名相同,并在前面加上“”;3)析构函数也不能有返回值,并且也不能有函数参数,换句话说,析构函数不能被重载;4)析构函数的主要功能是在对象消失时,执行如释放内存等清理工作;5)在对象消失时,析构函数会被自动调用。2626缺省构造函数和缺省析构函数缺省构造函数和缺省析构函数缺省构造函数和缺省析构函数缺省构造函数和缺省析构函数1 1、缺省构造函数、缺省构造函数C+规定,每个类必须有构造函数,没有构造函数就不能创建对象。如果在类的定义中,程序员没有设计任何构造函数,C+会自动提供一个缺省的构造函数,它只分配对象的实体空间外。此时,如果创建的是静态对象或全局对象,则对象所有数据成员都初始化为零或空,如果是普通对象,它的值将会是随机的。缺省构造函数的形式是:类名:类名()/类体为空只要在类的定义中提供了任意一个构造函数,那么C+就不再自动提供缺省构造函数。27272 2、缺省析构函数、缺省析构函数 如果在类的定义中,程序员没有设计析构函数,如果在类的定义中,程序员没有设计析构函数,C+C+也会自也会自动提供一个缺省析构函数,格式:动提供一个缺省析构函数,格式:类名:类名()类名:类名()/缺省析构函数体为空缺省析构函数体为空2828拷贝构造函数拷贝构造函数构造函数除可以用基本数据类型初始化对象外,还可以使用已存在的同类型的对象即类类型的对象来初始化正在创建的对象。为此,必须在类中定义一个特殊的构造函数来完成这个工作,这个构造函数被称为拷贝初始化构造函数。它实现了在初始化时将一个已知对象的数据成员的值拷贝给正在创建的另一个同类的对象。当然,它具有一般构造函数的所有特性。格式为::(&)如:student:student(student&s)每个类中必须有一个。若类中未说明,则编译系统会自动生成缺省函数。函数名同类名只有一个引用参数2929拷贝初始化构造函数被自动调用有三种情况:拷贝初始化构造函数被自动调用有三种情况:一、是用一个已知对象一、是用一个已知对象初始化一个新对象初始化一个新对象时。时。二、是以二、是以值调用方式值调用方式向一个函数向一个函数传递对象参数传递对象参数时。时。三、当对象作为三、当对象作为函数返回值函数返回值时。时。拷贝初始化构造函数拷贝初始化构造函数拷贝初始化构造函数又称复制构造函数拷贝初始化构造函数又称复制构造函数3030【例7.8】用已知对象初始化新建对象时用已知对象初始化新建对象时:#includeclassPointpublic:Point(intxx=0,intyy=0)X=xx;Y=yy;/构造函数参数设置了缺省值Point(constPoint&p);/拷贝构造函数声明intGetX()returnX;/获取私有数据成员的公有成员函数intGetY()returnY;private:intX,Y;Point:Point(constPoint&p)3131X=p.X;Y=p.Y;coutCopy_constructorcalled.n;voidmain()PointA(10,20);/创建一个对象并传入参数去初始化PointB(A);/会自动调用拷贝构造函数coutB:B.GetX(),B.GetY()endl;程序运行的输出结果:程序运行的输出结果:Copy_constructorcalled.B:10,2032325 5、成员函数的特性成员函数的特性 内联函数和外联函数内联函数和外联函数 成员函数的重载性成员函数的重载性 设置参数的缺省值设置参数的缺省值3333内联函数:指定义在类体内的成员函数。外联函数:指说明在类体内,定义在类体外的成员函数。类外定义的函数缺省情况下都是外联函数,用关键字inline可以强制转换。对于内联函数,不是在调用时才转去执行函数体,而是在编译时对所有调用该函数的地方装入实际的函数代码。节省了调用开销,提高了运行速度。内联函数必须在调用之前进行定义。3434外联函数变成内联函数的方法很简单,只需在函数头前加上关键字inline。但是并不是所有外联函数加上inline后就一定会成为内联函数。有以下限制条件:1)内联函数中,不能含有复杂的结构控制语句,如switch和while。如果内联函数有这些语句,则编译器将该函数视同普通函数那样产生函数调用代码。2)递归函数不能被用来做内联函数。3)内联函数只适合于只有15行的小函数。对一个含有许多语句的大函数,函数调用和返回的开销相对来说微不足道,所以也没有必要用内联函数来实现。3535一般的成员函数都可以进行重载。构造函数可以,但析构函数不能。(至少参数类型或个数不同)【例7.11】构造函数的重载。#includeclassApublic:A()/无参构造函数无参构造函数a=b=0;coutDefaultconstructorcalled.n;A(inti,intj)/有参构造函数,重载有参构造函数,重载成员函数的重载性3636a=i,b=j;coutConstructorcalled.n;voidprint();private:inta,b;inlinevoidA:print()/由外联变内联函数由外联变内联函数couta=a,b=bendl;voidmain()Am,n(4,8);m.print();n.print();3737程序执行结果如下:程序执行结果如下:Defaultconstructorcalled.Constructorcalled.a=0,b=0a=4,b=83838一般的成员函数可以被设置参数的缺省值。构造一般的成员函数可以被设置参数的缺省值。构造函数也可以,但析构函数无参数,也不能。函数也可以,但析构函数无参数,也不能。C+C+在在调调用用时时会会根根据据函函数数的的形形参参型型式式配配于于相相应应的的实参值。实参值。设置参数的缺省值设置参数的缺省值函数设置参数的缺省值时要避免二义性!函数设置参数的缺省值时要避免二义性!39396 6、对象数组对象数组数组不仅可由简单变量组成,也可由对象组成。如果一个数组中的每一个元素都是由同一个类的若干个对象组成,此数组称为对象数组。1、对象数组的定义对象数组的定义对象数组定义格式如下:.其中,指出该数组元素是属于该类的对象,方括号内的给出某一维的元素个数。一维对象数组只有一个方括号,二维对象数组要有两个方括号,等等,例如:Pointpoints10;定义一个由10个Point类的对象组成的一维对象数组上。40402、对象数组的赋值对象数组的赋值同普通数组一样,对象数组可以被初始化,也可以被赋值。假设类的定义为:classPointpublic:Point(intxx=0,intyy=0)X=xx;Y=yy;/构造函数参数设置了缺省值构造函数参数设置了缺省值private:intX,Y;4141则可定义并初始化对象数组,如下:Pointpoints3=Point(1,2),Point(3,4),Point(5,6);也可以先定义对象数组,然后再赋值,如:,如:Pointpoints3points0=Point(1,2);points0=Point(3,4);points0=Point(5,6);4242、对象指针数组对象指针数组在C+中,指针是一个比较复杂的概念,之前已经接触过不少指针的应用。但本节的指向数组的指针和指针数组是两个完全不同的概念。1.指向对象数组的指针指向对象数组的指针我们前面已经学过指向一般数组的指针,它的定义格式如下:(*).其中,用来说明指针的*要与括在一起。用一个方括号表示该指针指向一维数组,用二个方括号表示该指针指向二维数组。用来说明指针所指向的数组的元素的类型。4343例如:int(*P)3;P是指向一维数组的指针,该数组有3个int型元素。对于指向对象数组的指针,把改为即可:(*).4444、指针数组指针数组如果一个数组的每个元素存放的都是指向某个变量或某个对象的指针(即地址),此数组即为指针数组。如:int*pa3;/存放三个整型指针的指针数组再如:char*pc25;可存放2个字符串的字符指针数组,每个字符串最多可存放4个字符。一般在编程中,使用字符型的指针数组用来存放若干个字符串。4545、带参数的带参数的main()main()函数函数 到现在为止,程序中使用main()函数都没有带参数。在实际编程中,有时需要main()带参数。比如DOS下用copy命令把windows目录下win.ini文件拷贝到D盘根目录,就需要有输入2个参数:C:copywindowswin.inid:其中copy是命令,参数1是“windowswin.ini”,参数2是“d:”。带参数的main()函数格式如下:voidmain(intargc,char*argv)46467 7、对象指针对象指针1 1对象指针对象指针是指向对象的指针。如果有一个类Rect,则:Clock clockA;/定义一个对象Clock *pclockA=&clockA;/定义一个对象指针并指向对象clockA可通过对象指针可以访问对象的公有成员,格式为:对象指针对象指针-公有数据成员名;公有数据成员名;或对象指针对象指针-公有成员函数名公有成员函数名(参数列表参数列表);例如:pclockA-cnt;/用对象指针访问数据成员pclockA-init();/用对象指针访问成员函数47472指向函数的指针指向函数的指针函数的入口地址是指函数体内第一条可执行语句的代码在内存中的地址,C+语言中规定函数名代表函数的入口地址。函数指针是专门用来存放函数入口地址的变量。指向一般函数的指针的定义格式:*()给指向函数的指针赋值的格式:=调用指向函数的指针调用函数的格式:(*)()4848this指针指针this指针是类的一个自动生成、自动隐藏的私有成员,它存在于类的非静态成员函数中,指向被调用函数所在的对象的地址。当一个对象被创建时,该对象的this指针就指向对象数据的首地址。“*this”表示该对象。49498 8、静态成员静态成员 静态数据成员静态数据成员 静态成员函数静态成员函数50501、静态数据成员静态数据成员 类是类型而不是数据对象,每个类的对象都是该类数据成员的拷贝。类是类型而不是数据对象,每个类的对象都是该类数据成员的拷贝。然而,往往需要让类的所有对象在类的范围内共享某个数据。声明为然而,往往需要让类的所有对象在类的范围内共享某个数据。声明为staticstatic的类成员便能在类的范围中共享,称之为的类成员便能在类的范围中共享,称之为静态成员静态成员。若想在同一个类的多个对象之间共享某个数据。可将该类成员声明为static,使之成为静态成员。静态成员是在编译时被创建,其空间只有一个,且与对象是否存在无关,可为所有以后创建的该类对象共享。并且空间一直保存到程序结束。而一般成员是在对象创建时由构造函数分配空间,属于具体的某个对象,对象不同则成员空间也不同,并在函数结束时由析构函数释放对象空间而随之释放。5151例如:一个学生类,有一个对应学生总数属的数据成员count则对于每一个已有学生对象而言,一旦现有学生人数变化,那么已有学生对象中count所保存的数据就不适用,则要对每个对象逐个修改,显然这是不实际的,而应采用静态成员。52521、静态数据成员在定义或说明时前面加关键字:static。2、静态数据成员是静态存储的,必须对它进行初始化,其初始化必须在类体外进行,但前面不再加static,也不加访问控制标识符public、private等。3、由于静态数据成员是类的成员,而不是对象的成员,因此,初始化静态数据成员时,使用作用域运算符(“:”)来标识其所属的类,采用以下格式初始化:数据类型数据类型 类名:静态数据成员名类名:静态数据成员名=值;值;4、可按如下格式使用静态数据成员:类名:静态数据成员名类名:静态数据成员名53532 2、静态成员函数静态成员函数 与静态数据成员一样,静态成员函数也是属于类的,而不依赖对象而存在,即为所有对象共有的。因此,静态成员函数没有this指针。使用时,通过类名(而不是对象名)进行引用。【例7.24】类中包含静态成员函数的使用示例。#includeclassMpublic:M(inta)A=a;B+=a;/构造函数,内联staticvoidf1(Mm);/静态成员函数staticintB;/静态数据成员private:intA;5454intM:B=0;/静态数据成员初始化voidM:f1(Mm)coutA=m.Aendl;/必须通过对象才能引用一般数据成员coutB=Bendl;/直接引用静态数据成员voidmain()coutValueB:M:Bendl;/注意此时对象还没有建立!MP(5),Q(10);/建立对象P、QM:f1(P);/通过类调用静态成员函数M:f1(Q);coutValueB:M:Bendl;/可见,B不依赖对象!5555程序输出结果:ValueB:0A=5B=15A=10B=15ValueB:15程序分析:见代码注释。其中特别要注意,静态成员函数可以直接引用静态成员,但不能直接引用非静态数据成员,必须通过象来引用类中的非静态成员。如本例中:coutA=m.Aendl;/通过对象使用一般数据成员coutB=Bendl;/直接使用静态数据成员56569 9、常对象常对象1 1、常对象常对象常对象是指用常对象是指用const修饰的对象。定义常对象时,同样要进行初始修饰的对象。定义常对象时,同样要进行初始化,并且以后该对象不能再被更新,修饰符化,并且以后该对象不能再被更新,修饰符const可以放在类名可以放在类名后面,也可以放在类名前面。后面,也可以放在类名前面。定义格式如下定义格式如下:const 或者或者 const 5757例如:例如:classMpublic:M(inta)A=a;B+=a;voidf1(intx);private:intA,B;constMobj1(10,20);Mconstobj2(30,40);其中其中obj1 obj1 和和obj2obj2都是常对象,以后不能被更新。都是常对象,以后不能被更新。58582、常数据成员、常数据成员 如果某个数据成员的值是不应该被修改的,可以用const声明为常数据成员常数据成员,它受到强制保护,以防止被意外改动。对于常数据成员,在任何函数中都不能对它赋值,也不能更新。因此必须对它进行初始化,而且只能通过成员初始化列表的方式进行初始化。59593 3、常成员函数、常成员函数常成员函数说明格式如下:()const;其中,const是加在函数说明后面的类型修饰符,它也是函数类型的一个组成部分,因此在函数实现部分必须要带const关键字。特别注意:只有常成员函数才能操作常量或常对象,非常成员函数不能用来操作常对象。60604 4、对象的常引用对象的常引用对象常引用是指所引用的对象不能被更新,它也一般做为函数的形参来使用。定义格式如下:const类型说明类型说明&引用名引用名【例例7.28】对象的常引用:#include#includeclassPointpublic:Point(inta,intb)x=a;y=b;voidMovePoint(inta,intb)x+=a;y+=b;voidprint()coutx=xy=yendl;6161intx,y;doublelength(constPoint&p1,constPoint&p2)/参数为对象引用参数为对象引用doubledelta=(p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y);return(sqrt(delta);voidmain()Pointa(2,11),b(14,15);cout两点的距离是:两点的距离是:length(a,b)endl;在实际应用中,常指针、常引用,包括常对象,往往用来作函数的形参,称为常参数。62621010、子对象子对象1 1、子对象子对象:当一个类的成员是某一个类的对象时,该对象就为子对象。当一个类的成员是某一个类的对象时,该对象就为子对象。例如:例如:classApublic:private:;classBpublic:private:Aa;/a是类是类A的对象,此处作为类的对象,此处作为类B的对象成员的对象成员;6363其中,B类中成员a就是子对象子对象,它是A类的对象作为B类的成员。在某个类中出现了子对象子对象(也称对象成员)时,在该类的构造函数中需采用成员初始化列表的方式对它初始化。64642 2、动态对象动态对象动态对象指在程序运行过程中根据需要可以随时建立或删除的对象。动态对象被创建在内存一些空闲的存储单元中,这些空闲的存储单元称为堆(heap),所以又把动态对象称为堆对象。堆内存可以在创建动态对象时被占有,也可以通过删除动态对象而获得释放。正如之前用new与delete来创建动与删除动态存储空间一样,也可以用这两个运算符来创建或删除动态对象。例如:A*pa;/建立对象指针建立对象指针papa=newA(3,4);/pa指向新建动态对象的起始地址指向新建动态对象的起始地址注意:动态对象没有对象名,只能用指向该对象的指针来访问该对象,比如:coutX;/输出动态对象的公有成员输出动态对象的公有成员X的值。的值。65651111、友元函数与友元类友元函数与友元类 友元函数友元函数 友元类友元类6666对于一个定义在类外部的普通函数或另一个类的成员函数,当在某个类中用关键字friend进行说明时,该函数就成为了这个类的友元函数。类的私有成员只能由本类的成员访问,外部函数只能访问类的成员函数,再由成员函数访问类的私有成员。采用友元的目的主要是为提提高高效效率率。显然它破破坏坏了了类类的封装性的封装性。注注意意:在某个类中说明的友友元元函函数数并并不不是是该该类类的的成成员员函函数数。它可以是外部的一个独立函数,也可以是另外一个类中的成员函数。1 1 1 1、友元函数、友元函数、友元函数、友元函数67672 2 2 2、友元类、友元类、友元类、友元类当一个类作为另一个类的友元时,称之为友元类友元类。那么此类的所有成员函数都将成为另一个类的友元函数友元函数。【例例7.33】友元类的应用友元类的应用。#includeclassAfriendclassB;/声明类B是类A的友元类public:voiddisplay()coutxendl;private:intx;classBpublic:6868voidSet(A&Aobject,inti)/函数成了类A的友元函数Aobject.x=i;/可以访问A中的私有数据voiddisplay(A&Aobject)Aobject.display();voidmain()BBobject;AAobject;Bobject.Set(Aobject,123);Bobject.display(Aobject);