1、C+语言程序设计 类和对象_扩展,2,主要内容,组合与对象成员const成员函数静态成员 友元关系Q&A,3,类的组合,描述的是一个类内嵌其他类的对象作为成员的情况,它们之间的关系是一种包含与被包含的关系 当创建类的对象时,如果这个类具有内嵌对象成员,那么各个内嵌对象也将被自动创建 在创建对象时,既要对本类的数据成员进行初始化,又要对内嵌对象成员进行初始化 组合类构造函数的一般形式 类名:类名(形参表):内嵌对象1(形参表),内嵌对象2(形参表), 构造函数的执行顺序为:按照内嵌对象声明的顺序依次调用内嵌对象的构造函数,最后再调用自身的构造函数,4,例:Line类与MyPoint类,#incl
2、ude class MyPoint public:MyPoint(int xp, int yp);MyPoint(const MyPoint,5,例:Line类与MyPoint类,#include #include “MyPoint.h“ int MyPoint:getX() return x; int MyPoint:getY() return y; MyPoint:MyPoint(int xp, int yp) x = xp; y = yp; cout “Class MyPoints Constructor was called.n“; MyPoint:MyPoint() cout “De
3、structor was called.n“; MyPoint:MyPoint(const MyPoint ,6,例:Line类与MyPoint类,#include #include “mypoint.h“ class Line public:Line(MyPoint pa, MyPoint pb); /构造函数Line(const Line,7,组合与对象成员,成员对象的构造顺序按类定义的出现顺序,最后执行自身构造函数 若子对象对应的类的构造函数有参数,那么包含子对象的类必须使用初始化列表的方式先初始化子对象,不仅体现在构造函数实现,而且体现在拷贝构造函数实现。 函数调用顺序:先调用内嵌对象
4、的构造函数(按内嵌时的声明顺序,先声明者先构造),然后调用本类的构造函数(析构函数的调用顺序相反) 调用默认构造函数(即无形参的),则内嵌对象的初始化也将调用相应的默认构造函数,8,主要内容,组合与对象成员const成员函数静态成员 友元关系Q&A,9,Const成员函数,const对象就是值不会改变的对象 对于const对象或对const对象的引用来说,编译器不允许你在其上调用任何方法,除非可以保证所调用的方法不会修改任何数据成员 要保证一个方法不会修改数据成员,具体做法就是将方法本身用const关键字来标记。 例如:修改后的MyPoint类,10,const成员函数,#include cl
5、ass MyPoint public:MyPoint(int xp, int yp);MyPoint(const MyPoint,11,const成员函数,#include #include “MyPoint.h“ int MyPoint:getX() const return x; int MyPoint:getY() const return y; ,12,const成员函数,const规范(即指定为const)是函数原型的一部分,在方法定义中也必须带上const 如果把一个成员函数声明为const,但它却会修改数据成员,则编译器会报错 非const对象可以调用const和非const成员
6、函数,而const对象只能调用const方法; 建议:将所有不会修改对象数据成员的成员函数都声明为const,这样就可以在程序中使用const对象或其引用,13,主要内容,组合与对象成员const成员函数静态成员 友元关系Q&A,14,静态成员,全局对象是实现数据共享的一种方法,由于它处处可见,因此不够安全,应尽量在程序中少用全局对象 实现类的多个对象之间的数据共享,可使用静态成员 静态成员包括静态数据成员和静态成员函数 静态成员用关键字static说明,15,静态数据成员,A variable that is part of a class, yet is not part of an ob
7、ject of that class, is called a static member. There is exactly one copy of a static member instead of one copy per object, as for ordinary non-static members.,16,静态数据成员,在一个类中,若将一个数据说明为static,则该数据称为静态数据,它告诉编译器无论建立多少个该类的对象,都只有一个静态数据的拷贝,这个拷贝被所有类对象共享 静态数据属于类而共享,不属于对象独有。它的值对每个对象都是一样的 对静态数据成员的值的更新,即是对所有对
8、象的该静态数据成员值的更新 静态数据使用关键字static,静态数据成员在类体中说明,在类体外定义,以分配存储空间并初始化,17,静态数据成员,/mypoint.h #include class MyPoint public:MyPoint(int xp, int yp);MyPoint(const MyPoint,18,静态数据成员,/mypoint.cpp #include #include “MyPoint.h“ int MyPoint:count = 0; MyPoint:MyPoint(int xp, int yp)id = count+; x = xp; y = yp; cout
9、“Class MyPoints Constructor was called.n“; MyPoint:MyPoint(const MyPoint ,19,静态数据成员,MyPoint类的四个对象的存储分配情况,每个对象具有自身整型变量的拷贝内存空间,而共享静态数据成员count在存储上只需一处拷贝就可以供所有对象使用。,20,静态数据成员,静态数据成员属于类,而不属于对象 静态数据成员也分为公有及私有 在类外只能访问公有的静态数据成员,需通过类名进行访问,如:id=MyPoint:count+; 在类内可以直接访问所有的静态数据成员,采用直接访问的方式,如:id=count+;,构造函数不对类
10、的静态数据成员进行分配空间和初始化,需在源文件(如MyPoint.cpp)中为其分配空间和初始化。 与常规数据成员不同,静态数据成员会默认初始化为0,21,静态成员函数,A function that needs access to members of a class, yet does not need to be invoked for a particular object, is called a static member function.,22,静态成员函数,静态成员函数的说明和定义与静态数据成员一样,函数实现可在类体内,也可在类体外,与一般成员函数相同 在静态成员函数的实现中
11、,可以直接使用静态成员,可以通过对象来使用非静态成员 调用时,不捆绑对象,所以,不能直接操作对象和其成员,若需访问该类对象,必须以参数传递之 静态成员函数一般设计为公有的,以访问私有静态数据成员为目的 调用方式是以类名加域操作符:后跟静态成员函数,23,主要内容,组合与对象成员const成员函数静态成员 友元关系Q&A,24,友元关系,类具有封装性,类中的私有数据只有通过该类的成员函数才可以访问。如果在程序中需要访问类的私有成员,就必须通过对象来调用类的成员函数,频繁调用成员函数将影响程序运行效率 为解决上述问题,C+ 提供一种友元机制,友元可以不通过调用成员函数就可以直接访问类的私有数据,以
12、提高程序运行效率 友元机制在数据封装这堵不透明的墙上开了一个小孔,友元的使用要慎重 友元可以是一个函数,称为友元函数;友元可以是一个类,称为友元类,25,友元函数,An ordinary member function declaration specifies three logically distinct things: The function can access the private part of the class declaration and the function is in the scope of the class and the function must b
13、e invoked on an object (has a this pointer).,By declaring a member function static, we can give it the first two properties only. By declaring a function a friend, we can give it the first property only.,26,友元函数,友元函数具有下述特点: 在类体内声明,在函数的类型说明符前加关键字friend 在类体外定义,定义格式与普通函数相同(不需再加friend关键字) 友元函数是非成员函数,在调用
14、上与普通函数相同 友元函数可以直接访问该类中的私有成员,27,友元函数,class Line; class MyPoint public:friend double distance(const MyPoint,28,友元函数,/mypoint.cpp double distance(const MyPoint ,若以成员函数方式实现,则其无法直接访问两个(或多个)类的私有数据成员 若以普通函数的身份实现,需要调用成员函数去访问私有数据成员,如果需要访问大量数据成员,则影响效率;而用友元之后,可以直接访问之,29,友元函数,友元函数另一作用:用在无法成员化的运算符重载中,例如:,class M
15、yPoint friend ostream ,30,友元类,如果要使一个类B能访问另外一个类A的私有成员,可以将该类B声明为另一个类A的友元。声明方法和友员函数相同,即在关键词class前加上friend 友员类的所有成员函数都可以当作该类的友员函数,能访问该类的私有和保护成员 例如:在类A的定义中加上语句friend class B;则类B为类A的友员类,31,友元类,#include /友元的宿主类 class BigBrother friend class Sister; /声明友元类 public:BigBrother(): money(100); /将初始的金钱数设置为100 void spendMoney()money -;int checkMoney()return money; private:int money; ;,32,友元类,/友元类的定义 class Sister public:void takeMoney(BigBrother,33,友元关系,友元关系不具有对称性 友元关系不具有传递性 友元关系不能被继承 友元的作用主要是为了提高程序的运行效率和方便编程。但随着硬件性能的提高,友元的作用也不明显;而且,友元破坏了类的封装性,所以在使用时,应权衡利弊,